美文网首页ios进阶酷
AppExtension:扩展的学习笔记

AppExtension:扩展的学习笔记

作者: 双鱼子曰1987 | 来源:发表于2021-04-20 13:13 被阅读0次

一、概述

“扩展”的原理网上有很多,官网也清晰讲明,具体参见以下官方链接。
本文旨在整理笔记,简述相关原理,以备后续查看。

二、AppExtension基本原理

1、搞清楚几个

概念

  • App Extension,Apple定义为”扩展“,也可以理解为”插件“。

  • Host App,能够调起extension的app被称为host app。
    An app that a user employs to choose an app extension is called a host app.
    例如,widget的host app就是Today。

  • Containing App,包含一个或者多个的Extension的App叫做ContainingApp,也叫做宿主App。
    an app that contains one or more extensions is called a containing app

2、iOS是如何处理扩展?

  • 扩展不是独立App,系统将其初始化为单独的进程。
    基于安全和性能的考虑,每一个扩展运行在一个单独的进程中,它拥有自己的bundlebundle后缀名是.appex

    iOS系统把扩展定义为 额外功能的触发入口点,它不是一个独立的App。因此,它必须依赖于宿主App,不能单独存在,也就没办法单独提审AppStore。
    An app extension is not an app. It implements a specific, well scoped task that adheres to the policies defined by a particular extension point.
    An app extension is different from an app. Although you must use an app to contain and deliver your extensions, each extension is a separate binary that runs independent of the app used to deliver it.

3、扩展的生命周期问题(App Extension’s Life Cycle)。

app_extensions_lifecycle_2x.png

主要有以下四个步骤:
1、用户触发“扩展”,如UI触发或者代码触发。
2、iOS系统自动唤起“扩展”。
3、执行“扩展”代码。
4、执行完成后,系统杀死“扩展”,回收资源。

三、扩展相关的通信

1、通信归类

  • Host App 与 ContainingApp 无法直接通信!
    An app extension’s containing app and the host app don’t communicate at all.

  • 扩展与Host App的通信是基于request/response模型。

    simple_communication_2x.png
  • 一般,扩展与ContainingApp是无法直接通信的,例如扩展允许的时候,宿主App可能还未运行。
    There is no direct communication between an app extension and its containing app; typically, the containing app isn’t even running while a contained extension is running.

2、扩展与ContainingApp的有限通信

the limited interaction available between an app extension and its containing app.

  • A Today widget 可以通过UrlSchemes的方式唤起ContainingApp。
    通过NSExtensionContext的方法openURL:completionHandler:

  • 扩展和ContainingApp可以通过shared container实现间接通信。
    数据共享 shared container 与 扩展AppExtension 、ContainingApp的实现彼此双向数据通信。

    detailed_communication_2x.png

3、request/response模型的理解

request/response是通过 ”上下文“ 机制实现。HostApp为”扩展“提供运行的上下文(an extension context)。大致流程是,HostApp将 RequestData 通过上下文(an extension context) 输送给 扩展AppExtension,扩展进行处理(UI显示,用户交互,代码处理等),处理完成后将 ResponseData 返回给HostApp。

由于”扩展“是一个独立的进程,一般一个App也是一个独立进程,因此它们间通信应该是基于进程间的通信方式。例如Socket、管道等,至于哪一种官方好像未说明(待研究)。

4、扩展(App Extension)与宿主App(Containing App)的数据共享shared container

虽然AppExtension的Bundle被导入如ContainingApp的包内,但是彼此的沙盒是没办法访问的。Apple发明了share container的中间层,来实现彼此的数据共享问题。也被称之为AppGroup的概念。
这也映射软件工程的一句经典话语:多了个中间层,一切都显得那么美好。

基本原理如下:Apple允许 App进程扩展进程 都可以对SharedContainer的共享数据区进行操作。

app_extensions_container_restrictions_2x.png
如何集成AppGroup能力?
  • ContainingApp和Extension的Target中,分别都打开AppGroup的能力。
    To enable data sharing, use Xcode or the Developer portal to enable app groups for the containing app and its contained app extensions.

  • 对应的开发和发布证书都必须勾选开启AppGroup的能力。

  • 同一个ContainingApp或者扩展下面,可以有多个AppGroup,根据名字区分,名字必须以group.开头。

  • 开启AppGroup后,App和扩展工程目录下的环境文件.entitlements里面多了一个App Groups

    FE61DC22-9CCC-416D-925A-55AEA2E9083D.png
支持的系统框架
  • NSUserDefaults
    必须使用initWithSuiteName:方法来初始化一个NSUserDefaults对象,其中的SuiteName就是创建的Group的名字,然后利用这个对象来实现,跨应用的数据读写

  • NSFileManager
    通过调用 containerURLForSecurityApplicationGroupIdentifier: 方法可以获得AppGroup的共享目录,然后在此目录的基础上实现任意的文件操作。

  • CoreData
    在初始化CoreData时,先使用NSFileManager取得共享目录,然后再指定共享目录为存储数据文件的目录。

共享数据的数据同步问题!

可以使用CoreData、SQList或者Posix locks锁技术,来实现数据同步问题。
Use Core Data, SQLite, or Posix locks to help coordinate data access in a shared container.

四、代码能力相关

1、能力限制

  • 包含NS_EXTENSION_UNAVAILABLE宏声明的API,则此API在”扩展“中将不可用。
    例如,扩展中无法使用+ (UIApplication *)sharedApplication
  • 不能使用 sharedApplication 对象及其其中的方法。
  • ”扩展“无法使用摄像头和麦克风。
  • ”扩展“无法通过AirDrop接收数据。
  • ”扩展“无法运行长时间的后台任务long-running background tasks
  • 系统严格限制 "扩展" 的内存
    这是因为在同一时间可能会有多个扩展同时运行,如Widget扩展。

2、代码复用

  • 内嵌一个framework文件在扩展和containing app之间共享代码。
    假设你希望在你的containing app与扩展之间共享图片处理的代码,此时你可以将代码打包成framework文件,内嵌到两个目标中。对于内嵌框架中的代码,确保不包含扩展不允许使用的API。
    官方自定义方案-Handling Common Scenarios
扩展Framework的要求
  • 设置扩展Target的Require Only App-Extension-Safe API为YES,否则Xcode会提醒linking against dylib not safe for use in application extensions
    To configure an app extension target to use an embedded framework, set the target’s “Require Only App-Extension-Safe API” build setting to Yes.If you don’t, Xcode reminds you to do so by displaying the warning “linking against dylib not safe for use in application extensions”.

  • 提审必须是包含arm64 (iOS) or x86_64 (OS X)
    A containing app that links to an embedded framework must include the arm64 (iOS) or x86_64 (OS X) architecture build setting or it will be rejected by the App Store.

  • 勾选Copy Files build phase.
    When configuring your Xcode project, you must choose “Frameworks” as the destination for your embedded framework in the Copy Files build phase.

五、实例

见另外一篇推送支持图片,详见:
AppExtension:NotificationServiceExtension集成、调试、打包的实践


参考

官网-Adding an App to an App Group.
官网-App Extensions Increase Your Impact
iOS 8新特性之扩展
App Extension编程指南(iOS8/OS X v10.10)中文版
iOS扩展开发攻略(一) - Share Extension
活久见的重构 - iOS 10 UserNotifications 框架解析

相关文章

网友评论

    本文标题:AppExtension:扩展的学习笔记

    本文链接:https://www.haomeiwen.com/subject/dybglltx.html