iOS分享扩展:在Safari上通过上下文菜单分享时获取页面的URL

20

我想要什么

我正在尝试实现以下用户流程:

  1. 用户在iOS Safari中浏览网页。
  2. 用户选择一些内容(文本和图像)并等待上下文菜单出现。
  3. 用户选择“分享…”项。
  4. 用户在从底部弹出的共享菜单中选择我的应用扩展程序。
  5. 所选内容和网页URL通过HTTP调用共享到远程服务器。

我尝试过的方法

我通过Xcode制作了一个Share扩展程序。这是我的info.plist文件中的NSExtension部分:

<key>NSExtension</key>
<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>NSExtensionActivationRule</key>
        <dict>
            <key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
            <integer>1</integer>
            <key>NSExtensionActivationSupportsText</key>
            <true/>
            <key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
            <integer>1</integer>
        </dict>
        <key>NSExtensionJavaScriptPreprocessingFile</key>
        <string>test</string>
    </dict>
    <key>NSExtensionMainStoryboard</key>
    <string>MainInterface</string>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.share-services</string>
</dict>

这是test.js文件:

var GetURL = function() {};
GetURL.prototype = {
run: function(arguments) {
    arguments.completionFunction({"URL": document.URL});
}
};
var ExtensionPreprocessingJS = new GetURL;

我期望以下结果:在viewDidLoad方法中,extensionContext?.inputItems将为我提供多个输入项,通过这些输入项,我将能够获取所选内容和网页URL。

出了什么问题

viewDidLoad方法中,extensionContext?.inputItems仅向我提供一个项目--选择的内容的纯文本表示(即使同时选择图像和文本)。我可以使用纯文本,但我需要网页URL。

我的问题

如何在iOS Safari中使用共享扩展通过上下文菜单共享所选内容时获取已打开网页的URL?

2个回答

17

Swift 3

尝试按照以下方式进行:

override func didSelectPost() {
    if let item = extensionContext?.inputItems.first as? NSExtensionItem,
        let itemProvider = item.attachments?.first as? NSItemProvider,
        itemProvider.hasItemConformingToTypeIdentifier("public.url") {
        itemProvider.loadItem(forTypeIdentifier: "public.url", options: nil) { (url, error) in
            if let shareURL = url as? URL {
                // do what you want to do with shareURL
            }
            self.extensionContext?.completeRequest(returningItems: [], completionHandler:nil)
        }
    }
}

"public.url"可以被从MobileCoreServices导入的kUTTypeURL字符串所替代。


这应该是被接受的答案,我在应用Swift3语法后它对我有效:itemProvider.loadItem(forTypeIdentifier: "public.url", options: nil, completionHandler: { (url, error) -> Void in - Yun CHEN
@YunCHEN 谢谢你的提示。已将答案更新为 Swift 3。 - Joe
你好,有关于docx/pdf的解决方案吗?谢谢。 - famfamfam

6

我已经在一个下午尴尬地阅读了这些文档,并尝试了不同的扩展组合,因为我想做的正是(我认为)你想做的事情。

我得出结论,在iOS上无法实现此精确的流程。 如果用户选择文本并使用上下文菜单(即“复制”,“查找”,“共享”...),则您的扩展将仅接收到他们选择的文本中的NSItemProvider,即没有包含预处理javascript结果的plist文件。当他们从该菜单中选择“共享”时,只有当您在扩展的Info.plist文件中设置了NSExtensionActivationSupportsTextYES时,扩展程序才会显示出来。

为了运行预处理javascript,扩展必须将NSExtensionActivationSupportsWebPageWithMaxCount设置为大于0的值,如文档所述。如果扩展程序通过所选文本上下文菜单调用,则该javascript文件永远不会运行。

然而,可以接近所需的流程。 如果用户在Safari中选择一些文本,然后不是在上下文菜单中点击“共享”,而是点击Safari UI底部的共享图标,则NSItemProvider以plist形式返回,并运行NSExtensionJavaScriptPreprocessingFile。 我的javascript文件如下:

var Share = function() {};

Share.prototype = {
  run: function(arguments) {
    arguments.completionFunction({"URL": document.URL, "selectedText": document.getSelection().toString()});
  },
  finalize: function(arguments) {
    // alert shared!
  }
};

var ExtensionPreprocessingJS = new Share

这意味着返回给扩展的plist对象中既包含页面的URL,也包含所选文本。
如果一个扩展的唯一目的是分享URL,并且没有URL的纯文本不是一个合理的用例,那么你可能不应该将NSExtensionActivationSupportsText设置为YES。例如,像Pocket这样的应用程序启用了它,但是如果用户在Safari中选择一些文本然后尝试通过上下文菜单进行共享,Pocket无法对只有纯文本而没有页面URL的内容执行任何有意义的操作,因此它只会弹出一个相当晦涩的错误消息。
如果您想查看我的扩展代码,我也发布了它。

以下是有关解决此问题的文档:https://developer.apple.com/documentation/foundation/nsitemprovider/1403900-loaditem - C. Bess
你的示例项目非常有帮助。谢谢。 - Dharmesh Kheni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接