This is documentation for the next SDK version. For up-to-date documentation, see the latest version (SDK 54).
Expo Sharing
A library that provides functionality for sharing and receiving data from other apps.
expo-sharing allows you to share files directly with other compatible applications and to receive compatible data shared from other apps.
Sharing limitations on web
expo-sharingfor web is built on top of the Web Share API, which still has very limited browser support. Be sure to check that the API can be used before calling it by usingSharing.isAvailableAsync().- HTTPS required on web: The Web Share API is only available on web when the page is served over https. Run your app with
npx expo start --tunnelto enable it. - No local file sharing on web: Sharing local files by URI works on Android and iOS, but not on web. You cannot share local files on web by URI — you will need to upload them somewhere and share that URI.
Installation
- npx expo install expo-sharingIf you are installing this in an existing React Native app, make sure to install expo in your project.
Configuration in app config
You can configure expo-sharing using its built-in config plugin if you use config plugins in your project (Continuous Native Generation (CNG)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library.
Example app.json with config plugin
The following example shows a configuration that allows sharing a single or multiple images on Android and iOS:
{ "expo": { "plugins": [ [ "expo-sharing", { "ios": { "enabled": true, "activationRule": { "supportsImageWithMaxCount": 5 } }, "android": { "enabled": true, "singleShareMimeTypes": ["image/*"], "multipleShareMimeTypes": ["image/*"] } } ] ] } }
Configurable properties
| Name | Default | Description |
|---|---|---|
ios.enabled | false | A boolean value to enable the iOS Share Extension. If |
ios.extensionBundleIdentifier | {appBundleIdentifier}.ShareExtension | The bundle identifier for the iOS Share Extension. |
ios.appGroupId | group.{appBundleIdentifier} | The App Group ID to use for sharing data between the app and the extension. |
ios.activationRule | {} | Configuration for the |
android.enabled | false | A boolean value to enable Android share intent handling. If |
android.singleShareMimeTypes | [] | An array of MIME types to accept for single file sharing (using |
android.multipleShareMimeTypes | [] | An array of MIME types to accept for multiple file sharing (using |
Sharing to your app from other apps
Note: This functionality is currently experimental. On iOS the share extension opens the main target, instead of processing the share in a sharingViewController, which is not officially supported by Apple and may stop working in a future iOS release.
When an app user shares content with your app, the operating system launches your app (also known as the process of bringing it to the foreground). To process this action, you need to configure your navigation to handle the incoming deep link.
Expo Router
If you are using Expo Router, you can use the +native-intent.ts file to handle the incoming share intent. This allows you to inspect the incoming path and redirect to a specific route.
import { getSharedPayloads } from 'expo-sharing'; export async function redirectSystemPath({ path, initial }: { path: string; initial: boolean }) { try { // Check if the URL is from the share extension/intent if (new URL(path).hostname === 'expo-sharing') { return '/handle-share'; } return path; } catch { // Fallback to the root path on error return '/'; } }
React Navigation
If you are using React Navigation, you can use the linking prop to intercept the deep link. You should check if the incoming URL hostname matches the expo-sharing scheme and redirect the user to a specific handler screen.
import * as Linking from 'expo-linking'; import { createStaticNavigation } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; const RootStack = createNativeStackNavigator({ screens: { // Other screens HandleShare: { screen: HandleShare, linking: { path: '/handle-share', }, }, }, }); const Navigation = createStaticNavigation(RootStack); function processUrl(url: string | null) { if (!url) return null; // The path to your share handler screen const handlerUrl = Linking.createURL('/handle-share'); // Check if the URL is from the share extension/intent if (new URL(url).hostname === 'expo-sharing') { return handlerUrl; } return url; } export default function App() { return ( <Navigation // The rest of your navigation config linking={{ prefixes: [Linking.createURL('/')], async getInitialURL() { const initialUrl = await Linking.getInitialURL(); return processUrl(initialUrl); }, subscribe(listener) { const linkingSubscription = Linking.addEventListener('url', ({ url }) => { const processedUrl = processUrl(url) ?? url; listener(processedUrl); }); return () => { linkingSubscription.remove(); }; }, }} /> ); }
No navigation library
If you are creating a basic app without a navigation library, your main screen is the handler screen. You can move on to the next section.
Displaying shared content
Once you have redirected the user to a handler screen, you can use the useIncomingShare hook to access and display the shared data.
The following example shows a screen that displays shared images:
import { Image } from 'expo-image'; import { useIncomingShare } from 'expo-sharing'; import { View, StyleSheet, ActivityIndicator } from 'react-native'; export default function ShareReceived() { const { resolvedSharedPayloads, isResolving } = useIncomingShare(); if (isResolving) { return ( <View style={styles.container}> <ActivityIndicator size="large" /> </View> ); } return ( <View style={styles.container}> {resolvedSharedPayloads.map((payload, index) => { if (payload.contentType === 'image') { return <Image source={{ uri: payload.contentUri }} style={styles.image} key={index} />; } return null; })} </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'white', }, image: { width: 300, height: 300, marginBottom: 20, borderRadius: 10, }, });
API
import * as Sharing from 'expo-sharing';
Methods
Determine if the sharing API can be used in this app.
Promise<boolean>A promise that fulfills with true if the sharing API can be used, and false otherwise.
| Parameter | Type | Description |
|---|---|---|
| url | string | Local file URL to share. |
| options(optional) | SharingOptions | A map of share options. Default: {} |
Opens action sheet to share file to different applications which can handle this type of file.
Promise<void>Types
| Property | Type | Description |
|---|---|---|
| anchor(optional) | {
height: number,
width: number,
x: number,
y: number
} | Only for: iOS set the anchor point for iPad |
| dialogTitle(optional) | string | Only for: Android Web Sets share dialog title. |
| mimeType(optional) | string | Only for: Android Sets |
| UTI(optional) | string |