From e67c7331bfe5960f507184e88be3562cf9ed3375 Mon Sep 17 00:00:00 2001 From: Rubin Raithel <33808743+Coronon@users.noreply.github.com> Date: Sun, 20 Mar 2022 21:04:50 +0100 Subject: [PATCH 1/4] [share_plus] add support for minSdkVersion 16 --- packages/share_plus/share_plus/CHANGELOG.md | 4 ++ .../share_plus/android/build.gradle | 2 +- .../plus/share/MethodCallHandler.kt | 59 +++++++++---------- .../example/android/app/build.gradle | 2 +- packages/share_plus/share_plus/pubspec.yaml | 2 +- 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/packages/share_plus/share_plus/CHANGELOG.md b/packages/share_plus/share_plus/CHANGELOG.md index ce449165c8..17fca040dc 100644 --- a/packages/share_plus/share_plus/CHANGELOG.md +++ b/packages/share_plus/share_plus/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.3 + +- Android: Revert increased minSdkVersion back to 16 + ## 4.0.2 - Fix type mismatch on Android for some users diff --git a/packages/share_plus/share_plus/android/build.gradle b/packages/share_plus/share_plus/android/build.gradle index bc486e272c..4f9ee5dee7 100644 --- a/packages/share_plus/share_plus/android/build.gradle +++ b/packages/share_plus/share_plus/android/build.gradle @@ -28,7 +28,7 @@ android { compileSdkVersion 31 defaultConfig { - minSdkVersion 22 + minSdkVersion 16 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { 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 775fed782c..478924d391 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 @@ -1,5 +1,6 @@ package dev.fluttercommunity.plus.share +import android.os.Build import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import java.io.IOException @@ -11,48 +12,34 @@ internal class MethodCallHandler( ) : MethodChannel.MethodCallHandler { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + // The user used a *WithResult method + val calledWithResult = call.method.endsWith("WithResult") + // We don't attempt to return a result if the current API version doesn't support it + val withResult = calledWithResult && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 + when (call.method) { - "share" -> { + "share", "shareWithResult" -> { expectMapArguments(call) + if (withResult && !manager.setCallback(result)) return + // Android does not support showing the share sheet at a particular point on screen. share.share( call.argument("text") as String, call.argument("subject") as String?, - false, + withResult, ) - result.success(null) - } - "shareFiles" -> { - expectMapArguments(call) - // Android does not support showing the share sheet at a particular point on screen. - try { - share.shareFiles( - call.argument>("paths")!!, - call.argument?>("mimeTypes"), - call.argument("text"), - call.argument("subject"), - false, - ) - result.success(null) - } catch (e: IOException) { - result.error("Share failed", e.message, null) + if (!withResult) { + if (calledWithResult) { + result.success("dev.fluttercommunity.plus/share/unavailable") + } else { + result.success(null) + } } } - "shareWithResult" -> { + "shareFiles", "shareFilesWithResult" -> { expectMapArguments(call) - if (!manager.setCallback(result)) return - - // Android does not support showing the share sheet at a particular point on screen. - share.share( - call.argument("text") as String, - call.argument("subject") as String?, - true, - ) - } - "shareFilesWithResult" -> { - expectMapArguments(call) - if (!manager.setCallback(result)) return + if (withResult && !manager.setCallback(result)) return // Android does not support showing the share sheet at a particular point on screen. try { @@ -61,8 +48,16 @@ internal class MethodCallHandler( call.argument?>("mimeTypes"), call.argument("text"), call.argument("subject"), - true, + withResult, ) + + if (!withResult) { + if (calledWithResult) { + result.success("dev.fluttercommunity.plus/share/unavailable") + } else { + result.success(null) + } + } } catch (e: IOException) { result.error("Share failed", e.message, null) } diff --git a/packages/share_plus/share_plus/example/android/app/build.gradle b/packages/share_plus/share_plus/example/android/app/build.gradle index d30aca2256..8c0a10bb9c 100644 --- a/packages/share_plus/share_plus/example/android/app/build.gradle +++ b/packages/share_plus/share_plus/example/android/app/build.gradle @@ -33,7 +33,7 @@ android { defaultConfig { applicationId "io.flutter.plugins.shareexample" - minSdkVersion 22 + minSdkVersion 16 targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/packages/share_plus/share_plus/pubspec.yaml b/packages/share_plus/share_plus/pubspec.yaml index 987288dd8f..6bac05a0f1 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: 4.0.2 +version: 4.0.3 homepage: https://plus.fluttercommunity.dev/ repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/ From a067b8f8f341e8e26e89ee99ee2a7b0ba9bf7000 Mon Sep 17 00:00:00 2001 From: Rubin Raithel <33808743+Coronon@users.noreply.github.com> Date: Sun, 20 Mar 2022 21:07:47 +0100 Subject: [PATCH 2/4] [share_plus] gracefully fall back to normal share methods --- packages/share_plus/share_plus/CHANGELOG.md | 1 + packages/share_plus/share_plus/pubspec.yaml | 2 +- .../CHANGELOG.md | 4 ++ .../lib/share_plus_platform_interface.dart | 30 +++++++++++--- .../pubspec.yaml | 2 +- .../share_plus_platform_interface_test.dart | 39 ++++++++++++++++--- 6 files changed, 65 insertions(+), 13 deletions(-) diff --git a/packages/share_plus/share_plus/CHANGELOG.md b/packages/share_plus/share_plus/CHANGELOG.md index 17fca040dc..12d8e7cd97 100644 --- a/packages/share_plus/share_plus/CHANGELOG.md +++ b/packages/share_plus/share_plus/CHANGELOG.md @@ -1,6 +1,7 @@ ## 4.0.3 - Android: Revert increased minSdkVersion back to 16 +- Gracefully fall back to normal share methods on not supported platforms ## 4.0.2 diff --git a/packages/share_plus/share_plus/pubspec.yaml b/packages/share_plus/share_plus/pubspec.yaml index 6bac05a0f1..2ea69782f5 100644 --- a/packages/share_plus/share_plus/pubspec.yaml +++ b/packages/share_plus/share_plus/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: mime: ^1.0.0 flutter: sdk: flutter - share_plus_platform_interface: ^3.0.0 + share_plus_platform_interface: ^3.0.2 share_plus_linux: ^3.0.0 share_plus_macos: ^3.0.0 share_plus_windows: ^3.0.0 diff --git a/packages/share_plus/share_plus_platform_interface/CHANGELOG.md b/packages/share_plus/share_plus_platform_interface/CHANGELOG.md index 4d2df718d6..752b2a2035 100644 --- a/packages/share_plus/share_plus_platform_interface/CHANGELOG.md +++ b/packages/share_plus/share_plus_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.2 + +- Gracefully fall back to normal share methods on not supported platforms + ## 3.0.1 - Set min Flutter to 1.20.0 to match Share plugins on all platforms diff --git a/packages/share_plus/share_plus_platform_interface/lib/share_plus_platform_interface.dart b/packages/share_plus/share_plus_platform_interface/lib/share_plus_platform_interface.dart index aad3ad4c4f..0049d6c128 100644 --- a/packages/share_plus/share_plus_platform_interface/lib/share_plus_platform_interface.dart +++ b/packages/share_plus/share_plus_platform_interface/lib/share_plus_platform_interface.dart @@ -66,8 +66,13 @@ class SharePlatform extends PlatformInterface { String? subject, Rect? sharePositionOrigin, }) async { - throw UnimplementedError( - 'shareWithResult() has only been implemented on IOS, Android & macOS'); + await _instance.share( + text, + subject: subject, + sharePositionOrigin: sharePositionOrigin, + ); + + return _resultUnavailable; } /// Share files with Result. @@ -78,8 +83,15 @@ class SharePlatform extends PlatformInterface { String? text, Rect? sharePositionOrigin, }) async { - throw UnimplementedError( - 'shareWithResult() has only been implemented on IOS, Android & macOS'); + await _instance.shareFiles( + paths, + mimeTypes: mimeTypes, + subject: subject, + text: text, + sharePositionOrigin: sharePositionOrigin, + ); + + return _resultUnavailable; } } @@ -94,8 +106,8 @@ class ShareResult { /// /// Note that an empty string means the share-sheet was /// dismissed without any action and the special value - /// `dev.fluttercommunity.plus/share/unavailable` is caused - /// by an unavailable Android Activity at runtime. + /// `dev.fluttercommunity.plus/share/unavailable` points + /// to the current environment not supporting share results. final String raw; /// The action the user has taken @@ -115,3 +127,9 @@ enum ShareResultStatus { /// The status can not be determined unavailable, } + +/// Returned if the platform is not supported +const _resultUnavailable = ShareResult( + 'dev.fluttercommunity.plus/share/unavailable', + ShareResultStatus.unavailable, +); diff --git a/packages/share_plus/share_plus_platform_interface/pubspec.yaml b/packages/share_plus/share_plus_platform_interface/pubspec.yaml index 50ca67971b..4e10b2a256 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: 3.0.1 +version: 3.0.2 homepage: https://plus.fluttercommunity.dev/ repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/ diff --git a/packages/share_plus/share_plus_platform_interface/test/share_plus_platform_interface_test.dart b/packages/share_plus/share_plus_platform_interface/test/share_plus_platform_interface_test.dart index 38da5d0460..f33bdcc6bf 100644 --- a/packages/share_plus/share_plus_platform_interface/test/share_plus_platform_interface_test.dart +++ b/packages/share_plus/share_plus_platform_interface/test/share_plus_platform_interface_test.dart @@ -179,19 +179,48 @@ void main() { }); }); - test('withResult methods throw unimplemented on non IOS & Android', () async { + test('withResult methods return unavailable on non IOS & Android', () async { + const resultUnavailable = ShareResult( + 'dev.fluttercommunity.plus/share/unavailable', + ShareResultStatus.unavailable, + ); + expect( - () => sharePlatform.shareWithResult('some text to share'), - throwsA(const TypeMatcher()), + sharePlatform.shareWithResult('some text to share'), + completion(equals(resultUnavailable)), ); await withFile('tempfile-83649d.png', (File fd) async { expect( - () => sharePlatform.shareFilesWithResult([fd.path]), - throwsA(const TypeMatcher()), + sharePlatform.shareFilesWithResult([fd.path]), + completion(equals(resultUnavailable)), ); }); }); + + test('withResult methods invoke normal share on non IOS & Android', () async { + await sharePlatform.shareWithResult( + 'some text to share', + subject: 'some subject to share', + sharePositionOrigin: const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + ); + verify(mockChannel.invokeMethod('share', { + 'text': 'some text to share', + 'subject': 'some subject to share', + 'originX': 1.0, + 'originY': 2.0, + 'originWidth': 3.0, + 'originHeight': 4.0, + })); + + await withFile('tempfile-83649e.png', (File fd) async { + await sharePlatform.shareFilesWithResult([fd.path]); + verify(mockChannel.invokeMethod('shareFiles', { + 'paths': [fd.path], + 'mimeTypes': ['image/png'], + })); + }); + }); } /// Execute a block within a context that handles creation and deletion of a helper file From 7e9df89cadd27beb37b52439eff5bfd04194e07e Mon Sep 17 00:00:00 2001 From: Rubin Raithel <33808743+Coronon@users.noreply.github.com> Date: Sun, 20 Mar 2022 21:11:09 +0100 Subject: [PATCH 3/4] [share_plus] improve documentation --- packages/share_plus/share_plus/CHANGELOG.md | 1 + .../share_plus/share_plus/lib/share_plus.dart | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/share_plus/share_plus/CHANGELOG.md b/packages/share_plus/share_plus/CHANGELOG.md index 12d8e7cd97..2e8861ded2 100644 --- a/packages/share_plus/share_plus/CHANGELOG.md +++ b/packages/share_plus/share_plus/CHANGELOG.md @@ -2,6 +2,7 @@ - Android: Revert increased minSdkVersion back to 16 - Gracefully fall back to normal share methods on not supported platforms +- Improve documentation for `shareWithResult` methods ## 4.0.2 diff --git a/packages/share_plus/share_plus/lib/share_plus.dart b/packages/share_plus/share_plus/lib/share_plus.dart index 3fec183976..2168dea66f 100644 --- a/packages/share_plus/share_plus/lib/share_plus.dart +++ b/packages/share_plus/share_plus/lib/share_plus.dart @@ -87,12 +87,17 @@ class Share { /// any other call to any share method that returns a result _might_ result in /// a [PlatformException] (on Android). /// - /// Because IOS, Android and macOS provide different feedback on share-sheet interaction, - /// a result on IOS will be more specific than on Android or macOS. While IOS can detect if - /// the user actually completed his selected action or aborted it midway, Android and macOS - /// only record if the user selected an action or outright dismissed the share-sheet. + /// Because IOS, Android and macOS provide different feedback on share-sheet + /// interaction, a result on IOS will be more specific than on Android or macOS. + /// While on IOS the selected action can inform its caller that it was completed + /// or dismissed midway (_actions are free to return whatever they want_), + /// Android and macOS only record if the user selected an action or outright + /// dismissed the share-sheet. /// /// **Currently only implemented on IOS, Android and macOS.** + /// + /// Will gracefully fall back to the non result variant if not implemented + /// for the current environment and return [ShareResult.unavailable]. static Future shareWithResult( String text, { String? subject, @@ -111,12 +116,17 @@ class Share { /// any other call to any share method that returns a result _might_ result in /// a [PlatformException] (on Android). /// - /// Because IOS, Android and macOS provide different feedback on share-sheet interaction, - /// a result on IOS will be more specific than on Android or macOS. While IOS can detect if - /// the user actually completed his selected action or aborted it midway, Android and macOS - /// only record if the user selected an action or outright dismissed the share-sheet. + /// Because IOS, Android and macOS provide different feedback on share-sheet + /// interaction, a result on IOS will be more specific than on Android or macOS. + /// While on IOS the selected action can inform its caller that it was completed + /// or dismissed midway (_actions are free to return whatever they want_), + /// Android and macOS only record if the user selected an action or outright + /// dismissed the share-sheet. /// /// **Currently only implemented on IOS, Android and macOS.** + /// + /// Will gracefully fall back to the non result variant if not implemented + /// for the current environment and return [ShareResult.unavailable]. static Future shareFilesWithResult( List paths, { List? mimeTypes, From c639fa8aa1cc74771c541782c5e056ae4d216021 Mon Sep 17 00:00:00 2001 From: Rubin Raithel <33808743+Coronon@users.noreply.github.com> Date: Wed, 23 Mar 2022 18:35:39 +0100 Subject: [PATCH 4/4] [share_plus] improve clarity --- docs/share_plus/usage.mdx | 18 +++++++++++++++++ packages/share_plus/share_plus/CHANGELOG.md | 2 +- .../plus/share/MethodCallHandler.kt | 20 +++++++++---------- .../share_plus/share_plus/lib/share_plus.dart | 6 ++++-- .../CHANGELOG.md | 2 +- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/docs/share_plus/usage.mdx b/docs/share_plus/usage.mdx index 3dec4c1ec6..d7683e120f 100644 --- a/docs/share_plus/usage.mdx +++ b/docs/share_plus/usage.mdx @@ -35,3 +35,21 @@ To share one or multiple files invoke the static `shareFiles` method anywhere in Share.shareFiles(['${directory.path}/image.jpg'], text: 'Great picture'); Share.shareFiles(['${directory.path}/image1.jpg', '${directory.path}/image2.jpg']); ``` + +If you are interested in the action your user performed with the share sheet, you can instead use the `shareWithResult` and `shareFilesWithResult` methods. + +```dart +final result = await Share.shareWithResult('check out my website https://example.com'); + +if (result.status != ShareResultStatus.success) { + print('thank you for sharing my website!'); +} +``` + +```dart +final result = await Share.shareFilesWithResult(['${directory.path}/image.jpg'], text: 'Great picture'); + +if (result.status == ShareResultStatus.dismissed) { + print('did you not like the picture?'); +} +``` diff --git a/packages/share_plus/share_plus/CHANGELOG.md b/packages/share_plus/share_plus/CHANGELOG.md index 2e8861ded2..39f9141699 100644 --- a/packages/share_plus/share_plus/CHANGELOG.md +++ b/packages/share_plus/share_plus/CHANGELOG.md @@ -1,7 +1,7 @@ ## 4.0.3 - Android: Revert increased minSdkVersion back to 16 -- Gracefully fall back to normal share methods on not supported platforms +- Gracefully fall back from `shareWithResult` to regular `share` methods on unsupported platforms - Improve documentation for `shareWithResult` methods ## 4.0.2 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 478924d391..b2baad9346 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 @@ -13,24 +13,24 @@ internal class MethodCallHandler( override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { // The user used a *WithResult method - val calledWithResult = call.method.endsWith("WithResult") + val isResultRequested = call.method.endsWith("WithResult") // We don't attempt to return a result if the current API version doesn't support it - val withResult = calledWithResult && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 + val isWithResult = isResultRequested && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 when (call.method) { "share", "shareWithResult" -> { expectMapArguments(call) - if (withResult && !manager.setCallback(result)) return + if (isWithResult && !manager.setCallback(result)) return // Android does not support showing the share sheet at a particular point on screen. share.share( call.argument("text") as String, call.argument("subject") as String?, - withResult, + isWithResult, ) - if (!withResult) { - if (calledWithResult) { + if (!isWithResult) { + if (isResultRequested) { result.success("dev.fluttercommunity.plus/share/unavailable") } else { result.success(null) @@ -39,7 +39,7 @@ internal class MethodCallHandler( } "shareFiles", "shareFilesWithResult" -> { expectMapArguments(call) - if (withResult && !manager.setCallback(result)) return + if (isWithResult && !manager.setCallback(result)) return // Android does not support showing the share sheet at a particular point on screen. try { @@ -48,11 +48,11 @@ internal class MethodCallHandler( call.argument?>("mimeTypes"), call.argument("text"), call.argument("subject"), - withResult, + isWithResult, ) - if (!withResult) { - if (calledWithResult) { + if (!isWithResult) { + if (isResultRequested) { result.success("dev.fluttercommunity.plus/share/unavailable") } else { result.success(null) diff --git a/packages/share_plus/share_plus/lib/share_plus.dart b/packages/share_plus/share_plus/lib/share_plus.dart index 2168dea66f..ed206d137c 100644 --- a/packages/share_plus/share_plus/lib/share_plus.dart +++ b/packages/share_plus/share_plus/lib/share_plus.dart @@ -92,7 +92,8 @@ class Share { /// While on IOS the selected action can inform its caller that it was completed /// or dismissed midway (_actions are free to return whatever they want_), /// Android and macOS only record if the user selected an action or outright - /// dismissed the share-sheet. + /// dismissed the share-sheet. It is not guaranteed that the user actually shared + /// something. /// /// **Currently only implemented on IOS, Android and macOS.** /// @@ -121,7 +122,8 @@ class Share { /// While on IOS the selected action can inform its caller that it was completed /// or dismissed midway (_actions are free to return whatever they want_), /// Android and macOS only record if the user selected an action or outright - /// dismissed the share-sheet. + /// dismissed the share-sheet. It is not guaranteed that the user actually shared + /// something. /// /// **Currently only implemented on IOS, Android and macOS.** /// diff --git a/packages/share_plus/share_plus_platform_interface/CHANGELOG.md b/packages/share_plus/share_plus_platform_interface/CHANGELOG.md index 752b2a2035..8d5901fd58 100644 --- a/packages/share_plus/share_plus_platform_interface/CHANGELOG.md +++ b/packages/share_plus/share_plus_platform_interface/CHANGELOG.md @@ -1,6 +1,6 @@ ## 3.0.2 -- Gracefully fall back to normal share methods on not supported platforms +- Gracefully fall back from `shareWithResult` to regular `share` methods on unsupported platforms ## 3.0.1