Реализация 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. Стоимость рассчитывается индивидуально.







