diff --git a/packages/share_plus/share_plus/CHANGELOG.md b/packages/share_plus/share_plus/CHANGELOG.md index f43fba7d56..5b8f1b0f19 100644 --- a/packages/share_plus/share_plus/CHANGELOG.md +++ b/packages/share_plus/share_plus/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.2.0 + + - **FEAT**(share_plus): Eligible user to share files via specific package name + ## 10.1.4 - **FIX**(share_plus): fallback for shareXFiles() to use download on web ([#3388](https://github.com/fluttercommunity/plus_plugins/issues/3388)). ([95a12ee3](https://github.com/fluttercommunity/plus_plugins/commit/95a12ee3982dd61de5d07005de62f81c2e99eb08)) diff --git a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/MethodCallHandler.kt b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/MethodCallHandler.kt index d4488922e5..7ecab7d319 100644 --- a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/MethodCallHandler.kt +++ b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/MethodCallHandler.kt @@ -53,6 +53,20 @@ internal class MethodCallHandler( success(isWithResult, result) } + "shareFilesToPackage" -> { + share.shareFilesToPackage( + call.argument>("paths")!!, + call.argument?>("mimeTypes"), + call.argument("text"), + call.argument("subject"), + isWithResult, + call.argument("packageName"), + call.argument>?>("extras"), + ) + + success(isWithResult, result) + } + else -> result.notImplemented() } } catch (e: Throwable) { diff --git a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/Share.kt b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/Share.kt index 59bdb1e914..6eddaefb36 100644 --- a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/Share.kt +++ b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/Share.kt @@ -158,6 +158,53 @@ internal class Share( startActivity(chooserIntent, withResult) } + @Throws(IOException::class) + fun shareFilesToPackage( + paths: List, + mimeTypes: List?, + text: String?, + subject: String?, + withResult: Boolean, + packageName: String?, + extras: List>? + ) { + clearShareCacheFolder() + val fileUris = getUrisForPaths(paths) + val shareIntent = Intent() + when { + (fileUris.isEmpty() && !text.isNullOrBlank()) -> { + share(text, subject, withResult) + return + } + fileUris.size == 1 -> { + val mimeType = if (!mimeTypes.isNullOrEmpty()) { + mimeTypes.first() + } else { + "*/*" + } + shareIntent.apply { + action = Intent.ACTION_SEND + type = mimeType + putExtra(Intent.EXTRA_STREAM, fileUris.first()) + } + } + else -> { + shareIntent.apply { + action = Intent.ACTION_SEND_MULTIPLE + type = reduceMimeTypes(mimeTypes) + putParcelableArrayListExtra(Intent.EXTRA_STREAM, fileUris) + } + } + } + shareIntent.setPackage(packageName); + extras?.forEach { item -> shareIntent.putExtra(item.keys.first(), item.values.first()) } + if (text != null) shareIntent.putExtra(Intent.EXTRA_TEXT, text) + if (subject != null) shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject) + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + // If we dont want the result we use the old 'createChooser' + startActivity(shareIntent, withResult) + } + private fun startActivity(intent: Intent, withResult: Boolean) { if (activity != null) { if (withResult) { diff --git a/packages/share_plus/share_plus/example/lib/main.dart b/packages/share_plus/share_plus/example/lib/main.dart index 913a6e33ce..ea280be2ff 100644 --- a/packages/share_plus/share_plus/example/lib/main.dart +++ b/packages/share_plus/share_plus/example/lib/main.dart @@ -160,6 +160,21 @@ class DemoAppState extends State { ); }, ), + const SizedBox(height: 32), + Builder( + builder: (BuildContext context) { + return ElevatedButton( + style: ElevatedButton.styleFrom( + foregroundColor: Theme.of(context).colorScheme.onPrimary, + backgroundColor: Theme.of(context).colorScheme.primary, + ), + onPressed: text.isEmpty && imagePaths.isEmpty && uri.isEmpty + ? null + : () => _onShareWhatsapp(context), + child: const Text('Share Whatsapp'), + ); + }, + ), const SizedBox(height: 16), Builder( builder: (BuildContext context) { @@ -204,6 +219,33 @@ class DemoAppState extends State { }); } + void _onShareWhatsapp(BuildContext context) async { + final box = context.findRenderObject() as RenderBox?; + + if (uri.isNotEmpty) { + await Share.shareUri(Uri.parse(uri)); + } else if (imagePaths.isNotEmpty) { + final files = []; + for (var i = 0; i < imagePaths.length; i++) { + files.add(XFile(imagePaths[i], name: imageNames[i])); + } + await Share.shareFilesToPackage( + files, + text: text, + subject: subject, + sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, + packageName: "com.whatsapp", + extras: [ + {"jid": "628111555333@s.whatsapp.net"} + ], + ); + } else { + await Share.share(text, + subject: subject, + sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size); + } + } + void _onShareWithResult(BuildContext context) async { // A builder is used to retrieve the context immediately // surrounding the ElevatedButton. diff --git a/packages/share_plus/share_plus/example/pubspec.yaml b/packages/share_plus/share_plus/example/pubspec.yaml index da086b16fb..eb70c60029 100644 --- a/packages/share_plus/share_plus/example/pubspec.yaml +++ b/packages/share_plus/share_plus/example/pubspec.yaml @@ -4,7 +4,8 @@ description: Demonstrates how to use the share_plus plugin. dependencies: flutter: sdk: flutter - share_plus: ^10.1.4 + share_plus: + path: ../ image_picker: ^1.1.2 file_selector: ^1.0.3 @@ -24,5 +25,5 @@ flutter: - assets/flutter_logo.png environment: - sdk: '>=3.4.0 <4.0.0' - flutter: '>=3.22.0' + sdk: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" diff --git a/packages/share_plus/share_plus/lib/share_plus.dart b/packages/share_plus/share_plus/lib/share_plus.dart index e6e2f64a8b..8cdcfc27f8 100644 --- a/packages/share_plus/share_plus/lib/share_plus.dart +++ b/packages/share_plus/share_plus/lib/share_plus.dart @@ -139,4 +139,25 @@ class Share { fileNameOverrides: fileNameOverrides, ); } + + static Future shareFilesToPackage( + List files, { + String? subject, + String? text, + Rect? sharePositionOrigin, + List? fileNameOverrides, + required String packageName, + List>? extras, + }) async { + assert(files.isNotEmpty); + _platform.shareFilesToPackage( + files, + subject: subject, + text: text, + sharePositionOrigin: sharePositionOrigin, + fileNameOverrides: fileNameOverrides, + packageName: packageName, + extras: extras, + ); + } } diff --git a/packages/share_plus/share_plus/pubspec.yaml b/packages/share_plus/share_plus/pubspec.yaml index 716edb03ed..642fd879a6 100644 --- a/packages/share_plus/share_plus/pubspec.yaml +++ b/packages/share_plus/share_plus/pubspec.yaml @@ -1,6 +1,6 @@ name: share_plus description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS. -version: 10.1.4 +version: 10.2.0 homepage: https://github.com/fluttercommunity/plus_plugins repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/share_plus/share_plus issue_tracker: https://github.com/fluttercommunity/plus_plugins/labels/share_plus @@ -35,7 +35,8 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - share_plus_platform_interface: ^5.0.2 + share_plus_platform_interface: + path: ../share_plus_platform_interface file: ">=6.1.4 <8.0.0" url_launcher_web: ^2.3.2 url_launcher_windows: ^3.1.2 @@ -53,4 +54,3 @@ dev_dependencies: environment: sdk: ">=3.4.0 <4.0.0" flutter: ">=3.22.0" - diff --git a/packages/share_plus/share_plus_platform_interface/CHANGELOG.md b/packages/share_plus/share_plus_platform_interface/CHANGELOG.md index 5e0683705c..dfeb3467eb 100644 --- a/packages/share_plus/share_plus_platform_interface/CHANGELOG.md +++ b/packages/share_plus/share_plus_platform_interface/CHANGELOG.md @@ -1,3 +1,6 @@ +## 5.1.0 + - **FEAT**(share_plus): shareFilesToPackage, allow user to share files to specific packages name + ## 5.0.2 - **REFACTOR**(all): Use range of flutter_lints for broader compatibility ([#3371](https://github.com/fluttercommunity/plus_plugins/issues/3371)). ([8a303add](https://github.com/fluttercommunity/plus_plugins/commit/8a303add3dee1acb8bac5838246490ed8a0fe408)) diff --git a/packages/share_plus/share_plus_platform_interface/lib/method_channel/method_channel_share.dart b/packages/share_plus/share_plus_platform_interface/lib/method_channel/method_channel_share.dart index bb7fa696c6..04d363c915 100644 --- a/packages/share_plus/share_plus_platform_interface/lib/method_channel/method_channel_share.dart +++ b/packages/share_plus/share_plus_platform_interface/lib/method_channel/method_channel_share.dart @@ -115,6 +115,56 @@ class MethodChannelShare extends SharePlatform { return ShareResult(result, _statusFromResult(result)); } + /// Summons the platform's share sheet to share multiple files. + @override + Future shareFilesToPackage( + List files, { + String? subject, + String? text, + Rect? sharePositionOrigin, + required String packageName, + List>? extras, + List? fileNameOverrides, + }) async { + assert(files.isNotEmpty); + assert( + fileNameOverrides == null || files.length == fileNameOverrides.length, + "fileNameOverrides list must have the same length as files list.", + ); + final filesWithPath = await _getFiles(files, fileNameOverrides); + assert(filesWithPath.every((element) => element.path.isNotEmpty)); + + final mimeTypes = filesWithPath + .map((e) => e.mimeType ?? _mimeTypeForPath(e.path)) + .toList(); + + final paths = filesWithPath.map((e) => e.path).toList(); + assert(paths.length == mimeTypes.length); + assert(mimeTypes.every((element) => element.isNotEmpty)); + + final params = { + 'paths': paths, + 'mimeTypes': mimeTypes, + }; + + if (subject != null) params['subject'] = subject; + if (text != null) params['text'] = text; + if (extras != null) params['extras'] = extras; + params['packageName'] = packageName; + + if (sharePositionOrigin != null) { + params['originX'] = sharePositionOrigin.left; + params['originY'] = sharePositionOrigin.top; + params['originWidth'] = sharePositionOrigin.width; + params['originHeight'] = sharePositionOrigin.height; + } + final result = + await channel.invokeMethod('shareFilesToPackage', params) ?? + 'dev.fluttercommunity.plus/share/unavailable'; + + return ShareResult(result, _statusFromResult(result)); + } + /// Ensure that a file is readable from the file system. Will create file on-demand under TemporaryDiectory and return the temporary file otherwise. /// /// if file doesn't contain path, diff --git a/packages/share_plus/share_plus_platform_interface/lib/platform_interface/share_plus_platform.dart b/packages/share_plus/share_plus_platform_interface/lib/platform_interface/share_plus_platform.dart index f1840624ef..1f29e407e6 100644 --- a/packages/share_plus/share_plus_platform_interface/lib/platform_interface/share_plus_platform.dart +++ b/packages/share_plus/share_plus_platform_interface/lib/platform_interface/share_plus_platform.dart @@ -71,6 +71,27 @@ class SharePlatform extends PlatformInterface { fileNameOverrides: fileNameOverrides, ); } + + /// Share [XFile] objects to package. + Future shareFilesToPackage( + List files, { + String? subject, + String? text, + Rect? sharePositionOrigin, + List? fileNameOverrides, + required String packageName, + List>? extras, + }) async { + return _instance.shareFilesToPackage( + files, + subject: subject, + text: text, + sharePositionOrigin: sharePositionOrigin, + fileNameOverrides: fileNameOverrides, + packageName: packageName, + extras: extras, + ); + } } /// The result of a share to determine what action the diff --git a/packages/share_plus/share_plus_platform_interface/pubspec.yaml b/packages/share_plus/share_plus_platform_interface/pubspec.yaml index 75017c1cf4..7bbe362f06 100644 --- a/packages/share_plus/share_plus_platform_interface/pubspec.yaml +++ b/packages/share_plus/share_plus_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: share_plus_platform_interface description: A common platform interface for the share_plus plugin. -version: 5.0.2 +version: 5.1.0 homepage: https://github.com/fluttercommunity/plus_plugins repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/