Expo 分享
一个提供与其他应用共享和接收数据功能的库。
expo-sharing 允许你直接与其他兼容的应用共享文件,并接收来自其他应用共享的兼容数据。
网络上的共享限制
🌐 Sharing limitations on web
expo-sharing网页版是基于 Web Share API 构建的,而该 API 仍然只有非常有限的浏览器支持。在调用它之前,请务必使用Sharing.isAvailableAsync()检查该 API 是否可以使用。- 网页需要 HTTPS:只有在通过 HTTPS 提供页面时,Web Share API 才能在网页上使用。使用
npx expo start --tunnel运行你的应用以启用它。 - 网页上无法共享本地文件:通过 URI 共享本地文件在 Android 和 iOS 上可行,但在网页上不可行。你不能在网页上通过 URI 共享本地文件——你需要先将文件上传到某个地方,然后共享该 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
如果你在项目中使用配置插件(连续原生生成 (CNG)),可以使用其内置的 配置插件 来配置 expo-sharing。该插件允许你配置无法在运行时设置并且需要构建新的应用二进制文件才能生效的各种属性。如果你的应用不使用 CNG,那么你需要手动配置该库。
🌐 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
以下示例展示了一个配置,该配置允许在 Android 和 iOS 上共享一张或多张图片:
🌐 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
重要 注意:此功能目前处于实验阶段。在 iOS 上,共享扩展则会打开主目标,而不是在共享
ViewController中处理分享,这在苹果官方并不支持,并且在未来的 iOS 版本中可能会停止工作。
当应用用户与你的应用共享内容时,操作系统会启动你的应用(也称为将应用调到前台的过程)。要处理此操作,你需要配置导航以处理传入的深度链接。
🌐 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 路由
🌐 Expo Router
如果你正在使用 Expo Router,你可以使用 +native-intent.ts 文件来处理传入的共享意图。这允许你检查传入的路径并重定向到特定路由。
🌐 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 导航
🌐 React Navigation
如果你正在使用 React Navigation,你可以使用 linking 属性来拦截深度链接。你应该检查传入的 URL 主机名是否与 expo-sharing 方案匹配,并将用户重定向到特定的处理屏幕。
🌐 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
一旦你将用户重定向到处理程序屏幕,就可以使用 useIncomingShare 钩子来访问和显示共享数据。
🌐 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';
Hooks
Hook, which returns the data shared with the application and updates the data if the shared payload has changed.
UseIncomingShareResultMethods
Returns resolved data shared with the app. Compared to data returned from getSharedPayloads contains additional
information useful for reading and displaying the data. For example, when a web URL is shared with the app,
a resolved payload will contain additional information about the URL contents.
Depending on what has been shared, this method may require a network connection to resolve content details.
Promise<ResolvedSharePayload[]>Returns raw data shared with the app. Returns an empty array if no data has been shared with the app.
SharePayload[]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
Describes a configuration for data types that are possible to share in the application on iOS.
| Property | Type | Description |
|---|---|---|
| supportsAttachmentsWithMaxCount(optional) | number | Determines a maximum number of attachments that can be shared with the app.
When Default: 0 |
| supportsFileWithMaxCount(optional) | number | Determines a maximum number of files that can be shared with the app.
When Default: 0 |
| supportsImageWithMaxCount(optional) | number | Determines a maximum number of images that can be shared with the app.
When Default: 0 |
| supportsMovieWithMaxCount(optional) | number | Determines a maximum number of videos that can be shared with the app.
When Default: 0 |
| supportsText(optional) | boolean | Whether the app should accept shared text. Default: false |
| supportsWebPageWithMaxCount(optional) | number | Determines a maximum number of webpages that can be shared with the app.
When Default: 0 |
| supportsWebUrlWithMaxCount(optional) | number | Determines a maximum number of web URLs that can be shared with the app.
When Default: 0 |
Type: SharePayload extended by:
| Property | Type | Description |
|---|---|---|
| contentMimeType | string | null | Mime type of the content accessible via the |
| contentSize | number | null | Size of the content accessible via the |
| contentType | ContentType | null | Type of the content accessible via the |
| contentUri | string | null | URI which can be used to access the shared content. When resolving contents of a URL with redirects, contains the redirect target URI.
Null when resolving a |
| originalName | string | null | If applicable, value of the |
Literal Type: string
Describes the resolved content type.
Acceptable values are: 'text' | 'audio' | 'image' | 'video' | 'file' | 'website'
Literal Type: union
Represents a payload shared with the app, with additional information about the shared contents.
Acceptable values are: UriBasedResolvedSharePayload | TextBasedResolvedSharePayload
Represents raw data shared with the app.
| Property | Type | Description |
|---|---|---|
| mimeType(optional) | string | The MIME type of the contents of the Default: 'text/plain' |
| shareType(optional) | ShareType | The type of the shared content. Default: 'text' |
| value(optional) | string | The primary value of the content.
Default: "" |
Literal Type: string
Determines the type of content being shared.
text: Plain text content.url: A specific URL.audio: An audio file.image: An image file.video: A video file.file: A generic file.
Acceptable values are: 'text' | 'url' | 'audio' | 'image' | 'video' | 'file'
| Property | Type | Description |
|---|---|---|
| anchor(optional) | {
height: number,
width: number,
x: number,
y: number
} | Only for: iOS Sets 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 |
Represents a resolved payload, where a text was shared with the app.
Type: BaseResolvedSharePayload extended by:
| Property | Type | Description |
|---|---|---|
| contentType(optional) | 'text' | - |
Represents a resolved payload, for which the data can be accessed through a URI.
Type: BaseResolvedSharePayload extended by:
| Property | Type | Description |
|---|---|---|
| contentType | 'audio' | 'file' | 'video' | 'image' | 'website' | - |
| contentUri | string | - |
Object returned by useIncomingShare hook containing information about data shared with the app.
| Property | Type | Description |
|---|---|---|
| clearSharedPayloads | () => void | Clears payloads shared with the app. |
| error | Error | null | Contains an error encountered while resolving the shared payload. Null on success. |
| isResolving | boolean | Boolean indicating whether the current shared payloads are being resolved. |
| refreshSharePayloads | () => void | Forces a refresh of the shared payloads. |
| resolvedSharedPayloads | ResolvedSharePayload[] | Contains an array of resolved payloads shared with the app. Returns an empty array if the shared payloads are being resolved or if the resolving has failed. |
| sharedPayloads | SharePayload[] | Returns unresolved payloads shared with the app. Synchronous and available immediately after creating the hook. |