Implementing Share Extension for Cross-App Data Sharing
Share Extension appears in the system share sheet when transmitting data from any other app. User shares a link from Safari, selects your app in the list—extension gets data and processes it. Mechanism differs for iOS and Android, each with nuances for inter-app data passing.
iOS Share Extension
Entry Point and Data Processing
Share Extension is an NSExtension with NSExtensionPointIdentifier: com.apple.share-services. Controller inherits SLComposeServiceViewController (simple interface) or UIViewController (full control). For non-standard UI—only UIViewController.
Incoming data comes via extensionContext.inputItems. Each NSExtensionItem contains array of NSItemProvider. Check available types:
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)
}
}
}
}
}
Passing Data to Main App
Share Extension runs in separate process. No direct method calls to main app. Two options:
App Groups + UserDefaults/CoreData. Write data from extension to shared container, main app reads on next launch:
let defaults = UserDefaults(suiteName: "group.com.company.app")
defaults?.set(sharedData, forKey: "pendingShare")
defaults?.synchronize()
URL Scheme. After saving data, open main app: extensionContext?.open(URL(string: "myapp://share?id=\(savedId)")!). Works but open(_:completionHandler:) from extension isn't guaranteed, Apple doesn't recommend as primary mechanism.
Most common error: extension writes to UserDefaults.standard instead of App Group suite. Main app doesn't read—different sandboxes. Data lost silently.
NSExtensionActivationRule
Controls which content types activate extension in share sheet. Via NSExtensionActivationRule in Info.plist or 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>
Wrong predicate—extension either doesn't appear or appears everywhere (useless).
Android Share Target
Different mechanism: intent with ACTION_SEND or ACTION_SEND_MULTIPLE. App declares itself as receiver in manifest:
<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>
Receive data in 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+ added Sharing Shortcuts (ShortcutManagerCompat)—direct share to specific contact or chat in app, no intermediate screen.
Timeline: 2–4 days accounting for both platforms, multiple data types, App Groups. Cost calculated individually.







