Что я хочу

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

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

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

Я сделал расширение 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?

15
sbichenko 27 Май 2017 в 18:47

2 ответа

Лучший ответ

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

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

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

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

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

3
apb 27 Ноя 2017 в 19:55

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

9
Justin Anderson 19 Окт 2017 в 13:45