进阶篇:使用 PyObjC 发送通知
越来越多的开发者选择 Mac 作为个人电脑,并用它来完成开发工作。OS X 平台上有一些独有的 Python 标准库和第三方库,它们很有用但是却鲜为人知。
当邮件客户端收到新邮件或在日历中出现新预约时,开发者会收到通知。这种通知机制也广泛应用在第三方团队协作工具(如 Slack)软件上。事实上,我们还能把通知机制应用于日常开发中,比如一个操作耗时较长,我们希望尽早了解到操作的反馈以便继续进行其他步骤,而不必一直在屏幕上等待它完成,可以切换屏幕,或者让它后台运行,我们去做其他的工作,待它完成后给我们发一个通知就好了。
Cocoa 是苹果公司为 Mac OS X 所创建的原生面向对象的编程环境,Cocoa 应用一般使用 Objective-C 开发,Python 开发者可以使用 PyObjC 这样的桥接技术编写 Cocoa 应用。Mac 自带的 Python 版本已经内置了 PyObjC,直接使用即可。
我们来实现这个发通知的应用:
import Foundation from AppKit import NSImage import objc NSUserNotification=objc.lookUpClass('NSUserNotification') NSUserNotificationCenter=objc.lookUpClass('NSUserNotificationCenter') ICON_PATH= '~/web_develop/chapter14/section5' def notify(title, subtitle, info_text, delay=0, sound=False, userInfo={}, is_error=False): icon=NSImage.alloc().initByReferencingFile_( os.path.join(ICON_PATH, 'douban.png')) notification=NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(info_text) notification.setUserInfo_(userInfo) notification.set_identityImage_(icon) if is_error: error_image=NSImage.alloc().initByReferencingFile_( os.path.join(ICON_PATH, 'error.png')) notification.setContentImage_(error_image) if sound: notification.setSoundName_('NSUserNotificationDefaultSoundName') notification.setDeliveryDate_( Foundation.NSDate.dateWithTimeInterval_sinceDate_( delay, Foundation.NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter( ).scheduleNotification_(notification)
setTitle_方法设置标题;setSubtitle_方法设置子标题;setInformativeText_设置内容;set_identityImage_会添加自定义图标;notify 接受 sound 参数,如果为 True,在发通知的时候会带系统默认声音。发送的通知效果如图 14.1 所示。
图 14.1 发送通知的效果
如果这是一个错误类型的通知(is_error=True),会通过 setContentImage_方法额外地在通知文本右侧添加一张错误的图片,效果如图 14.2 所示。
图 14.2 错误类型的通知
这是一个命令行的程序,应该使用命令行选项与参数的解析器模块 argparse,它在 Python 2.7 的时候进入标准库,用来替代 optparse 模块。我们来编写发送通知的命令行接口:
unicode=lambda s:s.decode('utf-8') parser=argparse.ArgumentParser( description='Send a custom notification on OS X.') parser.add_argument('-t', '--title', help='title of notification', default='', type=unicode) parser.add_argument('-s', '--subtitle', help='subtitle of notification', default='', type=unicode) parser.add_argument('-m', '--message', help='message of notification', default='', type=unicode) parser.add_argument('--sound', help='include audible alert', action='store_true', default=True) args=parser.parse_args() notify(args.title, args.subtitle, args.message, sound=args.sound)
notify 需要接收 unicode 类型的值,但是 argparse 的解析结果是字符串,argparse 可以灵活地支持解析参数的值的类型转换,所以使用了“unicode=lambda s:s.decode('utf-8')”之类的语句就可以用“type=unicode”,这样解析的结果就是 unicode 类型的值了。
除了发送通知,还需要把 notification.py 封装成系统命令,让发通知智能一些。举个例子,现在要执行:
> python runscript.py -c 4
封装之后就成为了:
> notify python runscript.py -c 4
这个 notify 命令接收要执行的命令及参数,通过 subprocess.call 的返回值判断执行是否成功,来决定通知的标题、类型(是否是错误类型的通知),通知内容为执行的命令。再者还要考虑发送通知的脚本的位置,因为可能开发调试是在虚拟机或者远程服务器上进行的,这就需要把消息传回到 Mac 电脑上。实现这样的功能的方法很多,比如在 Mac 搭建 Web 服务,RPC 服务或者使用 SSH 服务。本节将展示在虚拟机里面通过 ssh 连接 Mac 宿主机发通知的方式:
#!/usr/bin/python # coding=utf-8 import sys import subprocess def notify(title, msg, is_error=False): cmd=('ssh user@host ' '"python/Users/dongweiming/bin/notify.py ' '-t\'{}\'-m\'{}\'"').format(title, msg) if is_error: cmd+='--error' subprocess.call(cmd, shell=True) def main(): cmd=' '.join(sys.argv[1:]) retcode=subprocess.call(cmd, shell=True) if len(cmd)>33: cmd=cmd[:30]+'...' if retcode: title='执行失败' is_error=True else: title='执行成功' is_error=False notify(title, cmd, is_error=is_error) if __name__=='__main__': main()
把这个脚本放在$PATH 变量中指定的一个目录下,并添加执行权限:
> mkdir ~/bin > cp chapter14/section5/notify ~/bin > chmod+x ~/bin/notify > export PATH=$PATH: ~/bin
$PATH 变量决定了 Shell 将到哪些目录中寻找命令或程序。现在不必输入这个命令的完整路径,直接输入 notify 就可以了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论