Реалізація Share Extension для обміну даними між додатками
Share Extension—розширення, яке з'являється в системному share sheet при передачі даних з будь-якого іншого додатку. Користувач шарить ссилку з Safari, вибирає ваш додаток у списку—розширення отримує дані та обробляє їх. Механізм відрізняється для iOS та Android, у кожного свої нюанси з передачею даних між додатками.
iOS Share Extension
Точка входу та обробка даних
Share Extension—це NSExtension з NSExtensionPointIdentifier: com.apple.share-services. Контролер наслідує SLComposeServiceViewController (простий інтерфейс) або UIViewController (повний контроль). Для нестандартного UI—тільки UIViewController.
Вхідні дані приходять через extensionContext.inputItems. Кожен NSExtensionItem містить масив NSItemProvider. Потрібно перевіряти доступні типи:
guard let extensionItems = extensionContext?.inputItems as? [NSExtensionItem] else { return }
for item in extensionItems {
for provider in item.attachments ?? [] {
if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
provider.loadItem(forTypeIdentifier: UTType.url.identifier) { data, error in
if let url = data as? URL {
self.handleSharedURL(url)
}
}
} else if provider.hasItemConformingToTypeIdentifier(UTType.plainText.identifier) {
provider.loadItem(forTypeIdentifier: UTType.plainText.identifier) { data, error in
if let text = data as? String {
self.handleSharedText(text)
}
}
}
}
}
Передача даних в основний додаток
Share Extension працює в окремому процесі. Прямого вызова методів основного додатку немає. Два варіанти:
App Groups + UserDefaults/CoreData. Пишемо дані в shared container з розширення, основний додаток читає при наступному запуску:
let defaults = UserDefaults(suiteName: "group.com.company.app")
defaults?.set(sharedData, forKey: "pendingShare")
defaults?.synchronize()
URL Scheme. Після збереження даних відкриваємо основний додаток: extensionContext?.open(URL(string: "myapp://share?id=\(savedId)")!). Працює, але open(_:completionHandler:) з розширення—не гарантований, Apple не рекомендує як основний механізм.
Найчастіша помилка: розширення пишет у UserDefaults.standard замість App Group suite. Основний додаток це не читает—різні sandbox'и. Дані теряються без помилок.
NSExtensionActivationRule
Контролює, для яких типів контенту розширення з'являється в share sheet. Через NSExtensionActivationRule в Info.plist або через NSPredicate:
<key>NSExtensionActivationRule</key>
<string>SUBQUERY(extensionItems, $item,
SUBQUERY($item.attachments, $attachment,
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text"
).@count >= 1
).@count >= 1</string>
Неправильний предикат—розширення або не з'являється взагалі, або з'являється везде (марно).
Android Share Target
На Android механізм інший: intent з ACTION_SEND або ACTION_SEND_MULTIPLE. Додаток об'являє себе одержувачем в маніфесті:
<activity android:name=".ShareTargetActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
Отримуємо дані в активності:
if (intent?.action == Intent.ACTION_SEND) {
when {
intent.type?.startsWith("text/") == true -> {
val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
}
intent.type?.startsWith("image/") == true -> {
val imageUri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
}
}
}
Android 12+ додав Sharing Shortcuts (ShortcutManagerCompat)—прямий шаринг конкретному контакту або чату внутрішньо додатку, без проміжного екрану.
Тривалість реалізації: 2–4 дні з урахуванням обох платформ, обробки різних типів даних та App Groups. Вартість розраховується індивідуально.







