今年北京的金秋十月变成了雾霾十月,短短的二十天已经经历了三次重度雾霾,人将近有一半的时间埋在雾里时,就会觉得自己的脑子不大灵光。最近这几天我常常在想,当年俄国工人的十月革命,是不是也是脑子不大灵光的产物?
还好,今天的北京终于风来霾散,天空呈现出一种极为清澈的蓝,憋了很久的人们都出来放风,我们也去了奥林匹克森林公园,偌大的停车场第一次被塞的水泄不通,这一幕让我看来无比心酸,人民不容易。
奥森的景色美到让人心碎,但是,当你置身其中,想的却是,明天去哪里寻找这样的蓝色?每当在北京看到蓝天白云的时候,我就会想起《黑客帝国》里尼奥和崔妮蒂驾驶着飞船冲破云层看到壮美太空的场景,瞬间的美好更加让人悲伤,因为他们下一刻就重新坠入了阴霾滚滚的残酷世界。
今日题图:奥森里的黄和蓝。
碧云天,黄叶地。秋色连波,波上寒烟翠。山映斜阳天接水。芳草无情,更在斜阳外。
黯乡魂,追旅思。夜夜除非,好梦留人睡。明月楼高休独倚。酒入愁肠,化作相思泪。
前几篇关于 Mac 和 iPhone 的文章里提到了通知中心扩展的特性,很多读者让写写这部分内容。我在写的时候发现,我的朋友王巍已经写过了这部分内容,而且比我写的好。于是和王巍沟通后转载在 MacTalk,希望感兴趣的读者能够喜欢。
王巍 (@onevcat),一名来自中国的 iOS / Unity 开发者。现居日本,就职于 LINE。正在修行,探求创意之源。
我们都叫他猫神。
以下是原文。
本文是我的 WWDC 2014 笔记 中的一篇,涉及的 Session 有
• Creating Extensions for iOS and OS X, Part 1
• Creating Extensions for iOS and OS X, Part 2
扩展 (Extension) 是 iOS 8 和 OSX 10.10 加入的一个非常大的功能点,开发者可以通过系统提供给我们的扩展接入点 (Extension point) 来为系统特定的服务提供某些附加的功能。对于 iOS 来说,可以使用的扩展接入点有以下几个:
Today 扩展 - 在下拉的通知中心的 “今天” 的面板中添加一个 widget
分享扩展 - 点击分享按钮后将网站或者照片通过应用分享
动作扩展 - 点击 Action 按钮后通过判断上下文来将内容发送到应用
照片编辑扩展 - 在系统的照片应用中提供照片编辑的能力
文档提供扩展 - 提供和管理文件内容
自定义键盘 - 提供一个可以用在所有应用的替代系统键盘的自定义键盘或输入法
系统为我们提供的接入点虽然还比较有限,但是不少已经是在开发者和 iOS 的用户中呼声很高的了。而通过利用这些接入点提供相应的功能,也可以极大地丰富系统的功能和可用性。本文将先不失一般性地介绍一下各种扩展的共通特性,然后再以一个实际的例子着重介绍下通知中心的 Today 扩展的开发方法,以期为 iOS 8 的扩展的学习提供一个平滑的入口。
Apple 指出,iOS 8 中开发者的中心并不应该发生改变,依然应该是围绕 app。在 app 中提供优秀交互和有用的功能,现在是,将来也会是 iOS 应用开发的核心任务。而扩展在 iOS 中是不能以单独的形式存在的,也就是说我们不能直接在 AppStore 提供一个扩展的下载,扩展一定是随着一个应用一起打包提供的。用户在安装了带有扩展的应用后,将可以在通知中心的今日界面中,或者是系统的设置中来选择开启还是关闭你的扩展。而对于开发者来说,提供扩展的方式是在 app 的项目中加入相应的扩展的 target。因为扩展一般来说是展现在系统级别的 UI 或者是其他应用中的,Apple 特别指出,扩展应该保持轻巧迅速,并且专注功能单一,在不打扰或者中断用户使用当前应用的前提下完成自己的功能点。因为用户是可以自己选择禁用扩展的,所以如果你的扩展表现欠佳的话,很可能会遭到用户弃用,甚至导致他们将你的 app 也一并卸载。
扩展的生命周期和包含该扩展的你的容器 app (container app) 本身的生命周期是独立的,准确地说。它们是两个独立的进程,默认情况下互相不应该知道对方的存在。扩展需要对宿主 app (host app,即调用该扩展的 app) 的请求做出响应,当然,通过进行配置和一些手段,我们可以在扩展中访问和共享一些容器 app 的资源,这个我们稍后再说。
因为扩展其实是依赖于调用其的宿主 app 的,因此其生命周期也是由用户在宿主 app 中的行为所决定的。一般来说,用户在宿主 app 中触发了该扩展后,扩展的生命周期就开始了:比如在分享选项中选择了你的扩展,或者向通知中心中添加了你的 widget 等等。而所有的扩展都是由 ViewController 进行定义的,在用户决定使用某个扩展时,其对应的 ViewController 就会被加载,因此你可以像在编写传统 app 的 ViewController 那样获取到诸如 viewDidLoad 这样的方法,并进行界面构建及做相应的逻辑。扩展应该保持功能的单一专注,并且迅速处理任务,在执行完成必要的任务,或者是在后台预约完成任务后,一般需要尽快通过回调将控制权交回给宿主 app,至此生命周期结束。
按照 Apple 的说法,扩展可以使用的内存是远远低于 app 可以使用的内存的。在内存吃紧的时候,系统更倾向于优先搞掉扩展,而不会是把宿主 app 杀死。因此在开发扩展的时候,也一定需要注意内存占用的限制。另一点是比如像通知中心扩展,你的扩展可能会和其他开发人员的扩展共存,这样如果扩展阻塞了主线程的话,就会引起整个通知中心失去响应。这种情况下你的扩展和应用也就基本和用户说再见了..
扩展和容器应用本身并不共享一个进程,但是作为扩展,其实是主体应用功能的延伸,肯定不可避免地需要使用到应用本身的逻辑甚至界面。在这种情况下,我们可以使用 iOS 8 新引入的自制 framework 的方式来组织需要重用的代码,这样在链接 framework 后 app 和扩展就都能使用相同的代码了。
另一个常见需求就是数据共享,即扩展和应用互相希望访问对方的数据。这可以通过开启 App Groups 和进行相应的配置来开启在两个进程间的数据共享。这包括了使用 NSUserDefaults 进行小数据的共享,或者使用 NSFileCoordinator 和 NSFilePresenter 甚至是 CoreData 和 SQLite 来进行更大的文件或者是更复杂的数据交互。
另外,一直以来的自定义的 url scheme 也是从扩展向应用反馈数据和交互的渠道之一。
这些常见的手段和策略在接下来的 demo 中都会用到。一张图片能顶千言万语,而一个 demo 能顶千张图片。那么,我们开始吧。
后续的内容涉及很多图片和代码,鉴于微信的阅读效果,大家去读原文效果更好:
[http://onevcat.com/2014/08/notification-today-widget/]
最后推荐一本关于 Swift 的电子书《Swifter - 100 个 Swift 必备 tips》。作者也是王巍。关于本书,他是这么介绍的:
本书是 Swift 语言的知识点的集合。我自己赴美参加了 Apple 的 WWDC 2014,也正是在这届开发者大会上,Swift 横空出世。毫不夸张地说,从 Swift 正式诞生的第一分钟开始,我就在学习这门语言。虽然天资驽钝,不得其所,但是在这段集中学习和实践的时间里,也还算总结了一些心得,而我把这些总结加以整理和示例,以一个个的小技巧和知识点的形式,编写成了这本书。全书共有 100 节,每一节都是一个相对独立的主题,涵盖了一个中高级开发人员需要知道的 Swift 语言的方方面面。
我已经买了,写的非常好,适合用作官方文档的参考和补充,也是中级开发人员喜爱的 Swift 进阶读本,价格只有 25 元,远低于国外同类型电子书。
希望学习 Swift 语言的读者可以点击「阅读原文」,了解详情。