Building Share Extensions with React: Cross-Platform Patterns for Pixel and iPhone Compatibility
Cross-platform patterns to build native-like share extensions with React Native and web fallbacks—practical steps for iOS, Android, and PWA in 2026.
Ship native-like share experiences in 2026: cross-platform share extensions and intent handlers with React Native
Hook: If you’re struggling to build a reliable, cross-platform share flow that feels native on both iPhone and Android — and want a progressive web fallback that still “just works” — you’re in the right place. This guide walks through practical patterns for building share extensions, intent handlers, and web fallbacks using React Native (and lightweight native code) to emulate AirDrop-style interop across devices — including recent Pixel 9 and iOS developments from late 2025–early 2026.
The problem we solve
Teams shipping React Native apps often hit three hard problems when implementing share/receive flows:
- How to receive shared content from the OS without loading a full RN bundle inside an extension
- How to route a share intent into the main app in a robust, secure way (deep links, App Links, Universal Links)
- How to provide a web fallback (PWA) that can accept shared content or initiate peer flows when native APIs aren’t available
We’ll address each with concrete patterns, code, and trade-offs.
Why 2026 matters: recent platform trends
Two platform moves shaped this guide:
- Google’s work to make Pixel devices interoperable with Apple’s AirDrop model (notably in Pixel 9 series chatter in early 2026) increases the need for apps to support cross-OS peer transfers and intent interoperability. (See reporting from January 2026 documenting Pixel changes.)
- Browsers and PWAs have matured their Web Share Target and client-side WebRTC flows; Progressive Web Apps can now accept shared data in many contexts, making a web fallback viable for many apps.
“Interoperability is no longer optional — recent device updates (Pixel 9) and web API maturity mean your app should gracefully handle both native and web share flows.”
High-level architecture
We’ll use a three-layer approach:
- Minimal native receivers — tiny OS-specific handlers that accept shared data and persist it to a shared container (iOS App Group / Android file) or start the app via a deep link.
- Main React Native app — the full RN bundle that reads the persisted payload (or receives an intent payload) and presents the native-like UI for accepting/importing the item.
- Web fallback — PWA using the Web Share Target API and WebRTC-based peer flows for AirDrop-like transfers where available.
Design patterns and trade-offs
Keep share receivers tiny
Share extensions and Android share targets run under strict memory/time budgets. Don’t load your full RN bundle in the extension. Instead:
- Persist shared data to an App Group (iOS) or scoped storage/shared file (Android)
- Signal the main app via a deep link or notification
- Perform minimal processing in the extension — save file metadata, small thumbnails, and defer heavy parsing to the main app
Use App Groups and shared storage
Share extensions and the main app commonly communicate via shared containers. On iOS, configure an App Group. On Android, write to a private external file or use ContentProvider with temporary grant URIs.
Prefer deep links for immediate UX
When the user expects to continue in your app (e.g., finish sending, edit, annotate), launch the main app with a deep link containing a stable ID or pointer to the shared file in the shared container. Use Universal Links (iOS) and App Links (Android) so receiving the link is reliable.
Implementation: iOS Share Extension (React Native app)
We’ll outline a minimal Swift share extension that saves content to an App Group, then opens the main app with a URL scheme to hand off full handling to React Native.
1. Create a Share Extension target
- File → New → Target → Share Extension.
- Set the extension’s bundle ID and enable the same App Group as the main app.
2. Info.plist: supported data types
<key>NSExtension>
<dict>
<key>NSExtensionAttributes>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount>1</key>
</dict>
<key>NSExtensionPointIdentifier>com.apple.share-services</key>
</dict>
</key>
3. ShareViewController (Swift) — save to App Group and open main app
import UIKit
import Social
class ShareViewController: SLComposeServiceViewController {
override func didSelectPost() {
guard let item = extensionContext?.inputItems.first as? NSExtensionItem,
let attachments = item.attachments else { return }
// Save to shared container
let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.your.app")!
let fileURL = groupURL.appendingPathComponent("incoming_\(UUID().uuidString).dat")
attachments[0].loadItem(forTypeIdentifier: "public.data", options: nil) { (data, error) in
if let url = data as? URL {
try? FileManager.default.copyItem(at: url, to: fileURL)
} else if let d = data as? Data {
try? d.write(to: fileURL)
}
// Open main app via URL scheme
let url = URL(string: "yourapp://shared?file=\(fileURL.lastPathComponent)")!
_ = self.extensionContext?.open(url, completionHandler: nil)
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
}
}
}
Notes: Some versions of iOS restrict open URL calls from extensions; if that’s unavailable, save the file and surface an alert asking the user to open the main app. When possible, use Universal Links or NSUserActivity handoff for a better UX.
Implementation: Android Share Target (React Native app)
On Android, register an activity with an intent-filter for ACTION_SEND / ACTION_SEND_MULTIPLE. Keep the activity minimal and forward the payload to your main app via an Intent with extras or stored file path.
1. AndroidManifest.xml
<activity android:name=".ShareReceiverActivity"
android:exported="true"
android:theme="@style/Theme.AppCompat.Translucent">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
2. ShareReceiverActivity (Kotlin)
class ShareReceiverActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = intent
if (intent?.action == Intent.ACTION_SEND) {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
uri?.let {
// Copy into app-private storage and launch MainActivity
val fileName = "incoming_\${UUID.randomUUID()}.dat"
val outFile = File(getExternalFilesDir(null), fileName)
contentResolver.openInputStream(uri).use { input ->
outFile.outputStream().use { output -> input?.copyTo(output) }
}
val launch = Intent(this, MainActivity::class.java)
launch.putExtra("shared_file", outFile.absolutePath)
launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(launch)
}
}
finish()
}
}
React Native side: read the initial intent or the persisted file on app start. Add a small native module or use existing deep link handlers (Linking.getInitialURL plus custom native module for intent extras) to surface the incoming file path to your JS app.
React Native: reading the shared payload
In your RN entry, add logic to check the startup parameters for a shared file pointer. For example:
import { Linking } from 'react-native'
import RNFS from 'react-native-fs'
async function handleIncoming() {
const url = await Linking.getInitialURL()
// parse your custom URL and read file from App Group (iOS) or file path (Android)
}
useEffect(() => { handleIncoming() }, [])
For multi-step flows (e.g., accept file, then show editor), implement a small importer screen that reads the file, validates MIME/type, and provides progress. Defer heavy work into background tasks or the main app process.
AirDrop-style peer transfers: native vs web
AirDrop works at a lower system level using Apple’s peer-to-peer frameworks. Emulating that fully requires native APIs. But there are pragmatic options:
- Use native Nearby / Nearby Share on Android when available (Pixel 9 trend toward better iOS/Android interoperability may add more cross-platform options soon).
- Use MultipeerConnectivity on iOS for local peer-to-peer transfers.
- Fallback to WebRTC data channels in your PWA for peer-to-peer in the browser. Use a lightweight signaling channel (via QR codes or temporary short-lived room on your server) to bootstrap WebRTC.
Example: for cross-OS transfers, implement the following strategy:
- Detect capabilities: is Nearby Share / MultipeerConnectivity available? Use native if yes.
- If not, fall back to WebRTC via PWA: open a web page receiver with a room token encoded in a QR code shared via SMS or link.
- Use small thumbnails and resumable transfer (for big files), and encrypt payloads end-to-end if privacy matters.
Web fallback: Web Share Target + WebRTC
Progressive Web Apps can act as share targets via the Web Share Target API. Add this to your web manifest:
{
"name": "My App",
"short_name": "MyApp",
"start_url": "/?source=share",
"share_target": {
"action": "/share-target",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"title": "title",
"text": "text",
"files": [{ "name": "files", "accept": ["image/*", "video/*", "*/*"] }]
}
}
}
On the /share-target route, read the POST data in a Service Worker-controlled handler and persist to IndexedDB. Then bring the PWA UI forward and let the user accept or forward the file via WebRTC to another peer. For AirDrop-style flow, you can host a temporary STUN/TURN signaling room and use a QR code or deep link to connect the two endpoints.
Deep links, Universal Links, and App Links
Deep linking strategy is essential for reliability:
- Configure Universal Links (iOS) and App Links (Android) for secure, reliable routing. This avoids the “Open app?” confirmation dialogs and provides verified ownership.
- For ad-hoc peer-to-peer flows, produce a one-time link or QR encoded with a secure token and pointer to the shared file (or signaling room).
- Always validate tokens server-side if used, and limit their TTL to reduce risk.
Security, privacy, and UX considerations
- Permissions: request only what you need (file access, network). Explain why in-UX to reduce friction.
- Sanitize file types and scan for potentially dangerous content server-side if you accept uploads.
- Privacy: consider end-to-end encryption for transfers and ephemeral storage (auto-delete after import).
- Small UX touches: show upload progress, allow cancel, show thumbnail and file metadata, and don’t block the extension UI for long tasks.
Testing and validation
Test on real devices. Key checks:
- iOS: test share extensions on device (simulator has limitations). Verify App Group read/write, URL open flow, and Universal Links behavior.
- Android: test on a range of devices including Pixel 9 and Android 13–17. Confirm intent handling from multiple apps (Gallery, Files, Chrome).
- PWA: test Web Share Target across Chromium-based browsers and Safari/others where supported.
- Interoperability: if you target AirDrop-like transfers, validate cross-OS transfers between iPhone and Pixel devices — Pixel 9’s improved interoperability makes this a live scenario in 2026.
Performance and bundle-size tips
- Don’t bundle RN into extensions — keep extensions native and minimal.
- Use Hermes and code-splitting in your main app to keep startup fast after a share opens the app.
- Persist thumbnails only; load heavy assets on-demand and stream large files.
Advanced strategies and future-proofing (2026+)
As device vendors converge on cross-OS file transfer features, design for graceful capability detection and progressive enhancement:
- Feature-detect Nearby / Multipeer / WebRTC and pick the lowest-latency mechanism available.
- Bundle a lightweight native module that exposes capability flags to JS so your RN app chooses flows dynamically.
- Monitor platform updates — e.g., Pixel 9's AirDrop compatibility work means peer flows may become easier for cross-OS transfers; keep your signaling and UX flexible to adopt native APIs when available.
Actionable checklist (copy into your sprint)
- Define supported share MIME types and max file sizes.
- Create minimal iOS Share Extension with App Group write + deep link handoff.
- Add Android Share Receiver Activity that copies file to app storage and launches MainActivity with extras.
- Implement RN importer screen that reads shared files and validates them.
- Implement Web Share Target in PWA manifest and a Service Worker / IndexedDB handoff UI.
- Wire Universal Links / App Links and test across devices (include Pixel 9 and recent iOS builds).
- Document privacy/retention policy for incoming files and implement auto-cleanup.
Real-world example: flow summary
Here’s a typical flow that feels native on iOS and Android and has a PWA fallback:
- User taps share in Photos app and picks “YourApp”.
- OS launches a minimal Share Extension / ShareReceiverActivity.
- The receiver writes file to App Group / app storage and launches the main app via Universal Link or custom URL with a stable token/file ID.
- Main RN app reads the file, shows an import screen, and offers edit/accept. Heavy processing is done in-app, not in the extension.
- If native peer-to-peer is available (Multipeer / Nearby), use that; otherwise fallback to web: send a short-lived link or QR code to pair a PWA receiver via WebRTC.
Key takeaways
- Keep native receivers minimal. Defer heavy work to the main app, use shared storage.
- Leverage deep links and verified links for reliable routing and improved UX.
- PWA fallback using Web Share Target + WebRTC provides broad compatibility where native APIs aren’t available.
- Design for capability detection — the Pixel 9 and platform updates in 2026 make cross-OS flow support increasingly important.
Further reading & next steps
Start by implementing the smallest receiver possible for each platform, then build your RN importer screen and iterate on UX. Monitor OS updates (Pixel interoperability work and Android 17/18 changes) to opportunistically adopt native peer APIs.
Want a starter repo? Clone a minimal sample: native share receiver + RN importer + web manifest for Web Share Target. Use it as a scaffold and plugin your authentication/validation and business logic.
Final call-to-action
If you’re building this today, pick one platform to implement first and get an end-to-end flow working in a single sprint (receiver → shared storage → RN importer → UI). Share your questions or the edge cases you hit — I’ll help you iterate on the pattern for production readiness and for Pixel 9/iOS interop in 2026.
Related Reading
- Dog-Ready Road Trips: Routes, Rental Cars and Overnight Stays Across the UK
- Comfort Cooking for Anxious Nights: Mitski‑Mood Recipes to Soothe and Focus
- Prune Your Clinic’s Tech Stack: A Checklist for Small Health Providers
- How to Build a Hybrid Smart Lighting System for Historic and High-Value Homes
- How Keto Micro‑Popups and Local Testing Define Product Success in 2026
Related Topics
Unknown
Contributor
Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.
Up Next
More stories handpicked for you
From Local to Cloud: Best Practices for Migrating React Apps to Distributed Systems
How AI is Reshaping React: Integration of Generative Models in Development
Building a Resilient Future: Performance Optimization Techniques for React Applications
Vibe Coding and Micro Apps: The Future of Personalized React Development
Leveraging the Power of AI in Testing React Applications: Tools and Techniques
From Our Network
Trending stories across our publication group