前段时间写了一个批处理,运行后可以在两个 Wi-Fi 之间自动切换,当时虽然也想在 macOS 上实现一个,但没太大需求,便作罢。直到这周突然意识到,回家之后都会把微信和钉钉之类关掉,倒不是因为讨厌,而是开着浪费笔记本电量。所以便想着能不能在切换到指定网络之后,自动退出微信和钉钉。
简单版本
可能因为写批处理导致的惯性思维,导致想到这个需求之后,第一时间是想写一个 Shell 脚本,还特意去搜了有没有比较好的脚本管理工具(其实也没必要)。寻找一般无果后,起身上洗手间才恍然意识有 Hammerspoon 呀。
去官网一看,果然有 hs.wifi 模块,可以获取当前连接的 Wi-Fi 名称。下面是最开始比较简单的需求完成后的代码:
是不是很简单,十行代码就实现了最开始的需求:判断当前连接的 Wi-Fi,如果是 Work,则运行微信和钉钉,如果是 Home,则退出微信和钉钉。
不过这其中并没有对这个两个应用是否运行进行判断,特别时第一句 if 语句,即使并未运行微信和钉钉,也会进行 kill
操作,而由于找不到指定进程 Console 便会报错,虽然不影响使用,但报错便意味着代码还不够好。
上面代码中用到的 API:
- 和 Wi-Fi 相关的
- hs.wifi.watcher.new():建立一个 Wi-Fi 观察者,在 Wi-Fi 改变时作出响应;
- hs.wifi.currentNetwork():返回当前连接的 Wi-Fi 名称,未连接时则返回 nil;
- 执行的操作
- hs.application.launchOrFocus():启动指定 APP,如果已启动,则切换到前台;
- hs.application.get():获取正在运行应用,如果未运行则返回 nil;
- hs.application:kill():结束由 get 获得的应用,强制则是 kill9;
稍微复杂的版本
如果要对当前程序是否运行进行判断,用 if 语句即可:
相对与原来的版本,由两行变成了八行,如果对每个语句都进行判断,那就由原来的四行变成了十六行,看着相识的代码,是不是觉得那里不对。下面有一个办法,可以用更少的代码实现相同的功能,而且更优雅:
相对与之前的代码,是不是更简洁,而且如果以后想增加 kill 的应用,可以直接在括号中增加(其实还是不方便,还有另一个判断,难不成要加两次?)。
稍微复杂版本的模块化
当今世界,不用函数都不好意思说会写代码,本着能函数则函数的基本原则改写了上面的代码,扩展性更强(不能白白模块化不是)。
下面是完整的代码:
相较于之前的版本,主要是把 for 循环中的代码分别单独放到函数中,这样在 if 语句中只要调用这个函数即可,另外是把需要操作的应用放到一个表中,这样以后也便于修改。
其实如果注意观察会发现在最开始的代码中,launchOrFocus
用的是 WeChat,而 get
用的则是中文 微信,至于原因,对比下两个 API 的文档说明就明白了。
最后
上面的代码有一点不甚满意的是,当使用 launchOrFocus
打开应用时,会在前台打开,而不是后台运行,而使用 hide()
则会导致 Console 报错,因为应用并未启动完成。除非说再另外写一个函数去判断,但这样又增加了复杂性,感觉没必要(另外是增加延时操作,同样不怎么可行)。
此外,写这篇笔记的时候,实际代码比文中多了两个个判断,功能是当连接指定 Wi-Fi 时,设定 IP 为静态,而断开这个网络时,重新恢复为自动获取。是不是很酷,不过,下篇再说。
信息
版本
- macOS:macOS Catalina 10.15.1
- Hammerspoon:Version 0.9.76 (5104)