npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

expo-share-intent

v3.2.0

Published

use native share intent for ios and android with expo

Downloads

15,020

Readme

Expo Share Intent 🚀

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 | Simulator Android - expo share intent |

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

Installation

Install npm package

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 in you patches project directory (like example)
  • add post-install script to package.json
  "scripts": {
    ...
    "postinstall": "patch-package"
  },
  • add patch-package for auto patching
yarn add patch-package

More info in #13 and FAQ

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
  "plugins": [
      "expo-share-intent"
  ],

by default only text and url sharing is activated

  • configure a custom URL scheme
  "scheme": "my-app"

More info here : 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

Usage

Use the hook in your App

Make sure to use the hook in your main App.tsx component before any other Provider :

import { useShareIntent } from "expo-share-intent";

const { hasShareIntent, shareIntent, resetShareIntent, error } =
  useShareIntent();

See 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 :

import { ShareIntentProvider, useShareIntentContext } from "expo-share-intent";


const Home = () => {
  const { hasShareIntent, shareIntent, resetShareIntent, error } = useShareIntentContext();
  return ...
}

export default const App = () => {
  return (
    <ShareIntentProvider>
      <ThirdPartyExtraProvider>
        <Home />
      </ThirdPartyExtraProvider>
    </ShareIntentProvider>
  )
}

Share intent content

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 <meta name=""... /> (iOS only, available with NSExtensionActivationSupportsWebPageWithMaxCount) | |

Customize Content Types in app.json

Simply choose content types you need :

  "plugins": [
      [
        "expo-share-intent",
        {
          "iosActivationRules": {
            "NSExtensionActivationSupportsWebURLWithMaxCount": 1,
            "NSExtensionActivationSupportsWebPageWithMaxCount": 1,
            "NSExtensionActivationSupportsImageWithMaxCount": 1,
            "NSExtensionActivationSupportsMovieWithMaxCount": 1,
          },
          "androidIntentFilters": ["text/*", "image/*"]
        }
      ],
  ],

| Option | Values | | ----------------------------- | ------------------- | | iosActivationRules | Allow text sharing with "NSExtensionActivationSupportsText": trueUrl sharing with "NSExtensionActivationSupportsWebURLWithMaxCount": 1 and "NSExtensionActivationSupportsWebPageWithMaxCount": 1Images sharing with "NSExtensionActivationSupportsImageWithMaxCount": 1Videos sharing with "NSExtensionActivationSupportsMovieWithMaxCount": 1Files and audio sharing with "NSExtensionActivationSupportsFileWithMaxCount": 1default value: { "NSExtensionActivationSupportsWebURLWithMaxCount": 1, "NSExtensionActivationSupportsWebPageWithMaxCount": 1 }"More info in apple developper doc hereyou 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 | | 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).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). default value: false |

Expo Router

With expo-router you need to handle loading elements on Layout. 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

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.

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

Config sync failed

$ 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 (more info #31 and #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

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 :

 "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) and configure the expo-share-extension package.

for archive a POC was made on this PR

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!

Thanks

Special thanks to expo-config-plugin-ios-share-extension and react-native-receive-sharing-intent, on which this one is very inspired.