从iOS 8开始,Apple推出了新的App Extension,涉及方方面面,比如today panel、keyboard、content blocker、sharing action等。但是App Extension的官方开发指南很少,以后会有入门时的很多陷阱。 所以我准备写一个系列的文章,帮助大家更好的入门App Extension的开发,少走弯路。
什么是应用扩展?
顾名思义,就是一个扩展,很像一些大型软件(好吧,现在可能是应用)的插件机制。 App Extension其实不是你应用的插件,而是系统的插件。 它的生命周期是由系统来管理的,所以如果你想做坏事,它还是行不通的……但是App Extension分发的载体是应用,也就是说,如果你只是想做一个今天的面板插件,还需要一个主程序。 您的主程序什么都不做或提供一些基本设置和数据。
App Extension和主程序的关系?
可以说与它无关。 它基本上是两个独立的程序。 您的主程序既不能访问 App Extension 的代码,也不能访问其存储空间。 这完全是两个进程,两个程序。 这时候,你可能会问,我不能互动,搓有什么用? ? 别着急,后面我会讲到如何做一些交互。
应用扩展可以做什么? 你不能做什么?
几乎任何事情,难道没有人将一个小小的 Chrome 恐龙复活节彩蛋塞进今日面板吗? 也有人把输入法当成浏览器来分屏多任务……只有你想不到,但你做不到……额等等,有些事情还是做不到. 比如内存是有限的,App Extension的可用内存远远少于常规应用,所以如果你真的想做游戏,就得权衡一下你的资源占用问题能不能解决。 而你不能访问UIApplication,因为它的容器应用就是系统,你想拿系统的UIApplication干什么……(当然你可以通过递归找UIResponder得到UIApplication,不过我没试过) 同样,你不能执行长期操作,你的 App Extension 随时可能被系统杀死,谁知道呢?
还有更多没用的API3D素材,可以看这个苹果官方文档:
开始创建应用扩展
我们先来看看我们要做什么。 这是一个简单的 Todo 应用程序。 主程序如下所示:
今天面板插件看起来像这样:
界面很简单~
主程序的实现其实很简单,就是TableView的使用和数据持久化,这里就不重点说了。 但是需要注意的是,我们需要为今天的面板预留一个接口,假设我们要在今天的面板中显示前4个待办事项,我们必须将这4个项目分别存放在主程序和扩展程序都可以访问的地方可以访问。 后面会讲怎么做。
尖端:
Apple 的 HIG 明确指出,与其在 Today 面板中使用可滚动的 Scroll View,不如将其完全展开。 因此,对于多条数据,我们要么逐页显示,要么只显示前几条。
接下来,我们为项目创建一个 Today Extension:
一路下一步,输入一个子项名称,点击“完成”完成Today Extension的添加。
该子项目的初始目录结构如下:
PS entitiments文件是后面创建的,不会有
然后我们在Storyboard中拖出通用界面,如果画布的尺寸不合适,可以在这里调整,不过那是调整预览效果ios 游戏开发框架,真实尺寸在IB中是不能修改的。
那么我们如何修改今日面板中视图的大小呢? 答案是修改View Controller的preferredContentSize属性,忽略宽度,将高度调整到合适的大小,因为宽度总是和屏幕宽度一样。
在这个例子中,我使用 44 * item 数量 - 1 作为视图的高度,因为一个标准的 Table View Cell 的高度是 44开发学习,然后减去最后一个 item 分界线的高度就是我们理想中合适的高度。
主程序与 App Extension 共享数据
我们在主程序中创建了待办事项,App Extension如何获取它们? 既然两者的代码和数据是不可互通的ios 游戏开发框架,那么我们可以想当然地使用App Group来解决。 首先在主程序中创建一个App Group:
然后在App Extension中添加这个App Group。
这样我们就可以使用NSUserDefaults通过这个App Group来交换数据了。
还记得我说过所有数据的前四条应该显示在今天的面板上吗? 让我们在下面实现这个功能:
当主应用的数据发生变化时,调用该方法更新快照数据。
接下来我们主要看看Today Extension是如何实现的。 首先,让我们看一下这两种方法:
第一种方法是系统告诉 Extension 它需要更新。 你更新之后,你通过block回调告诉系统你做了什么,你做了什么。 通常,我们只是告诉系统我们已经更新了数据(也就是将NCUpdateResultNewData项作为参数传递给block.item)。
第二种方法是返回填充大小。 如果不实现,默认会在view的左侧有一定的缩进。 当然苹果还是希望大家不要修改默认的内补~
然后我们实现数据的读取:
PS 第三行写错了,不用在意
其实也很简单,只需要从App Group的配置中对前4项进行快照,然后更新Table View即可。 这个方法可以在viewDidLoad或者widgetPerformUpdateWithCompletionHandler:中调用。
这里我们看一下效果,选择Today Extension的Scheme,点击debug按钮,弹出如下对话框:
选择我们的主程序,然后单击“运行”。
App Extension 调用主程序并执行操作
当我们的Todo List为空时,我们想在Today面板中显示一个按钮,点击它可以快速进入Todo创建界面,像这样:
由于我们无法访问到主程序的代码,所以只有一种方式可供选择,那就是URL Scheme。
首先,我们为主程序注册一个URL Scheme:
然后响应按钮点击:
由于App Extension不能访问UIApplication,所以它的openURL:不能用,但是我们可以用extensionContext来打开URL,用法和效果是一样的。
回到主程序,我们处理URL的开启:
这里我使用Notification来通知指定的View Controller执行相应的动作。 当然,您也可以使用自己喜欢的方法。 这里最复杂的是处理路由。 现在实现的方法有很多,这里就不赘述了。
看一下效果(不好意思,图没做好,不动请在新窗口打开):
好了,到这里我们就基本打通了主程序和App Extension之间的通信,是不是很简单呢?
最后,一个小小的提醒
由于通知中心的界面是一个很大的UIVisualEffectView,具体参数也做了调整,所以插件的背景色要保持透明,主文字颜色为白色,副文字颜色应该是lightTextColor,这样才能适应磨砂玻璃的Vibrancy效果。
今日面板各插件的高度计算方法与UITableView的自适应高度相同。 如果不设置preferredContentSize,或者设置为CGSizeZero,则表示要使用自适应高度,系统会使用你设计的自适应高度。 布局确定合适的高度。 如果要这样做,参考iOS 8之后UITableViewCell自适应高度的方式即可。