进阶篇:使用 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 就可以了。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论