🌿 Share Receiver 🌿
A powerful and easy-to-use Flutter plugin that enables your iOS and Android apps to seamlessly receive and handle shared text, images, videos, and files from other applications using native share sheets.
Guide
Installation
Add share_receiver as a dependency in your pubspec.yaml file:
flutter pub add share_receiver
Configuration
Android
- Edit your Android Manifest file, located in
android/app/src/main/AndroidManifest.xmland add/uncomment the intent filters and meta data that you want to support:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="share_receiver_example"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- ... -->
<!-- Intent filters for share functionality -->
<!--TODO: Add this filter if you want to handle shared text-->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/*" />
</intent-filter>
<!--TODO: Add this filter if you want to handle shared images-->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<!--TODO: Add this filter if you want to handle shared videos-->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="video/*" />
</intent-filter>
<!--TODO: Add this filter if you want to handle any type of file-->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
<!-- ... -->
</application>
<!-- ... -->
</manifest>
Note
If you want to prevent incoming shares from opening a new activity each time, add/edit the attribute android:launchMode="singleTask" to your MainActivity intent inside your AndroidManifest.xml file.
iOS
- Edit your iOS Info.plist file, located in
ios/Runner/Info.plist. It registers your app to open via a deep link that will be launched from the Share Extension.
<!-- Uncomment below lines if you want to use a custom group id rather than the default. Set it in Build Settings → User-Defined -->
<!-- <key>AppGroupId</key>
<string>$(CUSTOM_GROUP_ID)</string> -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
-
Create Share Extension
- In Xcode, go to the menu and select File → New → Target → choose Share Extension
- Give it the name
ShareExtensionand save
-
Go to Build Phases of your
Runnertarget and moveEmbed Foundation Extensionto the top ofThin Binary. -
Make the following edits to
ios/ShareExtension/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Uncomment below lines if you want to use a custom group id rather than the default. Set it in Build Settings → User-Defined -->
<!-- <key>AppGroupId</key>
<string>$(CUSTOM_GROUP_ID)</string> -->
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<!-- The TRUEPREDICATE NSExtensionActivationRule that only works in development mode -->
<!-- <string>TRUEPREDICATE</string> -->
<!-- Add a new rule below will allow sharing one or more file of any type, url, or text content. -->
<!-- You can modify these rules to your liking for which types of share content your app can handle. -->
<string>SUBQUERY (
extensionItems,
$extensionItem,
SUBQUERY (
$extensionItem.attachments,
$attachment,
(
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.file-url"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.text"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.movie"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
)
).@count > 0
).@count > 0
</string>
<key>PHSupportedMediaTypes</key>
<array>
<string>Video</string>
<string>Image</string>
</array>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>
-
Add a group identifier to both the
RunnerandShareExtensiontargets- In Xcode, select Runner → Targets → Runner → Signing & Capabilities
- Click + and select App Groups
- Add a new group (default: your bundle identifier prefixed with
group., e.g.group.com.company.app) - Repeat those steps inside the ShareExtension target using the same group id
-
(Optional) If you used a custom group identifier that isn't your bundle identifier prefixed by
group., add a custom build setting in both targets:- Go to Targets → ShareExtension → Build Settings
- Click + → Add User-Defined Setting
- Key:
CUSTOM_GROUP_ID, Value: your app group identifier - Repeat for the Runner target
-
Wire up the Share Extension view controller
The Share Extension serializes the shared content and saves it to the shared container, then opens a deep link back into the main app. The extension itself is lightweight — it does not embed Flutter.
Important
The Share Extension must not link
FlutterGeneratedPluginSwiftPackage. That package pulls in the Flutter framework, which is too large for an extension. Useshare-receiver-models(SPM) orshare_receiver_models(CocoaPods) instead — both are Flutter-free.
Swift Package Manager
The
share_receiverpackage exposes a lightweightshare-receiver-modelsproduct that contains only the extension-safe code (no Flutter dependency).Step 1 — Add
share-receiver-modelsto your Share Extension target in Xcode:- Select your ShareExtension target → General → Frameworks and Libraries
- Click +, search for
share-receiver-modelsand add it
If
share-receiver-modelsdoes not appear in the list:- Go to File → Add Package Dependencies → Add Local
- Navigate to
ios/Flutter/ephemeral/Packages/.packages/share_receiver/ - When prompted to choose products, add only
share-receiver-modelsto the ShareExtension target (do not addshare-receiveror add anything to the Runner target)
Step 2 — Verify the Share Extension does not link
FlutterGeneratedPluginSwiftPackage:- Select your ShareExtension target → General → Frameworks and Libraries
- If
FlutterGeneratedPluginSwiftPackageis listed, remove it
Step 3 — Replace
ShareExtension/ShareViewController.swift:import share_receiver_models class ShareViewController: ShareReceiverServiceViewController {}
CocoaPods
Option 1 — Lightweight (recommended):
share_receiver_modelspod (no Flutter dependency)Add the following inside
ios/Podfilewithin thetarget 'Runner' doblock, then runpod installinside theiosdirectory.target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) # share_receiver start target 'ShareExtension' do inherit! :search_paths pod 'share_receiver_models', :path => '.symlinks/plugins/share_receiver/ios/share_receiver' end # share_receiver end endReplace
ShareExtension/ShareViewController.swiftwith:import share_receiver_models class ShareViewController: ShareReceiverServiceViewController {}Option 2 — Full pod (
share_receiver) with Flutter dependencyNote
This option links the Flutter framework into the Share Extension, which increases the extension binary size significantly. Prefer Option 1 unless you have a specific reason to use this approach.
target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) # share_receiver start target 'ShareExtension' do inherit! :search_paths end # share_receiver end endReplace
ShareExtension/ShareViewController.swiftwith:import share_receiver class ShareViewController: ShareReceiverServiceViewController {}Make sure the Xcode scheme has a Pre-Action Script so Flutter is available before the build:
- Xcode → Product → Scheme → Edit Scheme → Build → Pre-action → Add Run Script
/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare
Example
import 'package:flutter/material.dart';
import 'package:share_receiver/share_receiver.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
SharedData? _sharedData;
@override
void initState() {
super.initState();
_initShareReceiver();
}
@override
void dispose() {
ShareReceiver.instance.dispose();
super.dispose();
}
Future<void> _initShareReceiver() async {
// Get initial sharing data (if app was opened via share)
final initial = await ShareReceiver.instance.getInitialSharing();
if (initial != null) {
print('Received initial share data: $initial');
setState(() => _sharedData = initial);
// Clear the initial data
ShareReceiver.instance.clear();
}
// Listen for shares while app is running
ShareReceiver.instance.getMediaStream().listen((data) {
print('Received share data: $data');
setState(() => _sharedData = data);
// Clear the received data
ShareReceiver.instance.clear();
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Share Receiver Example')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
mainAxisSize: .min,
spacing: 8.0,
children: [
Text('Shared data: ${_sharedData?.toString() ?? 'No data'}'),
],
),
),
),
),
);
}
}
See the example here for runnable project of various usages.
Bugs or Requests
If you encounter any problems feel free to open an issue. If you feel the library is missing a feature, please raise a ticket on GitHub and I'll look into it. Pull request are also welcome.
See Contributing.md.
Support
Don't forget to give it a like 👍 or a star ⭐