OC网络学习12:App Extengsion-探索

张建 lol

关于

Extension 是 iOS8 新开发的一种对几个固定系统区域的扩展机制,它可以在一定程度上 弥补 iOS 的 沙盒机制对应用间通信的限制

定义

简单的说,App Extension 可以让开发者们 拓展自定义的功能和内容 到应用程序之外,并在用户与其他应用程序或系统交互时提供给用户

用途

你可以创建一个 App Extension,通过打开一个特殊的 开关,如下:

  • Share Extension:让用户从浏览器分享至其他社交软件中

  • Network Extension:给用户提供一个网络的扩展

扩展点(Extension Point)

  • Extension Point:启用扩展的区域称为 扩展点,系统中支持 Extension 的区域,Extension 的类别也是据此区分的,iOS上有 Share、Action、Photo Editing、Custom Keyboard、Widget 等。

  • 每种 Extension Point 的使用方式和适合干的工作都不同,因此不存在通用的 Extension Point

App

  • 就是我们正常手机里的每个应用程序,即 Xcode 运行后生成的程序。一个 App 可以包含一个或多个target,每个 target 将产生一个 product

Target

  • Target : 在项目中新建一个 Target 来创建 App Extension ,任意一个 Target 指定了应用程序中构建 Product 的设置信息和文件。

扩展(App Extension)

  • App Extension 并不是一个独立的 App,它有一个包含在 App Bundle 中独立的 Bundle,其后缀名是 .appex,其 生命周期 和普通 App 不同。

  • App Extension 不能单独存在,必须有一个包含它的 Containing App

  • 另外,App Extension 需要用户手动激活,不同的App Extension激活方式不同,比如:Custom Keyboard 需要在设置中进行相关设置;Photo Editing 需要在使用照片时在照片管理其中激活或关闭;ShareAction 可以在任何应用里被激活,但前提是开发者需要设置 Activation Rules ,以确定 App Extension 需要在合适出现。

Containing App

  • 在 iOS 中 ,App Extension 并不能单独存在,要想提交到 AppStore,必须将 App Extension 包含在一个 App 中提交,并且 App 的实现部分不能为空,这个包含 App ExtensionApp 就叫 Containing App

  • 一个 App 可以包含一个或多个 Extension

Host App

  • 包含 App Extension 并且能从中打开它(并不一定非要从此 App 内部打开,可以是 App 内部也可以)。我们可以把它理解为 宿主App,能够调起 ExtensionApp 被称为 Host App

App Extension 生命周期 (Life Cycle)

因为 App Extension 不是一个 App,它的 生命周期App 是不同的,在大多情况下,当用户从 App 的UI上或者其他视图控制器中选择开启 Extension 功能的选项时将会开始执行。

  • 开始:A Host App 定义了上下文提供给 Extension, 当它发送一个请求并且用户正确响应后开启 Extension 的生命周期。

  • 结束:通常会在完成 Host App 收到的请求后立即终止。

App Extension 生命周期

Extension 与 普通App 最大的区别就是 生命周期

  • 开始

在用户通过 Host App 点击 Extension 时,系统会实例化 Extension 应用,这是生命周期的开始

  • 执行任务

在 Extension 启动以后,开始执行它的使命

  • 终止

在用户取消任务,或者任务执行结束,或者开启了一个长时间后台任务时,系统会将其杀掉

由此可见,Extension 就是为了 任务 而生

App Extension 和 Host App 、Containing App 如何通讯

  1. App Extension 和 Host App

可以通过 ExtensionContext 属性直接通信,改属性是新增加的 UIViewController 类别:

1
2
3
4
5
6
7
 	
@interface UIViewController(NSExtensionAdditions) <NSExtensionRequestHandling>

// Returns the extension context. Also acts as a convenience method for a view controller to check if it participating in an extension request.
@property (nonatomic,readonly,retain) NSExtensionContext *extensionContext NS_AVAILABLE_IOS(8_0);

@end

