Extension概述
众所周知,基于iOS系统的安全性考虑,其应用的数据存储是通过沙盒模式进行的,要实现应用之间的数据共享十分困难,功能共享就更加棘手。在iOS8系统中,apple为我们提供了一个革命性的功能:扩展。我们可以通过扩展来使app间数据甚至功能进行共享。
App Extension出现后,突破了两个重要的iOS限制,那就是:由Open In系统创建的应用程序之间不必要的数据复制和无法替换苹果键盘。
然而,其中有一个最可能的误解需要澄清一下,就是iOS 8 App Extensions不同于Android Indents,Ars Technica网站撰稿人Andrew Cunningham这样写道。根据Google的描述:
Intent提供了一种机制,用于不同应用程序代码之间的后期运行时绑定。它主要用来启动Activities,因此可以将它看作是Activities之间的粘合剂。从本质上讲,它是一个无源数据结构,存放要执行动作的抽象描述。
虽然Extension在很多情况下与Intent没有什么不同,但在iOS 8中,App Extension系统的整体设计使得它与Intent有很大的不同。
Extension的生命周期
正如苹果文档中的描述,Extension是通过“包含应用程序(containing app)”提供的专门的二进制文件。包含应用程序只负责提供Extension,后者是独立运行的。尽管如此,一个iOS包含应用程序实际上还需要提供Extension之外的某些功能。OS X没有这样的要求,其上的包含应用程序不需要提供任何额外的功能。
虽然说必须有一个「容器软件」来包含各种扩展应用,扩展应用和容器软件仍旧分开运行。每个扩展都是一个以「.appex」作为扩展名的二进制文件。该种类型的文件可以被打开、完成给定任务、而后在容器软件未被关闭的情况下关闭扩展。同时我们也可以预想到,许多的应用软件内有着同样的扩展。比如说,Instagram 的扩展是可以给图像添加滤镜。很多其他的图像处理软件也需要给图像添加滤镜。此时苹果公司鼓励开发者使用「嵌入框架」(embedded framework)共享他们完成此任务的代码。创建嵌入框架的步骤很简单,仅需创建一个框架、把代码放进框架内、而后将框架嵌入容器软件和应用扩展即可。唯一需要注意的地方是这种特性必须在 iOS 8.0 或者后续的系统中才能存在。之前版本的操作系统不支持此种类型的操作。
苹果公司严格的强制回收内存机制是导致需要扩展和容器应用分开运行的重要原因之一。由于用户经常同时开启多个小插件,因此小插件的内存管理受到的限制尤其严格。这从 iPhone 4s 或者 iPad 2 这样的设备上这些内存受限的小插件的运行机制就能看出。
文档提到,Extension的生命周期与它的包含应用程序完全没有关系,它由4个阶段组成:
- 用户选择一个App Extension
- 系统启动它
- App Extension运行
-
系统终止App Extension
app_extensions_lifecycle_2x.png
如果两个应用程序需要同样的Extension做相同的工作,那么这会发生在两个独立的Extension进程中。
这一方法的主要动机是,通过生命周期短暂的Extension减少内存使用和能量消耗,并防止一个Extension的错误影响到使用了相同Extension的应用程序。
Extension的类型
Extension有多种类型,每一种类型都绑定到一个称为“扩展点(Extension point)”的系统区域:
Extension point | Typical app extension functionality |
---|---|
Today (iOS and OS X) | Get a quick update or perform a quick task in the Today view of Notification Center(A Today extension is called a widget) |
Share (iOS and OS X) | Post to a sharing website or share content with others |
Action (iOS and OS X; UI and non-UI variants) | Manipulate or view content originating in a host app |
Photo Editing (iOS) | Edit a photo or video within the Photos app |
Finder Sync (OS X) | Present information about file sync state directly in Finder. |
Document Provider (iOS; UI and non-UI variants) | Provide access to and manage a repository of files. |
Custom Keyboard (iOS) | Replace the iOS system keyboard with a custom keyboard for use in all apps |
Watch App (iOS) | Provide an app, a glance, or a notification UI for Apple Watch, as described in App Programming Guide for watchOS. |
- “今日(Today,又称为Widget)”:可以快速获取更新或者在通知中心的今日视图中执行一项快速任务。
- 共享:发布到一个共享网站或者与其它应用程序共享内容。
- 动作:在另一个应用程序的上下文中操作或查看内容。
- 照片编辑(仅限于iOS):在照片应用程序中编辑照片或视频。
- 查找器(仅限于OS X):在查找器中直接显示文件同步的状态信息。
- 文档提供程序(仅限于iOS):提供对文件库的访问和管理。
- 自定义键盘(仅限于iOS):用自定义键盘替代iOS系统键盘,并用于所有的应用程序中。
- Watch App(仅限于iOS):为Apple Watch提供一个app,一个glance页面或者一个通知UI,详见: App Programming Guide for watchOS。
由于每个扩展点都有与之相关的使用策略和专门的API,开发人员必须为他们想要提供的那种功能选择恰当的扩展点。例如,在默认情况下,键盘Extension“不能访问网络,而且不能与其包含应用程序共享同一容器”。通过对Extension进行恰当的配置,这样的限制可以移除,但开发人员仍然需要遵守苹果应用商店审查指南和iOS开发者计划许可协议中的具体的网络键盘指南。
Extension运行机制
即使是iOS 8 允许运行扩展,却仍旧在应用、应用扩展以及应用数据之间设置了许多的障碍。而这一切正是出于保护用户以及用户隐私的目的。实际上应用之间仍旧不能直接交流。像之前提到的一样,应用扩展是小的二进制文件,并且和容器应用程序分开来运行。调用这些扩展的应用程序(苹果称之为「主应用」,host app)在调用并启动扩展之后会与扩展进行直接的交流,然而主应用与容器应用之间永远不会建立连接。即使主应用想要调用一个扩展,也是通过向苹果的系统框架发送请求。此时仅仅启动应用扩展,而不直接启动容器应用。
simple_communication_2x.png
应用扩展和「主应用」之间可以交流,然而此时扩展和其容器应用之间并不会直接建立联系。
在 FortyTwo 公司的 iOS 开发者 Eduardo Fonseca 向我们解释了 iOS 是如何实现让应用和扩展之间不建立联系的效果的。
「每一个扩展是在主应用程序之内的独立的程序。这些扩展拥有独立的可执行代码。」Fonseca 说,「然而有趣的是实际上扩展并不是应用程序。苹果的系统框架会通过已经事先定义好的接口调用这些扩展。扩展的代码会被分开来单独执行,也就是说第三方应用的『应用空间』内什么都不会执行。这样的话支持使用扩展的应用(比如 Safari)就不会有任何危险。同样,在其他应用内执行你的扩展也不会遇到任何问题。它们就像油和水一样,是完全不会融合的分开的两个部分。」
即使应用程序扩展与其容器应用之间必须有所交流,他们也必须通过系统接口非直接地进行交流。默认下容器应用与其应用程序扩展之间是不可以互相接触到对方的数据的。
detailed_communication_2x.png
扩展和其容器应用必须通过接口和其他用来分享数据的特殊容器进行非直接的交流
为了在容器应用和其应用扩展之间分享数据,你也许需要把容器应用和扩展都设置成一个「应用群」(App Group) 的一部分。这样就可以通过包含应用沙箱和扩展沙箱的一个第三方容器传输二者之间的数据。你可能想过为什么在 iOS 上登录 Chrome 浏览器会让你同时登录谷歌地图或者谷歌云端硬盘。这就是因为 Chrome、谷歌地图和谷歌云端硬盘都是谷歌的应用群的一部分。然而即使在应用群里,数据的分享也有一些限制。它们之间能够分享数据库、缓存信息、登录信息等等,但是本地存储的媒体文件或者其他文件却绝对不能分享。
app_extensions_container_restrictions_2x.png
把容器应用和应用扩展放到一个应用群里能够使它们在分享区域分享一些数据。否则容器应用和应用扩展的数据会被存储在不同的地方。
简单地来总结一下上述内容:苹果公司不想让一个应用能够进入另一个应用的沙箱内。而应用扩展就像是在沙箱里的小沙箱,因此在主应用调用扩展时,扩展不会将容器应用内的数据泄露给主应用。
应用程序扩展的执行方式和应用程序的执行方式也不一样。如果你在不同的应用内同时开起了多个同样的应用程序扩展,系统实际上会打开多个应用程序扩展进程、每个都作为一个独立的进程单独运行。比如说你在 Safari 里打开了一个扩展、而后在邮件里也打开了一个同样的扩展,那么即使扩展都一样,系统实际上会运行两个不同扩展程序进程。这些进程之间不会利用你相同的存储地址区域,因此这能让两个主应用使用独立的数据,并且如果一个应用扩展进程崩溃了也不会影响另一个进程。像 Chrome 和 Safari 这样的浏览器也出于同样的目的,每个网页标签实际上也是分别运行的。
Extension限制
上线限制
像所有未越狱的 iPhone 里的软件一样,所有的 iOS 扩展将需要从苹果应用商城中下载。不过此处最大的限制是苹果公司不会允许开发者提供仅仅作为扩展出现的应用。开发者必须提供一个基本的「容器应用程序」,扩展则作为锦上添花的内容存在于这个基本的应用程序内。苹果公司强调,这个基本的「容器应用」必须提供给用户一些基本的功能,否则他们不会授权该软件登陆应用商店。这一点有别于安卓。
通信限制
对于Extension与其它应用程序之间的通信,苹果有几项强制规定:
1. 调用Extension的应用程序即主应用程序不能启动Extension;只有系统可以启动Extension。
2. 当Extension启动后,主应用程序就和它直接通信。
3. 主应用程序永远不和包含应用程序直接通信。
4. Extension不是一个应用程序,但它由系统生成,并有它自己单独的进程。
5. 为了在包含应用程序和它的Extension之间共享数据,包含应用程序及其Extension都必须是应用程序组的一部分。对于应用程序组的其中两个成员,部分数据可以在两者沙箱之外的第三个容器中共享。
正如Ars Technica的Andrew Cunningham总结的那样,这些
规则的最终结果主要是一个应用程序不能进入另一个应用程序的沙箱。这与Android相反,在Android上,内容提供程序和解析程序仍然可以一起工作来为应用程序提供对其它应用程序中数据的访问。
参考链接:
App Extension Programming Guide
App Extension编程指南(iOS8/OS X v10.10):创建应用扩展
WWDC2014 IOS8 APP Extensions
App Extension编程指南(iOS8/OS X v10.10):扩展类型--自定义键盘
如何在Swift中创建Action扩展
网友评论