web-dev-qa-db-ja.com

iOS共有拡張機能:Safariのコンテキストメニューを介して共有するときにページのURLを取得します

欲しいもの

私は次のユーザーフローを達成しようとしています:

  1. ユーザーがiOSSafariでWebページを閲覧しています。
  2. ユーザーはいくつかのコンテンツ(テキストと画像)を選択し、コンテキストメニューが表示されるのを待ちます。
  3. ユーザーが「共有...」アイテムを選択します。
  4. ユーザーは、下から表示される共有メニューでアプリ拡張機能を選択します。
  5. 選択したコンテンツとWebページのURLは、HTT呼び出しを介してリモートサーバーと共有されます。

私が試したこと

Xcodeを介してShare拡張機能を作成しました。これが私のinfo.plistNSExtensionセクションです。

<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はいくつかの入力項目を提供し、それを介して選択したコンテンツとWebURLを取得できます。

何がうまくいかない

viewDidLoadメソッドではextensionContext?.inputItemsは、選択したコンテンツのプレーンテキスト表現(画像とテキストを同時に選択した場合でも)という1つのアイテムのみを提供します。プレーンテキストで生活できますが、ウェブページのURLが必要です。

私の質問

IOS Safariのコンテキストメニューを介して選択したコンテンツを共有するために共有拡張機能を使用する場合、開いたWebページのURLを取得するにはどうすればよいですか?

14
sbichenko

私はあなたがやろうとしていたことを正確に(私は思う)やろうとしていたので、これに関するドキュメントを読んで、拡張機能のさまざまな順列を試し、午後の恥ずかしいほど大部分を費やしました。

私は、この正確なフローはiOSでは達成できないと結論付けました。ユーザーがテキストを選択してコンテキストメニュー(つまり、「コピー」、「ルックアップ」、「共有」など)を使用する場合、拡張機能が受け取るのは、テキストを含むNSItemProviderだけです。選択されています。つまり、前処理javascriptの結果を含むplistではありません。そのメニューから[共有]を選択すると、拡張機能のInfo.plistファイルでNSExtensionActivationSupportsTextYESに設定されている場合にのみ、拡張機能が表示されます。

前処理JavaScriptを実行するには、拡張機能でNSExtensionActivationSupportsWebPageWithMaxCountdocs に従って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とselectedTextの両方があることを意味します。

拡張機能の唯一の目的がURLの共有であり、URLのないプレーンテキストが意味のある使用例ではない場合は、NSExtensionActivationSupportsTextYESに設定しないでください。たとえば、Pocketのようなアプリでは有効になっていますが、ユーザーがSafariでテキストを選択し、コンテキストメニューから共有しようとすると、PocketはプレーンテキストだけでページURLがないと意味のあることを何もできないため、ポップするだけです。かなり不可解なエラーメッセージが表示されます。

私は 私の拡張機能のコードを公開しました もご覧になりたい場合は。

2
apb

Swift

次の線に沿って何かを試してください:

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"は、kUTTypeURLからインポートされたMobileCoreServices文字列に置き換えることができます。

8
Joe