揭秘 iOS App Extension 开发 —— Today 篇

从 iOS 8 开始,苹果引入了全新的 App Extension,涉及到方方面面,例如今日面板、键盘、内容拦截器、分享动作等。但是官方对于 App Extension 的开发指南少之又少,入门起来会有很多坑。所以我准备写一系列文章来帮助大家更好入门 App Extension 的开发,也能少走弯路。

何为 App Extension?

顾名思义,它是一种扩展,很类似于一些大型软件(好吧,现在可能是个应用都可以有)的插件机制。App Extension 事实上并不是你应用的插件,而是系统的插件,其生命周期是由系统来管理的,所以如果你想做什么坏事还是行不通的...但是 App Extension 分发的载体是应用,也就是说如果你只是单纯想做一个今日面板插件,也需要有个主程序,你的主程序可以什么都不做,也可以提供一些基本的设置和数据。

App Extension 和主程序的关系?

可以说没有什么关系,基本上就是两个独立的程序,你的主程序既不可以访问 App Extension 的代码,也不可以访问其存储空间,这完完全全就是两个进程、两个程序。这时你可能会问,我擦,都不能交互那有什么卵用??别急,后面我会讲到如何做一些交互。

App Extension 可以干什么?不可以干什么?

基本上什么都能干,有人不是在今日面板里把 Chrome 的恐龙小彩蛋硬塞进去了吗?还有拿输入法当浏览器作分屏多任务的...只有你想不到,没有你做不到......诶等等,有些还是做不到的。比如,内存有限制,App Extension 的可用内存远不如常规应用,以至于如果你真想做游戏,还是掂量掂量你的资源占用问题能不能解决吧。而且还不能访问 UIApplication,因为它的容器应用是系统,你拿系统的 UIApplication 想干嘛...(当然,你可以用递归查找 UIResponder 的方法拿到 UIApplication,但是我没试过)再次,你不能执行长时间的操作,你的 App Extension 可能随时被系统 Kill 掉,who knows?

还有更多不可用的 API 可以看这个苹果官方文档:Understand How an App Extension Works

开始创建一个 App Extension

首先看一下我们要做的东西,是一个简单 Todo 应用,主程序长这个样:


今日面板插件长这个样:


界面都很简单啦~
主程序实现其实很简单,就是 Table View 的使用以及数据持久化,这里就不着重讲了。但注意,我们要留出一个接口给今日面板,假设这里我们要在今日面板里显示前 4 条待办事项,我们必须要单独将这 4 条存在一个主程序和扩展都能访问的地方。后面我会说怎么做。

Tips:


苹果的 HIG 明确指出,不要在今日面板里使用可以滚动的 Scroll View,而是要完全展开,因此对于多条数据,我们要不就分页,要不就只显示前几项。

下面,我们就为工程创建一个 Today Extension:


一路下一步,输入一个子项目名,点 『Finish』就完成 Today Extension 的添加了。

这个子项目的初始目录结构如下:


P.S. 那个 entitiements 文件是后来创建的,一开始不会有

然后我们在 Storyboard 里把大致界面拖出来,如果画布大小不合适可以在这调整一下,但是也就是调整了预览效果,真实的大小不能在 IB 里修改。


那我们怎么修改视图在今日面板里的大小呢?答案是修改 View Controller 的 preferredContentSize 属性,不理会 width,调整 height 到合适的大小即可,因为宽度总是和屏幕宽度相同的。

在这个例子中,我使用 44 * 项目数量 - 1 来作为视图高度,因为一个标准 Table View Cell 的高度是 44,然后减掉最后一个条目分割线的高度就是我们理想的合适高度。

主程序向 App Extension 共享数据

我们在主程序里创建了待办事项,怎么才能让 App Extension 获取到呢?由于两者代码和数据都不互通,所以我们 可以理所当然的想到用 App Group 来解决。首先在主程序中创建一个 App Group:

然后在 App Extension 里添加这个 App Group 即可。
这样,我们就可以用 NSUserDefaults 通过这个 App Group 交流数据了。

还记得我说过要拿出所有数据的前四条放到今日面板中展示吗?下面我们就来实现这个功能:


当主应用的数据变化后就调用这个方法来更新快照数据。

下面我们主要来看 Today Extension 怎么实现,首先看看这两个方法:


其中第一个方法是系统告诉 Extension 需要更新了,当你更新完毕之后通过 block 回调告诉系统你完成了还有做了什么,通常我们就告诉系统我们更新数据了即可(就是给 block 传 NCUpdateResultNewData 枚举项作为参数)。

其中第二个方法是返回一个内补大小,如果不实现,默认情况视图左侧会有一定的缩进。当然,苹果还是希望你不要修改默认的内补~

然后我们实现数据的读取:


P.S. 第三行写错了,不要管它
其实也很简单,就是从 App Group 的配置里拿出前 4 项的快照,然后更新一下 Table View 即可。这个方法在 viewDidLoad 或者 widgetPerformUpdateWithCompletionHandler: 中调用都可以。

到这我们看看效果,选中 Today Extension 的那个 Scheme 点击调试按钮,弹出下面的对话框:



选择我们的主程序,点击 『Run』。

App Extension 调起主程序并执行动作

当我们的 Todo List 是空的情况下,我们希望在今日面板里展示一个按钮,点击后可以快速进入创建 Todo 的界面,就像这样:


由于我们访问不了主程序的代码,所以只剩下一条路可以选,那就是 URL Scheme

首先,我们给主程序注册一个 URL Scheme:


然后响应按钮点击:


由于 App Extension 访问不了 UIApplication,因此不能用它的 openURL:,但是我们可以用 extensionContext 来打开 URL,用法和效果是一样的。

回到主程序,我们处理 URL 的打开:


这里我用 Notification 的方式告知指定 View Controller 来执行相应动作,当然你也可以用你自己喜欢的方式,这里最复杂也就是处理路由,现在也有很多方法实现,我这里就不深究了。

下面看看效果(不好意思,图没做好,不动请在新窗口中打开):


好了,到这我们就基本打通主程序和 App Extension 的相互通信了,是不是也很简单呢?

最后,一个小提醒

由于通知中心的界面是一大块 UIVisualEffectView ,并且具体参数调整过,所以插件的背景色最好保持透明,主要文字颜色最好是白色,次要文字的颜色最好是 lightTextColor,这样能适应毛玻璃下的 Vibrancy 效果。

今日面板每个插件的高度计算和 UITableView 自适应高度的计算方式一致,如果你没有设置 preferredContentSize,或者把它设为 CGSizeZero 了,就表示你想采用自适应高度,那么系统就会根据你设计的 Auto Layout 来确定适合的高度。如果你想这么做的话,直接参考 UITableViewCell 在 iOS 8 以后自适应高度的方式即可。

完了~希望大家支持!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容