苹果如何检测网速(DIY:在macOS状态栏显示实时网速)

在写这篇文章之前,首先我要声明,这是作者第一次写macOS APP。如有不足,请指正。

如何检测网速

MacOS系统什么都好,但是笔者是强迫症患者,还是想看看实时网速。为此我在app store搜索了相关软件,结果都不是免费的。好在作者本人从事IT行业,技术一般,所以只是想写一个自己用的小玩意,花了两天时间记录下来,分享给同行。以上是本文的缘起。

为了在状态栏中显示实时网速,作者将其分解为两步:1 .获取数据源,即如何获取实时网速。2.显示到状态栏。

数据源的获取

如何获取实时网速?第一反应是官方API。结果我在官方文档里没有找到相关的API(如果有同行知道,请告知作者)。于是,我试着在百度上搜索,结果一无所获。在这种情况下,我使用谷歌搜索相关信息。在一个GitHub作者的作品中,我发现作者使用了nettop的命令行工具。总的原则是定期启动shell进程来执行这个命令并分析返回的数据。这种方法不是不可以,但是如果定时器一直启动进程,相应的性能会差很多。权衡之后,这个方案最终被放弃了。这时候我突然想起来Linux系统下有一个ifaddrs.h的头文件,里面有一个if_data的指针,这个指针的语句包含了总的进出流量,也就是说只要定期检查进出流量,除以间隔时间,就可以大致得出实时的流量。

想到这里,我直接在macOS系统下查看了头文件,写了一个demo测试,发现没有问题,可以使用(不知道为什么,在作者的系统上,系统自带的活动监视器里的流量统计和这个功能得到的数据不太一致,但是计算实时网速的时候差别不大,有些厉害的大佬还是要告诉我)。所以我写了一个C库让swift调用。以下是通用代码。

#包括& # 34;netlib.h & # 34 # include & lt;ifaddrs.h & gt # include & lt;net/if . h & gt; # include & lt;stdlib.h & gt int request _ net _ speed(p _ callback func,void * obj) { struct if addrs * IFA _ list = NULL; struct if addrs * IFA = NULL; struct if _ data * ifd = NULL; int ret = 0; ret = getifaddrs(& IFA _ list); if(ret & lt;0)返回-1; for(IFA = IFA _ list;ifaIFA = IFA-& gt;ifa_next) { if(!(IFA-& gt;ifa_flags&IFF_UP)&&!(IFA-& gt;ifa_flags&IFF_RUNNING)) 继续; if(IFA-& gt;ifa_data==0) 继续; ifd =(struct if _ data *)IFA-& gt;ifa _ data func(IFA-& gt;ifa_name,ifd-& gt;ifi_ibytes,ifd-& gt;ifi_obytes,obj); } IFA = NULL; ifd = NULL; free(IFA _ list); 返回0; }这个函数传入一个函数指针来执行外部方法。以上数据源的获取完成。

显示到状态栏

这是作者第一次写macOS APP。所有的东西都是通过百度或者谷歌找到的。首选语言是swift。至于为什么不用OC,swift是官方语言。

其实这里很简单,特别是对于一些苹果开发者来说,但是作者是新手,所以我把重要的代码贴在这里。

private let status item = nsstatusbar . system . status item(with length:nsstatusitem . variable length) func applicationDidFinishLaunching(_ a Notification:Notification){ //创建提供窗口内容的SwiftUI视图。 let bar height = nsapplication . shared . main menu?。menubar height testcalcfontize(bar height:bar height!) let menu = ns menu() //menu . additem(with title:& # 34;开始& # 34;,action: #selector(onWake),key equivalent:& # 34;") //menu . additem(with title:& # 34;暂停& # 34;,action: #selector(onSleep),key equivalent:& # 34;") menu . additem(with title:& # 34;退出& # 34;,action: #selector(quitApp),key equivalent:& # 34;") status item . menu = menu start(); /睡眠或醒来时重新运行程序 ns workspace . shared . notification center . add observer( self,selector:# selector(on wake(notification:)), name: NSWorkspace . didwakentification,object:nil) ns workspace . shared . notification center . add observer( self,selector:# selector(on sleep(notification:)), name:ns workspacetoOpaque()) // obj是被捕获的实例,也就是传入的观察者 timer = timer。scheduled timer(with time interval:time interval(interval),repeats:true){(kt timer)in request _ net _ speed({(name,ibytes,o bytes = nil else { return } let self = Unmanaged & lt;AppDelegate & gt。from opaque(UnsafeMutableRawPointer(obj!)).take unretainedvalue() my . show text(name:name!,ibytes: ibytes,o bytes: o bytes) },observer) } }个人认为只要找到NSStatusBar这个类,就成功了一大半。至于剩下的工作,如何调用这个类来显示需要显示的内容。其中用swift调用C感觉技术上有点难。本来这个小玩意计划一天搞定,结果两天就卡在这个地方了。这里的答案是从堆栈溢出中找到的。简单来说吧。Request_net_speed是一个C方法,将swift中的回调方法传入C中,因为是作者第一次使用swift,但一时没看懂。在C# java swift等语言中,有一个很重要的概念叫做instance,作者就卡在这里了。这里我们需要把类本身的实例传递给C,那么当C调用swift方法的时候,swift就捕获这个实例,然后用这个实例调用实例本身的方法(也就是我自己


以上是自己写的macOS实时网速显示,挂上GitHub“链接”,有需要的小伙伴可以拉源代码。

温馨提示:《nettool》这是前面提到的作者的作品。没有得到授权,就不会挂链接。你可以自己搜一下。

您可以还会对下面的文章感兴趣

使用微信扫描二维码后

点击右上角发送给好友