最近在研究ios8 的分享扩展,虽然这个技术早就出来了,但是除了微信,微博,其他的APP好像很少有用到这个技术的,就连QQ也是最近才加上的这个功能,想问旁边的技术大牛,但是很不幸,他们也都没有做过,只好由我这个菜鸟闭门造车自己来研究了。基础知识咱就不罗嗦了,就谈一谈我在研究分享扩展的时候遇到的一些问题吧,尽管我现在还是没能把分享扩展研究的很透彻。
1、如果你想指定你的分享扩展可以使用的分享内容类型,以便用户理解他们能分享什么内容,可以通过这些内容来指定。
Key | Description |
---|---|
| Include this key to indicate to the system and to other apps that your app supports a maximum number of attachments. |
| Include this key to indicate to the system and to other apps that your app supports a minimum number of attachments. |
| Include this key to indicate to the system and to other apps that your app supports files in general. |
| Include this key to indicate to the system and to other apps that your app supports image files. |
| Include this key to indicate to the system and to other apps that your app supports movie files. |
| Include this key to indicate to the system and to other apps that your app supports text. |
| Include this key to indicate to the system and to other apps that your app supports web URLs. |
| Include this key to indicate to the system and to other apps that your app supports web pages. |
NSExtensionJavaScriptPreprocessingFile
这个是string类型的,在iOS和OS X平台可用。在分享扩展中可以加入这个文件,你可以给在分享扩展中提供的js文件起一个特定的名字。提供了js文件后,当你用Safari作为host app使用分享扩展分享一个网页时,我们就可以从扩展中提取出关于网页的更多的内容。比如title,URL。
值得一提的是,当你在你的分享扩展中的plist文件中加入NSExtensionActivationRule这个属性,并且用了以上的子属性后,没有出现在plist文件列表中的子属性,在你使用分享扩展时,是不会出现的,就比如我的plist文件是这样的,我做的分享扩展其实就是只是在Safari中可以分享一个网页就可以了,所以没有加入NSExtensionActivationSupportsImageWithMaxCount这些属性都没有,那么当我在Photos中想分享一张图片时,这个分享扩展是不会出来的。
2、关于调试,很多人说什么先运行containing app,再在真机上运行host app什么的就可以调试,但是我真是试了好多次,发现都不行,command+R按了无数次,总是不能调试,就这个问题纠结了好几点,点了post之后什么反应都没有,不能调试我怎么找原因啊,是吧,纠结的我啊,后来我心一横,不在真机上command+R了,选择的是模拟器,结果就可以调试了,看下面正方形是黑色的就证明是可以调试了,虽然我没想清楚是为啥,但是这也是给了我一个教训,脑袋不能一根筋的转,当找不到解决办法的时候就换个方式试试,没准就柳暗花明了呢,之前一直奉行真机才可以调试,所以一直就没有试过模拟器。
but,几天后又试了一下,可以在真机上调试了,真是奇怪。
3、好了,终于可以调试了,那下面就是数据提取了,问题又来了,为啥我按照网上的那些提取方法,就提取不出来数据呢,这里借用大神的一点文字说明:
提取数据
extensionContext
是一个 NSExtensionContext 对象,分享的数据都封装在其inputItems
属性中,这是一个包含 NSExtensionItem 对象的数组。实际上,不管你分享了多少内容,文字、多张图片或是链接,都封装在一个 NSExtensionItem 对象里,该对象中最重要的属性是attachments
,是个NSItemProvider对象数组,每个 NSItemProvider 对象包含了单个分享的数据,可以是文字、图片、视频或是 URL。这些数据都由载体应用提供,使用 UIActivityViewController 来实现分享的时候传递的数据就封装在 NSItemProvider 对象里,也就是说实际上我们要从 NSItemProvider 对象里提取分享的数据。
NSItemProvider 类也是 iOS 8 中的新类,使用一种安全的方式在载体应用和 扩展之间传递数据,提供了以下两个方法来获取数据:
- (BOOL)hasItemConformingToTypeIdentifier:(NSString *)typeIdentifier
//用于获取封装的数据类型,咋看之下非常别扭。需要提供 Uniform Type Identifier 简称 UTI 格式的标志符来找出数据类型。
- loadItemForTypeIdentifier:options:completionHandler:
//指定格式来获取数据,异步执行。
至于指定数据,获取格式什么的,我们可以用官方文档中的数据格式,比如public.image, public.text这种格式,具体可参考官方文档的此链接
https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html#//apple_ref/doc/uid/TP40009259-SW1
Identifier (Constant) | Conforms to | Tags | Comments |
---|---|---|---|
public.item ( | - |
| Base type for the physical hierarchy. |
public.content ( | - |
| Base type for all document content. |
public.composite-content ( | public.content |
| Base type for mixed content. For example, a PDF file contains both text and special formatting data. |
public.data ( | public.item |
| Base physical type for byte streams (flat files, pasteboard data, and so on). |
public.database | - |
| Base functional type for databases. |
public.calendar-event | - |
| Base functional type for scheduled events. |
public.message ( | - |
| Base type for messages (email, IM, and so on). |
public.presentation | public.composite-content |
| Base type for presentations. |
public.contact ( | - |
| Base type for contact information. |
public.archive ( | - |
| Base type for an archive of files and directories. |
public.disk-image ( | public.archive |
| Base type for items mountable as a volume. |
public.text ( | public.content, public.data |
| Base type for all text, including text with markup information (HTML, RTF, and so on). |
public.plain-text ( | public.text | .txt, text/plain | Text of unspecified encoding, with no markup. Equivalent to the MIME type text/plain |
public.utf8-plain-text ( | public.plain-text | 'utf8', NSStringPBoardType | Unicode-8 |
public.utf16-external-plain-text ( | public.plain-text | 'ut16' | Unicode-16 with byte-order mark (BOM), or if BOM is not present, an external representation byte order (big-endian). |
public.utf16-plain-text ( | public.plain-text | 'utxt' | Unicode-16, native byte order, with an optional byte-order mark (BOM). |
com.apple.traditional-mac-plain-text | public.plain-text | 'TEXT' | Classic Mac OS text. |
public.rtf ( | public.text | 'RTF ', .rtf, text/rtf, NeXT Rich Text Format 1.0 pasteboard type, NSRTFPBoardType | Rich Text. |
上面写到,我们是在loadItemForTypeIdentifier:options:completionHandler可以下载数据,但是我遇到的问题是,我根本下载不了数据,但是检查了一下,觉得写得代码也没有什么问题啊,断点调试才发现这个方法中的completionHandler的闭包方法根本就没有被执行,查了很久的资料才发现是
[self.extensionContextcompleteRequestReturningItems:@[]completionHandler:nil];
这句代码出现了问题,这个是系统自动加在
- (void)didSelectPost方法中的,
- completeRequestReturningItems:completionHandler:
在didSelectPost
方法的最后调用,用于向载体应用反馈结果并且准备结束扩展的运行。一般来讲也没啥消息好反馈的。
但是下载数据是异步下载的,所以在我们还没有把数据下载下来的时候,就已经把扩展给结束掉了,那自然就无法提取数据了。解决方法就是把数据提取不要放在didSelectPost方法里执行,或者可以在异步下载完数据以后,再调用.-completeRequestReturningItems:completionHandler:方法,就ok啦。
5、我在Xcode中另外新建了一个分享扩展,然后把他们运行在机器上,但是不知道为什么在我的机器上(iPhone 5,iPhone 6s Plus)上都不显示,后来调了下才发现原来扩展也有它自己的deployment target,当我们把扩展的deployment target改为比我们的设备的iOS 版本低的时候就可以显示出来了,之前新建的时候没改,一直是9.1,我的iPhone 5是8.0的,所以显示不出来。
二、存在的问题
(1)如何像微信、QQ那样自定义UI,试了还没成功
(2)如何后台上传数据,目前只是利用App Groups保存在NSUserDefaults中,然后在containing app中进行数据上传。
菜鸟一个,学习较慢。