Share Extension 简介
前两篇文章介绍了Application Extension运行原理、Today Extension,本篇来介绍一下 Share Extension 创建和使用。
分享扩展给用提供一个方便的途径来分享内容,例如在某个带有分享按钮的应用中,用户可以选择一个分享扩展,来把要想分享的内容或者评论发布到自己的社交账号。
可以在iOS、macOS上创建分享扩展,在创建之前要注意:
- 确保用户在使用你的分享扩展时,方便、快捷
- 确保用户能够预览、编辑、配置要分享的内容
- 在分享之前确认内容
创建 Share Extension
下面就来在iOS上创建一个分享扩展,就接着上篇的Today项目里面创建。
注意本例子使用的是 Xcode9,iOS 11。
新建 target
创建之后Xcode默认的模板就可直接运行,在运行的时候可以选择运行主体应用Containing App,想要看到你的分享的扩展,需要另打开一个带有分享按钮的应用当做你的扩展的宿主应用Host App,在Host App中展开分享页面才能看到,要是看不到的话,点击More更多按钮,在里面打开就能看到。
最好直接选择分享扩展运行,方便我们调试,在选择分享扩展运行时,弹出个框选择一个iOS App来当做你的扩展的Host App,如下图所示:
例子选择打开系统的相册,运行打开相册,点击分享按钮,看到创建的扩展,点击就会弹出系统默认的编辑视图。
若是系统弹出的默认编辑视图不能满足你的需求,也可以不用系统默认的分享弹出框,完全自己实现一个编辑视图。
声明 Share Extension 支持的数据类型
使用Xcode创建 Share Extension 后,项目文件夹里默认生成的文件有 ShareViewController、Info.plist、storyboard。
Info.plist里面包含 Share Extension 的一些配置文件,值得注意的是 NSExtension 扩展描述字段,用来设置扩展的一些属性:
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<string>TRUEPREDICATE</string>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
根据你的分享扩展的需要去添加对应键。
NSExtensionAttributes 是用来描述扩展的属性字段,里面包含了 NSExtensionActivationRule ,这个用来控制 Share Extension 或者 Action Extension 所能支持的分享的内容,默认的值是 TRUEPREDICATE 分享的内容都满足扩展需要,该分享扩展会一直在分享列表显示供用户使用。如果对分享的内容有所限制,例如微信、微博,最多能分享九张图,如果你的选择了多于九张图,则在分享列里就不会显示微信、微博的分享。想要添加限制,需要修改 NSExtensionActivationRule 对应的值为 dictionary,里面所能包含的键有AppExtensionKeys:
包含了支持的最大、最小的内容个数、文件个数、图片个数、视频个数、链接个数等。例如下面的属性配置最大支持10张图片、1个视频、1个网页:
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>10</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
如果不支持某特定的数据格式可设置值为0,或者从dictionary中移除对应的值。
处理 Share Extension 的数据
默认创建的ShareViewController 继承自SLComposeServiceViewController 。在ShareViewController中有个 didSelectPost 方法:
//用户点击发布post按钮后,调用此方法。
//默认状态会在该方法里面实现extensionContext 的 -completeRequestReturningItems:completionHandler:方法
//子类要覆盖此方法,从而能够根据上下文内容,来执行post操作
// 子类可以用super调用此方法来完成默认的行为; 如果一个子类不调用super,那么它必须手动调用extensionContext的completeRequestReturningItems:方法。
- (void)didSelectPost {
//执行post 操作
//获取分享的内容,发送请求
//NSExtensionItem *inputItem = self.extensionContext.inputItems.firstObject;
[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
//或者直接调用 [super didSelectPost] 默认状态下完成操作
}
NSExtensionContext 类型的属性,是宿主应用(Host App) 调起扩展所对应的上下文,里面的值包含了想要分享的图片、文字、网页等内容信息。
- 属性 inputItems : 该数组存储着容器应用传入给NSExtensionContext的NSExtensionItem数组。其中每个NSExtensionItem标识了一种类型的数据。
- 方法 completeRequestReturningItems: 通知宿主应用的扩展已完成发布请求。调用此方法后,扩展视图会关闭,其中的items就是返回宿主应用中的数据项。
- 方法 cancelRequestWithError: 通知宿主应用的扩展已取消请求。其中error为错误的描述信息。
NSExtensionItem类的结构如下:
NSExtensionItem中的attachments属性,是一个附件数组,数组里的是NSItemProvider类型,其中包含了图片、视频、链接等内容。
要想获得 NSItemProvider 中的内容会使用到其类中的一个方法 loadItemForTypeIdentifier:options:completionHandler 加载typeIdentifier指定的资源,加载完成后会触发completionHandler。
所以 NSExtensionContext 上下文里的数据结构如下:
从 NSItemProvider 中获取分享内容的方法,如下(获取分享的网页链接的数据):
[self.extensionContext.inputItems enumerateObjectsUsingBlock:^(NSExtensionItem * _Nonnull extItem, NSUInteger idx, BOOL * _Nonnull stop) {
[extItem.attachments enumerateObjectsUsingBlock:^(NSItemProvider * _Nonnull itemProvider, NSUInteger idx, BOOL * _Nonnull stop) {
if ([itemProvider hasItemConformingToTypeIdentifier:@"public.url"]) {
[itemProvider loadItemForTypeIdentifier:@"public.url"
options:nil
completionHandler:^(NSURL * _Nullable item, NSError * _Null_unspecified error) {
//NSLog(@"url === %@", item);
}
}];
}];
就这样一步步获取到要分享的内容,获取到内容后发送内容给服务器,Share Extension 可以通过与容器应用Containing App 共享数据,在Containing App中显示从 Host App 分享过来的数据。
(Extension和Containing App间共享数据,在上一篇文章Today Extension有介绍,同样的方法可以去查看,这里就不在赘述了)
简单的写了个小例子,效果如下:
Demo地址:https://github.com/MA806P/MYZAppExtension
Reference
App Extension Programming Guide - Today
http://www.jianshu.com/p/863ce6729455