分享内容

国内主流 app 的分享功能都是自定义的,这样做的考虑主要是为了让流量留在自己的生态中,另一方面 UIActivityViewController 不太符合国人的使用习惯。

相比之下,国外的 app 如 Twitter,使用的都是苹果从 iOS 6 开始引入的 UIActivityViewController。

iOS 中的分享 - 图1 如果你的 app 面向国外用户,UIActivityViewController 了解一下。:)

UIActivityViewController 使用起来非常方便,首先初始化一个实例:

  1. init(activityItems: [Any], applicationActivities: [UIActivity]?)

其中,activityItems 是你要分享的内容,可以是字符串、URL或者图片等内容。但是接受分享的应用能接受的文件类型不一样,我们还可以通过自定义 activityItems 来实现以不同形式分享到不同应用的功能。

要自定 activityItems,只需实现 UIActivityItemSource ,它有两个必选方法:

  1. func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any
  2. func activityViewController(_ activityViewController: UIActivityViewController,
  3. itemForActivityType activityType: UIActivityType?) -> Any?

其中第一个方法返回一个 placeholder,官方文档是这样解释的

For example, the placeholder could be a UIImage object but the actual value could be an NSData object with PDF information.

个人理解是比如 PDF 渲染速度较慢,UIActivityViewController 会先查询 placeholder 显示出来。

第二个方法返回的就是实际要分享的内容,可以根据不同的 UIActivityType 返回不同类型的数据。比如拷贝到剪贴板返回字符串,分享到微信返回图片。如果分享的是一个自定义文件,返回文件的 URL 即可。

至于 UIActivityItemProvider,只是官方给出的一个实现了 UIActivityItemSource 协议的类。

实例化完毕之后,UIActivityViewController 还有一些属性需要设置:

  • excludedActivityTypes:设置你不想显示的分享类型。

  • popoverPresentationController?.sourceView:在 iPad 上显示成 popover 时需要设置

  • popoverPresentationController?.sourceRect:在 iPad 上显示成 popover 时需要设置

  • popoverPresentationController?.barButtonItem:在 iPad 上显示成 popover 时需要设置

  • completionWithItemsHandler:分享结束后的回调

最后 present 设置完毕的 UIActivityViewController。

至此,分享功能就介绍完了。

打开分享的文件

但是如果想用你的 app 打开某个文件,也就是出现在 UIActivityViewController 分享界面中,还需要做额外的一些工作。

在开始之前,你需要了解 UTI(Uniform Type Identifiers) 的概念。

简单来讲,UTI 是苹果定义的用来区分文件类型的标志符。同样是文本文件,不同文件的后缀名可能是 txt、text、html,但实际上一个纯文本编辑器都能打开它们。如果系统遇到一个陌生的文件后缀,也可以通过 UTI 来正确识别,并且知道哪些应用可以用来打开这个文件。

iOS 中的分享 - 图2

可以看到 UTI 本身是个树形结构,类似于类的继承关系,所有的 UTI 都符合(Conforms To)public.data,可以理解成所有 UTI 最终都是 public.data 的子 UTI。

现在要做的就是在 Xcode 的 Info.plist 中的 Document Type 里添加要支持的 UTI,具体步骤参见官方文档。可以根据 Apple 已经定义好的 UTI 列表添加对应的 UTI。

这样,当用户分享特定文件时就可以看到你的 app 了,如何获取内容呢?

AppDelegate 有个方法:

  1. func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool

当系统通过你的 app 打开文件时会调用这个方法,其中的 url 就是文件的 URL,可以通过这个 URL 来获取文件内容。

自定义文件类型

如果你的 app 会生成自定义格式,那么你需要声明一个自定义的 UTI,Exported UTI 了解一下。

要声明一个自定义的 UTI 需要以下几个信息:

  • UTTypeIdentifier:自定义 UTI 的唯一标识符。

  • UTTypeTagSpecification:包含后缀名、对应的 MIME type 等信息。

  • UTTypeConformsTo:符合的已有 UTI,可以理解成父 UTI。

  • UTTypeIconFile(可选):文件显示的图标

  • UTTypeDescription:用来描述文件类型的字符串

要注意的是:

  • 要保证自定义 UTTypeIdentifier 的唯一性,可以使用

官方的一个示例:

  1. <key>UTExportedTypeDeclarations</key>
  2. <array>
  3. <dict>
  4. <key>UTTypeIdentifier</key>
  5. <string>public.jpeg</string>
  6. <key>UTTypeReferenceURL</key>
  7. <string>http://www.w3.org/Graphics/JPEG/</string>
  8. <key>UTTypeDescription</key>
  9. <string>JPEG image</string>
  10. <key>UTTypeIconFile</key>
  11. <string>public.jpeg.icns</string>
  12. <key>UTTypeConformsTo</key>
  13. <array>
  14. <string>public.image</string>
  15. <string>public.data</string>
  16. </array>
  17. <key>UTTypeTagSpecification</key>
  18. <dict>
  19. <key>com.apple.ostype</key>
  20. <string>JPEG</string>
  21. <key>public.filename-extension</key>
  22. <array>
  23. <string>jpeg</string>
  24. <string>jpg</string>
  25. </array>
  26. <key>public.mime-type</key>
  27. <string>image/jpeg</string>
  28. </dict>
  29. </dict>
  30. </array>

具体的添加方法,参见官方文档

参考