实际上 ExtensionHost App 之间是通过 IPC(interprocess communication) 实现的,只是苹果把调用接口高度抽象了,我们并不需要关注那么底层的东西。

  1. Containing App 和 Host App

他们之间没有任何直接关系,也 从来不需要通信

  1. App Extension 和 Containing App

这二者之间的关系最复杂,纠纠缠缠扯不清关系。

  • 不能直接通信

首先,尽管 Extensionbundle 是放在 Containing Appbundle 中,但是他们是两个完全独立的进程,之间 不能直接通信

不过 Extension 可以通过 openURL 的方式启动 Containing App(当然也能启动其它app),不过必须通过 extensionContext 借助 Host App 来实现:

1
2
3
4
5
6
// 通过openURL的方式启动Containing APP
- (void)openURLContainingAPP{
[self.extensionContext openURL:[NSURL URLWithString:@"appextension://123"] completionHandler:^(BOOL success) {
NSLog(@"open url result:%d",success);
}];
}

Extension 中是无法直接使用 openURL 的。

  • 可以共享 Shared Resources

ExtensionContaining App 可以共同读写一个被称为 Shred Resources 的存储区域,这是通过 App Group 实现的。

  • Containing App 能够控制 Extension 的出现和隐藏

通过以下代码,Containing App 可以让 Extension 出现或隐藏(当然 Extension 也可以让自己隐藏):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 让隐藏的插件重新显示
- (void)showTodayExtension{
[[NCWidgetController widgetController] setHasContent:YES forWidgetWithBundleIdentifier:@"com.wangzz.app.extension"];
}

// 隐藏插件
- (void)hiddeTodayExtension{
[[NCWidgetController widgetController] setHasContent:NO forWidgetWithBundleIdentifier:@"com.wangzz.app.extension"];
}
```

# App Groups文件路径

下面代码用于打印 App Groups路径、应用的可执行文件路径、对应的Documents路径:

// App Groups路径
NSURL * containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:ApplicationGroupIdentifier];
NSLog(@”=====app group:=====\n%@”,containerURL.path);

// 打印可执行文件路径
NSLog(@”=====bundle:=====\n%@”,[[NSBundle mainBundle] bundlePath]);

// 打印documents
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
NSLog(@”=====documents:=====\n%@”,path);

1
2
3

* Containing App

2023-07-05 16:56:31.862847+0800 零信任[20109:1279420] =====app group:=====
/private/var/mobile/Containers/Shared/AppGroup/2E1178DA-ED5B-49AD-ABCB-B49AD88F1D4D

2023-07-05 16:56:31.862926+0800 零信任[20109:1279420] =====bundle:=====
/private/var/containers/Bundle/Application/F3FE7759-284D-4D79-A0FC-24D9F71EA9CF/零信任.app

2023-07-05 16:56:38.918528+0800 零信任[20109:1279420] =====documents:=====
/var/mobile/Containers/Data/Application/4E039FD4-7EB7-4A8B-B436-68BCA93DE2DC/Documents

1
2
3

* Extension 路径

=====app group:=====
/private/var/mobile/Containers/Shared/AppGroup/2E1178DA-ED5B-49AD-ABCB-B49AD88F1D4D

=====bundle:=====
/private/var/containers/Bundle/Application/F3FE7759-284D-4D79-A0FC-24D9F71EA9CF/零信任.app/PlugIns/tunnel.appex

=====documents:=====
/var/mobile/Containers/Data/PluginKitPlugin/213025D2-89D3-4938-B513-B2F3CB9D5F8F/Documents

```

由此可见,不管是 Extension 还是 Containing App,它们的可执行文件和保存数据的目录是分开存放的,即所有 App 的可执行文件都放在一个目录下,保存数据的目录保存在另一个目录下,同样,App Groups 放在另一个目录下

  • Post title:OC网络学习12:App Extengsion-探索
  • Post author:张建
  • Create time:2023-07-04 16:59:48
  • Post link:https://redefine.ohevan.com/2023/07/04/OC网络/OC网络学习12:App Extengsion-探索/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.