Custom Share Sheet Extension Development for iOS
Imagine: a user selects 10 images in Photos, taps "Share" — and your app must accept them all without crashing. If processing is synchronous in viewDidLoad(), the app crashes with NSInternalInconsistencyException. We develop Share Sheet extensions from scratch or integrate into an existing project. Our solution handles URLs, images, text, and files — up to 50 MB at once — passing them to the main app via App Group. Over 5+ years, we've shipped 30+ extensions that passed App Review on the first try. We'll evaluate your project in 1 business day — get in touch.
A Share Sheet Extension is a system element that appears when tapping "Share" in any iOS app: Safari, Photos, Files. The extension type is specified in NSExtensionPointIdentifier: com.apple.share-services. Without proper configuration, the user sees an empty screen or a crash. We use proven approaches: asynchronous content loading via NSItemProvider, careful handling of NSExtensionActivationRule, and reliable data transfer. We guarantee compatibility with the latest iOS versions and full compliance with App Store Review Guidelines.
What problems does a Share Extension solve?
A Share Extension solves three key tasks:
- Receiving content from other apps (URLs, images, files) without crashes.
- Processing large volumes of data (up to 50 MB) without interface freezes.
- Transferring data to the main app via App Group while preserving context.
Typical beginner mistakes: synchronous loading in viewDidLoad, ignoring NSExtensionActivationRule, neglecting to process multiple NSItemProvider instances. Our engineers, with 30+ projects under their belt, have developed an algorithm that eliminates these issues.
How to handle multiple content types?
Users can select multiple files. NSExtensionItem may contain several attachments. Iterate over all, check each via hasItemConformingToTypeIdentifier. Distinguish between kUTTypeFileURL and kUTTypeURL — they are different UTIs.
| UTI | Content Type | Example Check |
|---|---|---|
| public.url | URL from Safari | hasItemConformingToTypeIdentifier(UTType.url.identifier) |
| public.image | Image | hasItemConformingToTypeIdentifier(UTType.image.identifier) |
| public.plain-text | Text | hasItemConformingToTypeIdentifier(UTType.plainText.identifier) |
Example processing for URL and image:
guard let item = extensionContext?.inputItems.first as? NSExtensionItem,
let providers = item.attachments else { return }
for provider in providers {
if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
provider.loadItem(forTypeIdentifier: UTType.url.identifier) { [weak self] url, error in
DispatchQueue.main.async {
self?.receivedURL = url as? URL
self?.updateUI()
}
}
} else if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
provider.loadItem(forTypeIdentifier: UTType.image.identifier) { [weak self] image, error in
DispatchQueue.main.async {
self?.receivedImage = image as? UIImage
self?.updateUI()
}
}
}
}
Important: always use closures and dispatch to the main thread — this prevents crashes when updating the UI.
How to configure NSExtensionActivationRule without errors?
Bad configuration — the extension appears everywhere it's not needed, annoying users. The basic rule is set with a dictionary using keys like NSExtensionActivationSupportsWebURLWithMaxCount. For complex logic, use an NSPredicate string.
| Rule Type | Example | Purpose |
|---|---|---|
| Dictionary | NSExtensionActivationSupportsImageWithMaxCount:5 |
Show for up to 5 images |
| Predicate | SUBQUERY(extensionItems, $item, SUBQUERY($item.attachments, $att, $att.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf").@count >= 1).@count >= 1 |
Only for PDF |
Example full Info.plist
```xmlPredicates are more flexible: they allow checking file UTIs and combining conditions. For content types, it's better to use a predicate — it more accurately filters out unnecessary items.
What is needed for secure data transfer?
A Share Extension lives in a separate process. Data does not automatically reach the main app. Use an App Group container: UserDefaults(suiteName:) or files in containerURL. For immediate processing, use extensionContext?.open(URL(string: "yourapp://share-received")!). But this closes the Share Sheet and switches the user — not always desirable.
With the latest iOS versions, you can use SwiftUI via UIHostingController. However, @Environment(\.dismiss) does not work — closing is only via extensionContext?.completeRequest(returningItems:). SwiftUI reduces UI code volume by 1.5 times compared to UIKit for a typical Share form — speeding up development by 2-3 weeks.
Step-by-step guide: how to create a Share Extension
Here is the algorithm we use:
- Create a new target in Xcode: File → New → Target → Share Extension.
- Configure
NSExtensionActivationRuleinInfo.plistfor your app's content types. - Implement
ShareViewController— inherit fromSLComposeServiceViewControlleror create a custom UI in SwiftUI. - Process incoming elements via
NSItemProviderasynchronously. - Transfer data to the main app via App Group or URL scheme.
- Test with real data of large volume and multiple files.
This process, when properly configured, takes from 2 weeks for a basic extension.
What is included in the work
- Audit of content types and extension requirements.
- Architecture design and NSExtensionActivationRule configuration.
- Swift implementation using SwiftUI or UIKit.
- App Group integration for data transfer.
- Testing on devices with different iOS versions, including edge cases.
- Documentation preparation and assistance with App Store publication.
- Post-release support (2 weeks of free improvements).
Comparison: iOS Share Extension vs. third-party SDKs
Some use third-party SDKs for sharing, but a custom extension gives full control over UI and processing. For example, a SwiftUI Share Extension works 2x faster with large files than the built-in Activity View Controller. And configuring NSExtensionActivationRule allows showing the extension only for relevant content — increasing conversion by 30%.
Work process
- Audit: analyze the content types the extension will accept.
- Design: configure NSExtensionActivationRule, design the UI (compact, up to a third of the screen).
- Implementation: write Swift code using SwiftUI or UIKit, integrate App Group.
- Testing: verify on iOS 16 and newer, including edge cases (large files, multiple attachments).
- Deployment: deliver documentation and source code, assist with App Store publication.
Estimated timelines
Simple Share Extension (accept URL or image, show form): 2-4 weeks. Extension with complex processing logic, multiple file types, server synchronization: 4-7 weeks. Cost is calculated after analyzing content types and UI requirements. Get a consultation — we'll evaluate in 1 business day. Order turnkey development and get a solution ready for publication in stores.







