A Flutter plugin that enables flutter apps to receive sharing photos, videos, text, urls or any other file types from another app.
Also, supports iOS Share extension and launching the host app automatically. Check the provided example for more info.
Android | iOS | |
---|---|---|
Support | SDK 19+ (Kotlin 1.9.22) | 12.0+ (Swift 5.0) |
To use this plugin, add receive_sharing_intent
as a dependency in your pubspec.yaml file. For example:
dependencies:
receive_sharing_intent: ^latest
Add the following filters to your android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
.....
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:name="io.flutter.app.FlutterApplication"
...
>
<!--Set activity launchMode to singleTask, if you want to prevent creating new activity instance everytime there is a new intent.-->
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!--TODO: Add this filter, if you want support opening urls into your app-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="example.com"
android:pathPrefix="/invite"/>
</intent-filter>
<!--TODO: Add this filter, if you want support opening files into your app-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="*/*"
android:scheme="content" />
</intent-filter>
<!--TODO: Add this filter, if you want to support sharing text into your app-->
<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 support sharing images into your app-->
<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 support sharing videos into your app-->
<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 support sharing any type of files-->
<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>
....
Make sure the deployment target for Runner.app and the share extension is the same.
<?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>
<key>AppGroupId</key>
<string>$(CUSTOM_GROUP_ID)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>PHSupportedMediaTypes</key>
<array>
<!--TODO: Add this flag, if you want to support sharing video into your app-->
<string>Video</string>
<!--TODO: Add this flag, if you want to support sharing images into your app-->
<string>Image</string>
</array>
<key>NSExtensionActivationRule</key>
<dict>
<!--TODO: Add this flag, if you want to support sharing text into your app-->
<key>NSExtensionActivationSupportsText</key>
<true/>
<!--TODO: Add this tag, if you want to support sharing urls into your app-->
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<!--TODO: Add this flag, if you want to support sharing images into your app-->
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>100</integer>
<!--TODO: Add this flag, if you want to support sharing video into your app-->
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>100</integer>
<!--TODO: Add this flag, if you want to support sharing other files into your app-->
<!--Change the integer to however many files you want to be able to share at a time-->
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>
...
<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>
<key>NSPhotoLibraryUsageDescription</key>
<string>To upload photos, please allow permission to access your photo library.</string>
...
....
<!--TODO: Add this tag, if you want support opening urls into your app-->
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:example.com</string>
</array>
....
...
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
# Share Extension is name of Extension which you created which is in this case 'Share Extension'
target 'Share Extension' do
inherit! :search_paths
end
end
...
Signing & Capabilities
tab and add App Groups capability in BOTH Targets: Runner
and Share Extension
group.MyContainer
in the example project its group.com.kasem.ShareExtention
Build Settings -> +
) string CUSTOM_GROUP_ID
in BOTH Targets: Runner
and Share Extension
and set value to group id created above. You can use different group ids depends on your flavor schemesEmbed Foundation Extension
to the top of Thin Binary
.ShareViewController
ios/Share Extension/ShareViewController.swift inherit from RSIShareViewController
:// If you get no such module 'receive_sharing_intent' error.
// Go to Build Phases of your Runner target and
// move `Embed Foundation Extension` to the top of `Thin Binary`.
import receive_sharing_intent
class ShareViewController: RSIShareViewController {
// Use this method to return false if you don't want to redirect to host app automatically.
// Default is true
override func shouldAutoRedirect() -> Bool {
return false
}
}
Error: No such module 'receive_sharing_intent'
Embed Foundation Extension
to the top of Thin Binary
.Error: App does not build after adding Share Extension?
Linking/Other Linker Flags
You might need to disable bitcode for the extension target
Error: Invalid Bundle. The bundle at 'Runner.app/Plugins/Sharing Extension.appex' contains disallowed file 'Frameworks'
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late StreamSubscription _intentSub;
final _sharedFiles = <SharedMediaFile>[];
@override
void initState() {
super.initState();
// Listen to media sharing coming from outside the app while the app is in the memory.
_intentSub = ReceiveSharingIntent.instance.getMediaStream().listen((value) {
setState(() {
_sharedFiles.clear();
_sharedFiles.addAll(value);
print(_sharedFiles.map((f) => f.toMap()));
});
}, onError: (err) {
print("getIntentDataStream error: $err");
});
// Get the media sharing coming from outside the app while the app is closed.
ReceiveSharingIntent.instance.getInitialMedia().then((value) {
setState(() {
_sharedFiles.clear();
_sharedFiles.addAll(value);
print(_sharedFiles.map((f) => f.toMap()));
// Tell the library that we are done processing the intent.
ReceiveSharingIntent.instance.reset();
});
});
}
@override
void dispose() {
_intentSub.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
const textStyleBold = const TextStyle(fontWeight: FontWeight.bold);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: <Widget>[
Text("Shared files:", style: textStyleBold),
Text(_sharedFiles
.map((f) => f.toMap())
.join(",\n****************\n")),
],
),
),
),
);
}
}