Расширение общего доступа iOS: получить URL-адрес страницы при совместном использовании через контекстное меню в Safari

Что я хочу

Я пытаюсь добиться следующего пользовательского потока:

  1. Пользователь просматривает веб-страницу в iOS Safari.
  2. Пользователь выбирает некоторый контент (текст и изображения) и ждет появления контекстного меню.
  3. Пользователь выбирает пункт «Поделиться…».
  4. Пользователь выбирает мое расширение приложения в меню общего доступа, которое появляется снизу.
  5. Выбранный контент и URL-адрес веб-страницы передаются на удаленный сервер через вызов HTT.

Что я пробовал

Я сделал расширение Share через Xcode. Вот раздел NSExtension моего info.plist:

<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-адрес веб-страницы.

Мой вопрос

Как я могу получить URL-адрес открытой веб-страницы при использовании расширения «Поделиться» для обмена выбранным контентом через контекстное меню в iOS Safari?


person sbichenko    schedule 27.05.2017    source источник


Ответы (2)


Я провел смущающе большую часть дня, читая документы по этому вопросу и пробуя различные перестановки расширений, поскольку я хотел сделать именно (я думаю) то, что вы пытались сделать.

Я пришел к выводу, что этого точного потока невозможно добиться на iOS. Если пользователь выбирает текст и использует контекстное меню (например, «Копировать», «Поиск», «Поделиться»...), единственное, что ваше расширение когда-либо получит, — это NSItemProvider с выбранным им текстом, т. е. не plist с результатами предварительной обработки javascript. Когда они выбирают «Поделиться» в этом меню, расширение отображается тогда и только тогда, когда у вас есть NSExtensionActivationSupportsText, установленное на YES в файле расширения Info.plist.

Чтобы запустить предварительную обработку JavaScript, в расширении должно быть установлено значение NSExtensionActivationSupportsWebPageWithMaxCount больше 0 в соответствии с документы. Если расширение вызывается через выбранное текстовое контекстное меню, этот файл javascript никогда не запускается.

Однако можно довольно близко подобраться к желаемому потоку. Если пользователь находится в Safari и выбирает некоторый текст, а затем, вместо нажатия «Поделиться» в контекстном меню, нажимает значок «Поделиться» в нижней части пользовательского интерфейса Safari, тогда 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-адреса не является разумным вариантом использования, вам, вероятно, не следует устанавливать NSExtensionActivationSupportsText на YES. Например, в таком приложении, как Pocket, оно включено, но если пользователь выбирает некоторый текст в Safari, а затем пытается поделиться через контекстное меню, Pocket не может сделать ничего значимого, используя только открытый текст и без URL-адреса страницы, поэтому он просто всплывает. довольно загадочное сообщение об ошибке.

Я также опубликовал код своего расширения, если вы хотите взглянуть.

person apb    schedule 27.11.2017
comment
Документы, помогающие преодолеть упомянутую проблему: developer.apple.com/documentation/foundation/ nsitemprovider/ - person C. Bess; 15.08.2019

Свифт 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" можно заменить строкой kUTTypeURL, импортированной из MobileCoreServices.

person Joe    schedule 31.05.2017
comment
Это должен быть принятый ответ, он работает для меня после применения синтаксиса Swfit3: itemProvider.loadItem(forTypeIdentifier: public.url, options: nil, completeHandler: {(url, error) -> Void in - person Yun CHEN; 05.06.2017
comment
@YunCHEN спасибо за совет. Обновлен ответ на Swift 3 - person Joe; 06.06.2017
comment
Обратите внимание, что награда была присуждена автоматически. itemProvider.hasItemConformingToTypeIdentifier("public.url") возвращает false для меня. И extensionContext?.inputItems содержит только один элемент - простое текстовое представление выбора - именно то, что я описал в своем вопросе. - person sbichenko; 18.06.2017
comment
привет, любое решение для docx/pdf? Спасибо - person famfamfam; 27.03.2021