expo-share-intent
A React hook and Expo config plugin that captures shared text, links, images, videos, and files on iOS and Android.
Repository Health
Technical Analysis
expo-share-intent is an Expo native module that lets a React Native app become a share target on iOS and Android, so users can send text, links, images, videos, and files into the app from any other app on the device. It ships both the native glue (a Swift share extension on iOS, intent filters on Android) and an Expo config plugin that generates all of that native configuration automatically during expo prebuild — no manual Xcode target setup or AndroidManifest edits required.
On the JavaScript side, a single useShareIntent hook (or ShareIntentProvider/useShareIntentContext for multi-screen apps) exposes a normalized ShareIntent object with the same shape regardless of which platform delivered it, including extracted web links, file metadata (mime type, size, dimensions, duration), and optional webpage metadata like title and og:image. Configuration options let consumers scope exactly which content types (text, URL, image, video, file) trigger the share target on each platform, and versions are tied explicitly to supported Expo SDK releases.
What You Get
- The
useShareIntenthook, returningshareIntent,hasShareIntent,resetShareIntent, anderrorstate derived from native share events ShareIntentProvideranduseShareIntentContextfor consuming the shared intent from any screen in a multi-provider app- An Expo config plugin that generates the iOS share-extension Xcode target, entitlements, and Android manifest intent filters automatically during
expo prebuild - Automatic web-link extraction from shared plain text, plus optional webpage metadata (title,
og:image) via iOS’sNSExtensionActivationSupportsWebPageWithMaxCountand a configurablepreprocessorInjectJS - Fine-grained content-type configuration (
iosActivationRules,androidIntentFilters,androidMultiIntentFilters) to control which MIME types are shareable per platform - AppState-aware behavior that resets the current share intent when the app is backgrounded, avoiding stale re-shares on the next foreground
Common Use Cases
- Building a “read later”/bookmarking app that accepts links shared from any browser or app
- Building a share target for photos and videos, such as a photo organizer or social cross-poster
- Document-intake apps that accept files shared from Files/Google Drive for OCR, storage, or processing
- Apps built with Expo Router or React Navigation that need consistent share-target behavior across iOS and Android without native code
Under The Hood
Architecture
The package splits cleanly into three layers: a thin JS/TS public API (src/index.ts re-exporting useShareIntent, ShareIntentProvider/useShareIntentContext, and utility parsers), a native-module bridge (src/ExpoShareIntentModule.ts, using requireOptionalNativeModule from expo-modules-core to load the platform implementation and gracefully return undefined when unavailable, e.g. on web or in Expo Go), and platform-native code (ios/ExpoShareIntentModule.swift plus android/.../ExpoShareIntentModule.kt, ExpoShareIntentSingleton.kt, and ExpoShareIntentReactActivityLifecycleListener.kt) that captures OS share events and emits onChange/onError/onStateChange events back to JS. A separate plugin/ TypeScript project is an Expo config plugin invoked at expo prebuild time; it composes focused mods (withIosShareExtensionConfig, withIosShareExtensionXcodeTarget, withIosAppEntitlements, withIosAppInfoPlist, writeIosShareExtensionFiles, withAndroidIntentFilters, withAndroidMainActivityAttributes) to write the native share-extension target and intent filters directly into the generated native projects. State flows one way: native share event, to a native module event emitter, to useShareIntent’s onChange listener, to parseShareIntent in utils.ts normalizing the iOS JSON-string payload or the Android object payload into one ShareIntent shape, to React state, to the consumer via hook or context. Every consumer is affected identically by that single normalization function, which is a real cross-cutting risk given there’s no test suite to catch a regression in it before a published release.
Tech Stack
TypeScript throughout, targeting Expo SDK 57 (peer-depending on expo: "^57", with react/react-native left as wildcards to track the host app), built with the standard expo-module-scripts/expo-module CLI into CommonJS output under build/ and plugin/build/. Runtime dependencies are minimal and Expo-native: @expo/config-plugins for the config-plugin composition, plus expo-constants and expo-linking for scheme and deep-link resolution. Native code is Swift for the iOS share extension and Kotlin for Android, both built against the Expo Modules Core API (NativeModule, requireOptionalNativeModule). Tooling includes ESLint 8 with Expo’s config, Prettier, TypeScript, and release-it with conventional-changelog for releases; CI builds the plugin, then lints, prebuilds, and tests three separate example apps (basic, Expo Router, React Navigation) on every pull request.
Code Quality
No dedicated unit-test files exist in the published source (src/ or plugin/src/); the yarn test steps in CI run inside the three example apps and primarily exercise the config plugin’s expo prebuild output rather than unit-testing parseShareIntent or the hook’s state machine directly. Error handling is present but soft: JSON parsing is wrapped in try/catch with a fallback default and a debug log, and parse failures in the hook surface through an error string state, while native-module absence is handled via optional chaining rather than a typed error. Naming is consistent and descriptive, and the exported TypeScript types (ShareIntent, AndroidShareIntent, IosShareIntent) are explicit. ESLint, Prettier, and a CI lint step keep style consistent, but the absence of unit coverage for the core parsing logic is a real gap for a library other apps depend on for correctness.
API Design
The public surface is intentionally small and idiomatic for React: one hook with sensible defaults, or a provider/context pair for multi-screen apps, mirroring familiar context-provider conventions. Getting started requires zero native code — a single config-plugin entry in app.json generates the iOS extension target and Android manifest filters, followed by expo prebuild and a dev-client build (Expo Go is explicitly unsupported, and the README calls this out directly). The configuration surface is documented in one README table with defaults spelled out per option, and separate example apps demonstrate Expo Router and React Navigation integration, addressing real gotchas like deep-link handling on layout mount. The only friction is that some of these integration patterns require reading a fairly long troubleshooting/FAQ section to get right.
Used by 3 apps in this directory
Karakeep
Bookmarks Archiving
Self-hosted bookmark manager that captures links, notes, images, and PDFs with AI tagging, full-text search, and automatic archiving.
Linkwarden
Bookmarks Archiving · Knowledge Management
Self-hosted collaborative bookmark manager that captures full-page archives, enables annotation, and keeps your knowledge accessible forever.
Papra
Bookmarks Archiving
Self-hosted document archiving with email ingestion, OCR full-text search, and pluggable storage — store once, find anything.