share_receiver 1.0.2
share_receiver: ^1.0.2 copied to clipboard
A Flutter plugin for iOS and Android to handle incoming shared text or media from other apps.
🌿 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 ⭐
