Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/achorein/expo-share-intent
🚀 Simple share intent in an Expo Native Module
https://github.com/achorein/expo-share-intent
android expo ios react-native share-extension share-intent
Last synced: 4 days ago
JSON representation
🚀 Simple share intent in an Expo Native Module
- Host: GitHub
- URL: https://github.com/achorein/expo-share-intent
- Owner: achorein
- License: mit
- Created: 2024-02-19T16:51:01.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2024-12-23T08:24:10.000Z (16 days ago)
- Last Synced: 2024-12-28T04:02:33.702Z (11 days ago)
- Topics: android, expo, ios, react-native, share-extension, share-intent
- Language: TypeScript
- Homepage:
- Size: 1.89 MB
- Stars: 245
- Watchers: 7
- Forks: 18
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# Expo Share Intent 🚀
![npm](https://img.shields.io/npm/v/expo-share-intent.svg)
![License](https://img.shields.io/npm/l/expo-share-intent.svg)
![Downloads](https://img.shields.io/npm/dm/expo-share-intent.svg)
![GitHub stars](https://img.shields.io/github/stars/achorein/expo-share-intent.svg)Allow sharing **URL, text, images, videos and files** to your **iOS** and **Android** app, using a simple high-performance native module for Expo (React Native).
> The aim of this project is to have identical behavior between iOS and Android, and so to implement a single logic in the main application. In this way, when sharing data, the user is directly redirected to the main application, which will be responsible to manage the external data.
| iOS | Android |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| ![Simulator Screen Recording - iPhone 15 Pro - 2024-12-11 at 09 09 40](https://github.com/user-attachments/assets/b98d1ec1-8ad3-410f-b09b-14b4dce52260) | ![Simulator Android - expo share intent](https://github.com/user-attachments/assets/d2c38b8f-6ec1-4c62-b7b8-dc13aeea8c93) |## Versioning
Ensure you use versions that work together
| Expo | Supported `expo-share-intent` version |
| ---------- | ------------------------------------- |
| **SDK 52** | 3.0+ |
| **SDK 51** | 2.0+ |
| **SDK 50** | 1.0+ |
| **SDK 49** | 0.2+ |> iOS privacy manifest is available since v1.4.1
## Table of Contents
- [Usage](#usage)
- [Configure Content Types](#customize-content-types-in-appjson)
- [Share Intent content](#share-intent-content)
- [Expo Router](#expo-router)
- [React Navigation](#react-navigation)
- [iOS Custom View](#ios-custom-view-)
- [Troubleshooting / FAQ](#troubleshooting---faq)
- [Support](#support)## Installation
**Install npm package**
```bash
yarn add expo-share-intent
# or
npm install expo-share-intent
```**Requirement: `patch-package`**
For the moment this package need a post-install script
- copy the [xcode patch](https://github.com/achorein/expo-share-intent/blob/main/example/basic/patches/xcode%2B3.0.1.patch) in you `patches` project directory (like example)
- add post-install script to `package.json````json
"scripts": {
...
"postinstall": "patch-package"
},
```- add `patch-package` for auto patching
```bash
yarn add patch-package
```> More info in [#13](https://github.com/achorein/expo-share-intent/issues/13) and [FAQ](https://github.com/achorein/expo-share-intent/edit/main/README.md#config-sync-failed)
**Requirement: `expo-linking`**
Since Expo52, you also need to install `expo-linking` in your app :
```
expo install expo-linking
```**Into your `app.json`:**
- add expo plugin
```json
"plugins": [
"expo-share-intent"
],
```> by default only text and url sharing is activated
- configure a custom URL scheme
```json
"scheme": "my-app"
```> More info here : [Linking to your app](https://docs.expo.dev/guides/linking/#linking-to-your-app)
**Run your app in dev-client**
```
expo prebuild --no-install --clean
expo run:ios
expo run:android
```> We cannot use expo go with this package, more info [here](https://github.com/achorein/expo-share-intent?tab=readme-ov-file#expo-go-)
## Usage
#### Use the hook in your App
Make sure to use the hook in your main `App.tsx` component before any other Provider :
```ts
import { useShareIntent } from "expo-share-intent";const { hasShareIntent, shareIntent, resetShareIntent, error } =
useShareIntent();
```See [App.tsx ](https://github.com/achorein/expo-share-intent/blob/main/example/basic/App.tsx) for more details
#### Use the Provider in your App
When dealing with multiple screens and providers your may use `ShareIntentProvider` and it's specific hook `useShareIntentContext`. Must be in your top component (`App.tsx`) before any other Provider :
```tsx
import { ShareIntentProvider, useShareIntentContext } from "expo-share-intent";const Home = () => {
const { hasShareIntent, shareIntent, resetShareIntent, error } = useShareIntentContext();
return ...
}export default const App = () => {
return (
)
}```
#### Share intent content
```ts
const { shareIntent } = useShareIntent();
```| attribute | description | example |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `shareIntent.text` | raw text from text/weburl (ios) and text/\* (android) | "`some text`", "`http://example.com`", "`Hey, Click on my link : http://example.com/nickname`" |
| `shareIntent.webUrl` | link extracted from raw text | `null`, "`http://example.com`", "`http://example.com/nickname`" |
| `shareIntent.files` | image / movies / audio / files with name, path, mimetype, size (in octets) and image/video dimensions (width/height/duration) | `[{ path: "file:///local/path/filename", mimeType: "image/jpeg", fileName: "originalFilename.jpg", size: 2567402, width: 800, height: 600 }, { path: "file:///local/path/filename", mimeType: "video/mp4", fileName: "originalFilename.mp4", size: 2567402, width: 800, height: 600, duration: 20000 }]` |
| `shareIntent.meta` | meta object which contains extra information about the share intent | `{ title: "My cool blog article", "og:image": "https://.../image.png" }` |
| `shareIntent.meta.title` | optional title property sent by other app (available on Android and when `NSExtensionActivationSupportsWebPageWithMaxCount` is enabled on iOS) | `My cool blog article` |
| `shareIntent.meta.xxx` | list all webpage metadata available in meta tags `` (iOS only, available with `NSExtensionActivationSupportsWebPageWithMaxCount`) | |#### Customize Content Types in `app.json`
Simply choose content types you need :
```json
"plugins": [
[
"expo-share-intent",
{
"iosActivationRules": {
"NSExtensionActivationSupportsWebURLWithMaxCount": 1,
"NSExtensionActivationSupportsWebPageWithMaxCount": 1,
"NSExtensionActivationSupportsImageWithMaxCount": 1,
"NSExtensionActivationSupportsMovieWithMaxCount": 1,
},
"androidIntentFilters": ["text/*", "image/*"]
}
],
],
```| Option | Values |
| ----------------------------- | ------------------- |
| iosActivationRules | Allow **text** sharing with `"NSExtensionActivationSupportsText": true`
**Url** sharing with `"NSExtensionActivationSupportsWebURLWithMaxCount": 1` and `"NSExtensionActivationSupportsWebPageWithMaxCount": 1`
**Images** sharing with `"NSExtensionActivationSupportsImageWithMaxCount": 1`
**Videos** sharing with `"NSExtensionActivationSupportsMovieWithMaxCount": 1`
**Files and audio** sharing with `"NSExtensionActivationSupportsFileWithMaxCount": 1`
_default value_: `{ "NSExtensionActivationSupportsWebURLWithMaxCount": 1, "NSExtensionActivationSupportsWebPageWithMaxCount": 1 }"`
_More info in apple developper doc [here](https://developer.apple.com/documentation/bundleresources/information_property_list/nsextension/nsextensionattributes/nsextensionactivationrule)_
you can also provide a custom query (ex: `"iosActivationRules": "SUBQUERY (...)"`) |
| iosShareExtensionName | override `CFBundleDisplayName` the extension `info.plist`, also used as extension name for xcode target (ex: `ExpoShareIntent Example Extension`, folder: `ExpoShareIntentExampleExtension`) |
| iosAppGroupIdentifier | custom application group identifier for `com.apple.security.application-groups` (ex: `group.custom.exposhareintent.example`) cf [#94](https://github.com/achorein/expo-share-intent/issues/94) |
| androidIntentFilters | **one file sharing** array of MIME types :`"text/*"` / `"image/*"` / `"video/*"` / `"*/*"`
_default value_: `["text/*"]` (text and url) |
| androidMultiIntentFilters | **multiple files sharing** array of MIME types : `"image/*"` / `"video/*"` / `"audio/*`/ `"*/*"`
_default value_: `[]` |
| androidMainActivityAttributes | _default value_: `{ "android:launchMode": "singleTask" }` |
| preprocessorInjectJS | Add javascript to webpage preprocessor before the share extension is called (cf [Accessing a Webpage](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW12)).
Example:preprocessorInjectJS: "metas['og\\:image'] = metas['og\\:image'] || document.querySelector('img#seo-image')?.getAttribute('src')"
|
| disableAndroid | Disable the android share intent. Useful if you want to use a custom implementation. _default value_: `false` |
| disableIOS | Disable the ios share extension. Useful if you want to use a custom implementation (ex: [iOS Custom View](#ios-custom-view-)). _default value_: `false` |### Expo Router
With `expo-router` you need to handle loading elements on [Layout](https://docs.expo.dev/routing/appearance/). It's the only way to call the native module using deeplink url.
An example is available with Expo Router v3 in [example/expo-router](https://github.com/achorein/expo-share-intent/tree/main/example/expo-router/)
### React Navigation
If you want to handle share intent with React Navigation v6, you must use the `ShareIntentProvider` and add a custom mapping function in your linking configuration.
Take a look at the example in [example/react-navigation](https://github.com/achorein/expo-share-intent/tree/main/example/react-navigation/).
## Troubleshooting - FAQ
### iOS Extension Target
When building on EAS you should only have **one** extension target (during credentials setting process).
To avoid expo auto configuration to add an experimental "appExtensions" to `app.json` you must manually configure your eas build (projectId in `app.json` and a `eas.json` file).
More details in [#1](https://github.com/achorein/expo-share-intent-demo/issues/1)
### Config sync failed
```bash
$ yarn prebuild
â § Running prebuild[expo-share-intent] add ios share extension (scheme:exposhareintentexample appIdentifier:expo.modules.exposhareintent.example)
â ‡ Running prebuild[expo-share-intent] add android filters text/* image/*
✖ Config sync failed
TypeError: [ios.xcodeproj]: withIosXcodeprojBaseMod: Cannot read properties of null (reading 'path')
```This package need a post-install script, see `xcode+3.0.1.patch` file in [example/patches](https://github.com/achorein/expo-share-intent/tree/main/example/basic/patches) (more info [#31](https://github.com/achorein/expo-share-intent-demo/issues/31) and [#13](https://github.com/achorein/expo-share-intent/issues/13))
### Expo Go ?
We are using native code to make share intent works, so we can't use Expo Go and have to use a custom dev client, that's why the demo use `expo prebuild --no-install` command and then `expo run:ios`, instead of a simple `expo start --ios`
-> More information [here](https://docs.expo.dev/workflow/customizing/)That way you can test your share intent into simulator, but that does not exempt you to test a complete build on device at the end of your development process to make sure all works as excepted.
NB: don't commit your ios/ and android/ folder, rebuild it before EAS build.
> If you want to open your application in expo go with this package your can **disable** the native module call with `useShareIntent({ disabled: true })`. Allowing to speed test other features on your app without share intent.
### Google Signin and CFBundleURLSchemes
When using `@react-native-google-signin/google-signin` you need to configure a custom scheme in your app.json to handle google signin fallback. By doing this, the original app scheme is deleted and must be manually reassigned :
```json
"scheme": "exposhareintentexample",
"ios": {
"supportsTablet": true,
"bundleIdentifier": "expo.modules.exposhareintent.example",
"infoPlist": {
"CFBundleURLTypes": [
{
"CFBundleURLSchemes": [
"com.googleusercontent.apps.xxxxxxxx-xxxxxxxxx",
"exposhareintentexample"
]
}
]
}
},
```### iOS Custom view ?
This project does not and will not support the iOS custom view (native view in the context of sharing intent). Everything must be managed in the main application!
> Managing a custom view requires to package a complete application (seperate react-native bundle), which comes with its own set of constraints (loading time, compatibility with third-party libraries, specific mainEntry, etc.). However `expo-share-intent` aims to remain small and powerful, with easy version upgrades.
If iOS Custom view is a must have feature for you, simply disable iOS configuration of this plugin in your `app.json` ([`disableIOS: true`](#customize-content-types-in-appjson)) and configure the [`expo-share-extension`](https://github.com/MaxAst/expo-share-extension) package.
> for archive a POC was made on this [PR](https://github.com/achorein/expo-share-intent/pull/138)
### iOS Context Menu ?
This project does not and will not support the iOS Context Menu!
> Even if it sounds interesting, the implementation is too specific for each use case and would require a separate project.
## Support
Enjoying this project? Wanna show some love? Drop a star and consider buying me a coffee to keep me fueled and motivated for the next releases
Are you using expo-share-intent at work? Please consider [sponsoring me](https://github.com/sponsors/achorein)!
## Thanks
Special thanks to [expo-config-plugin-ios-share-extension](https://github.com/timedtext/expo-config-plugin-ios-share-extension) and [react-native-receive-sharing-intent](https://github.com/ajith-ab/react-native-receive-sharing-intent), on which this one is very inspired.