Розробка розширення Share Sheet для iOS
Share Sheet Extension (тип NSExtensionPointIdentifier: com.apple.share-services) з'являється в системному шер-меню iOS, коли користувач натискає «Поділитися» в Safari, Фото, Файлах або будь-якому іншому додатку. Це дозволяє прийняти контент напряму — URL, зображення, файл — без перемикання між додатками.
NSItemProvider — серце Share Extension
Вхідний контент приходить через extensionContext?.inputItems як масив NSExtensionItem. Кожна містить attachments: [NSItemProvider]. Потрібно перевірити hasItemConformingToTypeIdentifier для потрібного UTI й завантажити дані через loadItem(forTypeIdentifier:options:completionHandler:).
Це асинхронно. І ось де починаються проблеми: розробники часто завантажують дані в viewDidLoad(), не чекаючи completion, й намагаються використовувати результат синхронно. Розширення крашиться або показує порожні дані.
Правильний підхід для завантаження URL з Safari:
guard let item = extensionContext?.inputItems.first as? NSExtensionItem,
let provider = item.attachments?.first,
provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) else { return }
provider.loadItem(forTypeIdentifier: UTType.url.identifier) { [weak self] url, error in
DispatchQueue.main.async {
self?.receivedURL = url as? URL
self?.updateUI()
}
}
Підтримка кількох UTI. Користувач може вибрати кілька файлів. NSExtensionItem може містити кілька attachments. Переглядаємо всі, перевіряємо кожна через hasItemConformingToTypeIdentifier. Не забуваємо про kUTTypeFileURL vs kUTTypeURL — це різні типи.
Info.plist: NSExtensionActivationRule
Це правило визначає, коли ваше розширення з'являється в шер-меню. Погана настройка — розширення з'являється везде, де не потрібно, і дратує користувачів.
Базове правило через NSExtensionActivationRule словник:
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key><integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key><integer>5</integer>
Для складної логіки — NSPredicate рядок у NSExtensionActivationRule. Наприклад, показувати тільки для PDF файлів: SUBQUERY(extensionItems, $item, SUBQUERY($item.attachments, $att, $att.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf").@count >= 1).@count >= 1.
App Group та передача даних в основне додаток
Share Extension живе в окремому процесі. Дані з розширення не потрапляють в основний додаток автоматично.
Схема: розширення зберігає дані в App Group container (UserDefaults(suiteName:) або файл у containerURL), основний додаток при наступному запуску читає з того ж місця. Для негайної обробки — відкриваємо основний додаток через extensionContext?.open(URL(string: "yourapp://share-received")!). Але це закриває Share Sheet і переключає користувача — не завжди бажано.
З iOS 16 можна використовувати SwiftUI у Share Extension через ShareViewController на основі UIHostingController. Але UIHostingController в Extension ведеться інакше: не підтримує @Environment(\.dismiss) для закриття через extensionContext?.completeRequest(returningItems:). Закриття тільки через extensionContext.
Типова структура роботи
Аудит вхідних типів даних, які потрібно прийняти. Настройка NSExtensionActivationRule. Розробка UI розширення (компактний — максимум третина екрана). Інтеграція через App Group. Обробка відміни (didSelectCancel) та завершення (didSelectPost).
Розклад
Просте Share Extension (прийняти URL або зображення, показати форму): 2–4 тижні. Розширення зі складною логікою, кількома типами файлів, синхронізацією з сервером: 4–7 тижнів. Вартість розраховується після аналізу типів контенту та вимог до UI.







