{"id":21405930,"url":"https://github.com/achorein/expo-share-intent","last_synced_at":"2025-05-15T01:06:25.794Z","repository":{"id":223524281,"uuid":"760032265","full_name":"achorein/expo-share-intent","owner":"achorein","description":"🚀 Simple share intent in an Expo Native Module","archived":false,"fork":false,"pushed_at":"2025-05-02T14:42:26.000Z","size":1902,"stargazers_count":389,"open_issues_count":22,"forks_count":25,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-05-13T16:14:13.041Z","etag":null,"topics":["android","expo","ios","react-native","share-extension","share-intent"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/achorein.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"achorein","custom":["https://www.buymeacoffee.com/achorein"]}},"created_at":"2024-02-19T16:51:01.000Z","updated_at":"2025-05-13T11:32:36.000Z","dependencies_parsed_at":"2024-03-18T10:29:42.914Z","dependency_job_id":"d7e83cf6-2074-43c1-a2f3-126c6a1b54b5","html_url":"https://github.com/achorein/expo-share-intent","commit_stats":{"total_commits":91,"total_committers":7,"mean_commits":13.0,"dds":"0.43956043956043955","last_synced_commit":"783306a18764de55a4aa5e9df3a20a1bce7dc38b"},"previous_names":["achorein/expo-share-intent"],"tags_count":58,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achorein%2Fexpo-share-intent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achorein%2Fexpo-share-intent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achorein%2Fexpo-share-intent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achorein%2Fexpo-share-intent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/achorein","download_url":"https://codeload.github.com/achorein/expo-share-intent/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254097772,"owners_count":22014307,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","expo","ios","react-native","share-extension","share-intent"],"created_at":"2024-11-22T16:29:24.241Z","updated_at":"2025-05-15T01:06:20.785Z","avatar_url":"https://github.com/achorein.png","language":"TypeScript","funding_links":["https://github.com/sponsors/achorein","https://www.buymeacoffee.com/achorein","https://github.com/sponsors/achorein)!"],"categories":[],"sub_categories":[],"readme":"# Expo Share Intent 🚀\n\n![npm](https://img.shields.io/npm/v/expo-share-intent.svg)\n![License](https://img.shields.io/npm/l/expo-share-intent.svg)\n![Downloads](https://img.shields.io/npm/dm/expo-share-intent.svg)\n![GitHub stars](https://img.shields.io/github/stars/achorein/expo-share-intent.svg)\n\nAllow sharing **URL, text, images, videos and files** to your **iOS** and **Android** app, using a simple high-performance native module for Expo (React Native).\n\n\u003e 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.\n\n| iOS                                                                                                                                                     | Android                                                                                                                   |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |\n| ![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) |\n\n## Versioning\n\nEnsure you use versions that work together\n\n| Expo       | Supported `expo-share-intent` version |\n| ---------- | ------------------------------------- |\n| **SDK 52** | 3.0+                                  |\n| **SDK 51** | 2.0+                                  |\n| **SDK 50** | 1.0+                                  |\n| **SDK 49** | 0.2+                                  |\n\n\u003e iOS privacy manifest is available since v1.4.1\n\n## Table of Contents\n\n- [Usage](#usage)\n  - [Configure Content Types](#customize-content-types-in-appjson)\n  - [Share Intent content](#share-intent-content)\n  - [Expo Router](#expo-router)\n  - [React Navigation](#react-navigation)\n  - [iOS Custom View](#ios-custom-view-)\n- [Troubleshooting / FAQ](#troubleshooting---faq)\n- [Support](#support)\n\n## Installation\n\n**Install npm package**\n\n```bash\nyarn add expo-share-intent\n# or\nnpm install expo-share-intent\n```\n\n**Requirement: `patch-package`**\n\nFor the moment this package need a post-install script\n\n- 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)\n- add post-install script to `package.json`\n\n```json\n  \"scripts\": {\n    ...\n    \"postinstall\": \"patch-package\"\n  },\n```\n\n- add `patch-package` for auto patching\n\n```bash\nyarn add patch-package\n```\n\n\u003e 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)\n\n**Requirement: `expo-linking`**\n\nSince Expo52, you also need to install `expo-linking` in your app :\n\n```\nexpo install expo-linking\n```\n\n**Into your `app.json`:**\n\n- add expo plugin\n\n```json\n  \"plugins\": [\n      \"expo-share-intent\"\n  ],\n```\n\n\u003e by default only text and url sharing is activated\n\n- configure a custom URL scheme\n\n```json\n  \"scheme\": \"my-app\"\n```\n\n\u003e More info here : [Linking to your app](https://docs.expo.dev/guides/linking/#linking-to-your-app)\n\n**Run your app in dev-client**\n\n```\nexpo prebuild --no-install --clean\nexpo run:ios\nexpo run:android\n```\n\n\u003e We cannot use expo go with this package, more info [here](https://github.com/achorein/expo-share-intent?tab=readme-ov-file#expo-go-)\n\n## Usage\n\n#### Use the hook in your App\n\nMake sure to use the hook in your main `App.tsx` component before any other Provider :\n\n```ts\nimport { useShareIntent } from \"expo-share-intent\";\n\nconst { hasShareIntent, shareIntent, resetShareIntent, error } =\n  useShareIntent();\n```\n\nSee [App.tsx ](https://github.com/achorein/expo-share-intent/blob/main/example/basic/App.tsx) for more details\n\n#### Use the Provider in your App\n\nWhen 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 :\n\n```tsx\nimport { ShareIntentProvider, useShareIntentContext } from \"expo-share-intent\";\n\n\nconst Home = () =\u003e {\n  const { hasShareIntent, shareIntent, resetShareIntent, error } = useShareIntentContext();\n  return ...\n}\n\nexport default const App = () =\u003e {\n  return (\n    \u003cShareIntentProvider\u003e\n      \u003cThirdPartyExtraProvider\u003e\n        \u003cHome /\u003e\n      \u003c/ThirdPartyExtraProvider\u003e\n    \u003c/ShareIntentProvider\u003e\n  )\n}\n\n```\n\n#### Share intent content\n\n```ts\nconst { shareIntent } = useShareIntent();\n```\n\n| attribute                | description                                                                                                                                          | example                                                                                                                                                                                                                                                                                                  |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `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`\"                                                                                                                                                                                                           |\n| `shareIntent.webUrl`     | link extracted from raw text                                                                                                                         | `null`, \"`http://example.com`\", \"`http://example.com/nickname`\"                                                                                                                                                                                                                                          |\n| `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 }]` |\n| `shareIntent.meta`       | meta object which contains extra information about the share intent                                                                                  | `{ title: \"My cool blog article\", \"og:image\": \"https://.../image.png\" }`                                                                                                                                                                                                                                 |\n| `shareIntent.meta.title` | optional title property sent by other app (available on Android and when `NSExtensionActivationSupportsWebPageWithMaxCount` is enabled on iOS)       | `My cool blog article`                                                                                                                                                                                                                                                                                   |\n| `shareIntent.meta.xxx`   | list all webpage metadata available in meta tags `\u003cmeta name=\"\"... /\u003e` (iOS only, available with `NSExtensionActivationSupportsWebPageWithMaxCount`) |                                                                                                                                                                                                                                                                                                          |\n\n#### Customize Content Types in `app.json`\n\nSimply choose content types you need :\n\n```json\n  \"plugins\": [\n      [\n        \"expo-share-intent\",\n        {\n          \"iosActivationRules\": {\n            \"NSExtensionActivationSupportsWebURLWithMaxCount\": 1,\n            \"NSExtensionActivationSupportsWebPageWithMaxCount\": 1,\n            \"NSExtensionActivationSupportsImageWithMaxCount\": 1,\n            \"NSExtensionActivationSupportsMovieWithMaxCount\": 1,\n          },\n          \"androidIntentFilters\": [\"text/*\", \"image/*\"]\n        }\n      ],\n  ],\n```\n\n| Option                        | Values    |\n| ----------------------------- | ------------------- |\n| iosActivationRules            | Allow **text** sharing with `\"NSExtensionActivationSupportsText\": true`\u003cbr/\u003e**Url** sharing with `\"NSExtensionActivationSupportsWebURLWithMaxCount\": 1` and `\"NSExtensionActivationSupportsWebPageWithMaxCount\": 1`\u003cbr/\u003e**Images** sharing with `\"NSExtensionActivationSupportsImageWithMaxCount\": 1`\u003cbr/\u003e**Videos** sharing with `\"NSExtensionActivationSupportsMovieWithMaxCount\": 1`\u003cbr/\u003e**Files and audio** sharing with `\"NSExtensionActivationSupportsFileWithMaxCount\": 1`\u003cbr/\u003e_default value_: `{ \"NSExtensionActivationSupportsWebURLWithMaxCount\": 1, \"NSExtensionActivationSupportsWebPageWithMaxCount\": 1 }\"`\u003cbr/\u003e_More info in apple developper doc [here](https://developer.apple.com/documentation/bundleresources/information_property_list/nsextension/nsextensionattributes/nsextensionactivationrule)_\u003cbr/\u003eyou can also provide a custom query (ex: `\"iosActivationRules\": \"SUBQUERY (...)\"`) |\n| iosShareExtensionName         | override `CFBundleDisplayName` the extension `info.plist`, also used as extension name for xcode target (ex: `ExpoShareIntent Example Extension`, folder: `ExpoShareIntentExampleExtension`) |\n| 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)  |\n| androidIntentFilters          | **one file sharing** array of MIME types :`\"text/*\"` / `\"image/*\"` / `\"video/*\"` / `\"*/*\"`\u003cbr/\u003e_default value_: `[\"text/*\"]` (text and url) |\n| androidMultiIntentFilters     | **multiple files sharing** array of MIME types : `\"image/*\"` / `\"video/*\"` / `\"audio/*`/ `\"*/*\"`\u003cbr/\u003e_default value_: `[]` |\n| androidMainActivityAttributes | _default value_: `{ \"android:launchMode\": \"singleTask\" }`  |\n| 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)).\u003cbr/\u003eExample: \u003ccode\u003epreprocessorInjectJS: \"metas['og\\\\:image'] = metas['og\\\\:image'] \u0026#124;\u0026#124; document.querySelector('img#seo-image')?.getAttribute('src')\"\u003c/code\u003e |\n| disableAndroid                | Disable the android share intent. Useful if you want to use a custom implementation. _default value_: `false`  |\n| 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` |\n\n### Expo Router\n\nWith `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.\n\nAn example is available with Expo Router v3 in [example/expo-router](https://github.com/achorein/expo-share-intent/tree/main/example/expo-router/)\n\n### React Navigation\n\nIf 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.\n\nTake a look at the example in [example/react-navigation](https://github.com/achorein/expo-share-intent/tree/main/example/react-navigation/).\n\n## Troubleshooting - FAQ\n\n### iOS Extension Target\n\nWhen building on EAS you should only have **one** extension target (during credentials setting process).\n\nTo 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).\n\nMore details in [#1](https://github.com/achorein/expo-share-intent-demo/issues/1)\n\n### Config sync failed\n\n```bash\n$ yarn prebuild\n⠧ Running prebuild[expo-share-intent] add ios share extension (scheme:exposhareintentexample appIdentifier:expo.modules.exposhareintent.example)\n⠇ Running prebuild[expo-share-intent] add android filters text/* image/*\n✖ Config sync failed\nTypeError: [ios.xcodeproj]: withIosXcodeprojBaseMod: Cannot read properties of null (reading 'path')\n```\n\nThis 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))\n\n### Expo Go ?\n\nWe 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`\n-\u003e More information [here](https://docs.expo.dev/workflow/customizing/)\n\nThat 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.\n\nNB: don't commit your ios/ and android/ folder, rebuild it before EAS build.\n\n\u003e 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.\n\n### Google Signin and CFBundleURLSchemes\n\nWhen 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 :\n\n```json\n \"scheme\": \"exposhareintentexample\",\n \"ios\": {\n      \"supportsTablet\": true,\n      \"bundleIdentifier\": \"expo.modules.exposhareintent.example\",\n      \"infoPlist\": {\n        \"CFBundleURLTypes\": [\n          {\n            \"CFBundleURLSchemes\": [\n              \"com.googleusercontent.apps.xxxxxxxx-xxxxxxxxx\",\n              \"exposhareintentexample\"\n            ]\n          }\n        ]\n      }\n    },\n```\n\n### iOS Custom view ?\n\nThis 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!\n\n\u003e 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.\n\nIf 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.\n\n\u003e for archive a POC was made on this [PR](https://github.com/achorein/expo-share-intent/pull/138)\n\n### iOS Context Menu ?\n\nThis project does not and will not support the iOS Context Menu!\n\n\u003e Even if it sounds interesting, the implementation is too specific for each use case and would require a separate project.\n\n## Support\n\nEnjoying 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\n\n\u003ca href=\"https://www.buymeacoffee.com/achorein\" target=\"_blank\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" alt=\"Buy Me A Coffee\" style=\"height: 60px !important;width: 217px !important;\" \u003e\u003c/a\u003e\n\nAre you using expo-share-intent at work? Please consider [sponsoring me](https://github.com/sponsors/achorein)!\n\n## Thanks\n\nSpecial 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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachorein%2Fexpo-share-intent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fachorein%2Fexpo-share-intent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachorein%2Fexpo-share-intent/lists"}