Welcome to share-extension-expo-plugin 👋

The Share Extension Expo plugin allows your app to be suggested in the iOS share sheet without leaving the expo managed workflow.
The iOS share extension is a specific app extension that allows your app to be shown in the iOS share sheet.

share sheet

🎁 What's inside ?

This package is composed from:

  • a native module available from javascript to:
    • manipulate the keychain (a data container shared by your app and the share extension)
    • send message intents (increment suggestion counter in iOS system)
  • an expo plugin that:
    • enables keychain sharing support for your app
    • adds (optional) INSendMessageIntent to the list of supported user activities
    • copies your extension files in xcode
    • adds and configures the iOS Share Extension

This means you still have to develop the share extension in XCode (using swift) and this plugin will copy the files in the generated xcode project + configure the share extension using your files

🛠️ Installation

Add the package to your dependencies

expo install share-extension-expo-plugin

⚙️ Configuration

Open your app.config.json or app.json and configure the following

Required config properties

Make sure to provide version, ios.bundleIdentifier and ios.buildNumber in your app.config.js or app.json for the plugin to work. Otherwise, you will have an error on build.

This plugin is, for now, only available to iOS 15 and later.
iOS 15 has the same support matrix as iOS 13 so if you want to upgrade your project to iOS 15, you can use the expo-build-properties to do it.

{
  ...
  "version": "0.0.1",
  "ios": {
    "bundleIdentifier": "com.example.MyApp",
    "buildNumber": "1", // can be set automatically by expo
    ...
  },
  ...
}

Plugin Properties

Add this plugin to your plugins array and use the array below to setup plugin props.

{
  ...
  "plugins": [
    ...
    [
      "share-extension-expo-plugin",
      {
        "devTeam": "XXXXXXXXXX",
        "extensionPath": "path/to/your/extension/files",
        "mainStoryboardName": "MainStoryboard",
        "activationRule": ["url", "image", "movie"]
        // ... check configuration below for more info
      }
    ]
    ...
  ]
  ...
}
Plugin Prop
devTeam required Used to configure Apple Team ID. You can find your Apple Team ID by running expo credentials:manager e.g: "91SW8A37CR"
extensionPath required Path from this module to your extension files (swift sources, storyboards, ...) e.g: ../assets/ios/shareExtension
mainStoryboardName required Used to configure the NSExtensionMainStoryboard entry in extension Info.plist e.g: MainStoryboard
activationRule required Used to configure the NSExtensionActivationRule entry in extension Info.plist. It can be either a string, in the apple string predicate format or an array of string containing type identifiers (without public.) e.g: ['text', 'url', 'image', 'movie']
supportSuggestions optional default: false. Set this to true to enable suggestions
overrideDeploymentTarget optional default: 15.0. Override this if your app targets a higher iOS version.
overrideSwiftVersion optional default: 5.7. Override this if your swift extension code has been created with a higher swift version

🔑 Credentials

Like every other iOS app extensions, you will need Apple credentials for your share extension. If you use EAS to handle your credentials, it will automatically be handled. Otherwise, you will have to configure everything on your apple developer account and on your expo project config.

📚 Documentation

import {
  getKeychainValue,
  setKeychainValue,
  removeKeychainValue,
  sendMessageIntent,
  RecordUser,
} from 'share-extension-expo-plugin'

function example() {
  // read a keychain entry
  const token = getKeychainValue('token')

  // write a keychain entry
  setKeychainValue('token', 'eyJhbGciOiJIUzI1NiIsIn...')

  // erase a keychain entry
  removeKeychainValue('token')

  // increment suggestion counter
  const recipient: RecordUser = {
    id: '0001',
    name: 'Etienne',
    email: 'etienne@example.com',
    picture: 'https://www.gravatar.com/avatar/6ed6da5f61da2e30d23693bf7c612bd4',
  }
  const sender: RecordUser = {
    ...recipient,
    id: '0002',
  }
  const conversationId = '0000'
  const optionalGroupName = 'Etienne Etienne'
  const optionalGroupPicture = 'https://www.gravatar.com/avatar/6ed6da5f61da2e30d23693bf7c612bd4'
  sendMessageIntent(
    [recipient],
    sender,
    conversationId,
    optionalGroupName,
    optionalGroupPicture
  )
}

👀 Example

You can find an example expo app that uses this plugin here: share-extension-expo-example

🍰 Contributing

Feel free to contribute, report issues or open pull requests.

🙏 Patrons

Special thanks to the company that made this possible: uKu

📝 License

Copyright © 2023 BreckoEC
This project is MIT licensed.


Developed with ❤️ from France 🇫🇷