From 496f153ce7898278138767f730810e249f1f81ad Mon Sep 17 00:00:00 2001 From: Coronon <33808743+Coronon@users.noreply.github.com> Date: Fri, 28 Oct 2022 22:41:21 +0200 Subject: [PATCH 1/3] fix(share_plus): return correct share result on android --- .../android/src/main/AndroidManifest.xml | 9 ++++ .../dev/fluttercommunity/plus/share/Share.kt | 10 ++--- .../plus/share/SharePlusPendingIntent.kt | 43 +++++++++++++++++++ .../plus/share/SharePlusPlugin.kt | 2 - .../plus/share/ShareSuccessManager.kt | 34 ++++----------- 5 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt diff --git a/packages/share_plus/share_plus/android/src/main/AndroidManifest.xml b/packages/share_plus/share_plus/android/src/main/AndroidManifest.xml index 8bbbe44d82..40801f1d83 100644 --- a/packages/share_plus/share_plus/android/src/main/AndroidManifest.xml +++ b/packages/share_plus/share_plus/android/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + + + + + + + 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 e2c1d3248b..9375657953 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 @@ -33,7 +33,7 @@ internal class Share( */ private val immutabilityIntentFlags: Int by lazy { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - PendingIntent.FLAG_IMMUTABLE + PendingIntent.FLAG_MUTABLE } else { 0 } @@ -71,9 +71,9 @@ internal class Share( PendingIntent.getBroadcast( context, 0, - Intent(ShareSuccessManager.BROADCAST_CHANNEL), + Intent(context, SharePlusPendingIntent::class.java), PendingIntent.FLAG_UPDATE_CURRENT or immutabilityIntentFlags - ).intentSender + ).getIntentSender() ) } else { Intent.createChooser(shareIntent, null /* dialog title optional */) @@ -129,9 +129,9 @@ internal class Share( PendingIntent.getBroadcast( context, 0, - Intent(ShareSuccessManager.BROADCAST_CHANNEL), + Intent(context, SharePlusPendingIntent::class.java), PendingIntent.FLAG_UPDATE_CURRENT or immutabilityIntentFlags - ).intentSender + ).getIntentSender() ) } else { Intent.createChooser(shareIntent, null /* dialog title optional */) diff --git a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt new file mode 100644 index 0000000000..a3b035a411 --- /dev/null +++ b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt @@ -0,0 +1,43 @@ +package dev.fluttercommunity.plus.share + +import android.content.* +import android.os.Build + +/** + * This helper class allows us to use FLAG_MUTABLE on the PendingIntent used in the Share class, + * as it allows us to make the underlying Intent explicit, therefore avoiding any risks an implicit + * mutable Intent may carry. + * + * When the PendingIntent is sent, the system will instantiate this class and call `onReceive` on it. + */ +internal class SharePlusPendingIntent: BroadcastReceiver() { + /** + * Companion object to achieve static behaviour. + */ + companion object { + @JvmField + /** + * Static result to access the result of the system instantiated instance + */ + var result: String = "" + } + + /** + * Handler called after an action was chosen. Called only on success. + */ + override fun onReceive(context: Context, intent: Intent) { + // Extract chosen ComponentName + val chosenComponent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // Only available from API level 33 onwards + intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT, ComponentName::class.java) + } else { + // Deprecated in API level 33 + intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT) + } + + // Unambiguously identify the chosen action + if (chosenComponent != null) { + result = chosenComponent.flattenToString() + } + } +} diff --git a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPlugin.kt b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPlugin.kt index b3b831ed10..d53a508ddb 100644 --- a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPlugin.kt +++ b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPlugin.kt @@ -15,14 +15,12 @@ class SharePlusPlugin : FlutterPlugin, ActivityAware { override fun onAttachedToEngine(binding: FlutterPluginBinding) { methodChannel = MethodChannel(binding.binaryMessenger, CHANNEL) manager = ShareSuccessManager(binding.applicationContext) - manager.register() share = Share(context = binding.applicationContext, activity = null, manager = manager) val handler = MethodCallHandler(share, manager) methodChannel.setMethodCallHandler(handler) } override fun onDetachedFromEngine(binding: FlutterPluginBinding) { - manager.discard() methodChannel.setMethodCallHandler(null) } diff --git a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/ShareSuccessManager.kt b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/ShareSuccessManager.kt index 36e1a4c50e..3ac7116f0b 100644 --- a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/ShareSuccessManager.kt +++ b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/ShareSuccessManager.kt @@ -9,31 +9,18 @@ import java.util.concurrent.atomic.AtomicBoolean * Handles the callback based status information about a successful or dismissed * share. Used to link multiple different callbacks together for easier use. */ -internal class ShareSuccessManager(private val context: Context) : BroadcastReceiver(), - ActivityResultListener { +internal class ShareSuccessManager(private val context: Context) : ActivityResultListener { private var callback: MethodChannel.Result? = null private var isCalledBack: AtomicBoolean = AtomicBoolean(true) - /** - * Register listener. Must be called before any share sheet is opened. - */ - fun register() { - context.registerReceiver(this, IntentFilter(BROADCAST_CHANNEL)) - } - - /** - * Deregister listener. Must be called before the base activity is invalidated. - */ - fun discard() { - context.unregisterReceiver(this) - } - /** * Set result callback that will wait for the share-sheet to close and get either * the componentname of the chosen option or an empty string on dismissal. */ fun setCallback(callback: MethodChannel.Result): Boolean { return if (isCalledBack.compareAndSet(true, false)) { + // Prepare all state for new share + SharePlusPendingIntent.result = "" isCalledBack.set(false) this.callback = callback true @@ -51,7 +38,7 @@ internal class ShareSuccessManager(private val context: Context) : BroadcastRece * Must be called if `.startActivityForResult` is not available to avoid deadlocking. */ fun unavailable() { - returnResult("dev.fluttercommunity.plus/share/unavailable") + returnResult(RESULT_UNAVAILABLE) } /** @@ -70,7 +57,7 @@ internal class ShareSuccessManager(private val context: Context) : BroadcastRece */ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { return if (requestCode == ACTIVITY_CODE) { - returnResult("") + returnResult(SharePlusPendingIntent.result) true } else { false @@ -78,16 +65,11 @@ internal class ShareSuccessManager(private val context: Context) : BroadcastRece } /** - * Handler called after a sharesheet was closed. Called only on success. + * Companion object holds constants used throughout the plugin when attempting to return + * the share result. */ - override fun onReceive(context: Context, intent: Intent) { - returnResult( - intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT).toString() - ) - } - companion object { - const val BROADCAST_CHANNEL = "dev.fluttercommunity.plus/share/success" const val ACTIVITY_CODE = 17062003 + const val RESULT_UNAVAILABLE = "dev.fluttercommunity.plus/share/unavailable" } } From eee78eafc4324509470cfdfb6b872f443706b5a0 Mon Sep 17 00:00:00 2001 From: Coronon <33808743+Coronon@users.noreply.github.com> Date: Fri, 28 Oct 2022 22:41:40 +0200 Subject: [PATCH 2/3] docs(share_plus): improve file_path.xml documentation --- .../android/src/main/res/xml/flutter_share_file_paths.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/share_plus/share_plus/android/src/main/res/xml/flutter_share_file_paths.xml b/packages/share_plus/share_plus/android/src/main/res/xml/flutter_share_file_paths.xml index 4e78448e9e..cb820aec00 100644 --- a/packages/share_plus/share_plus/android/src/main/res/xml/flutter_share_file_paths.xml +++ b/packages/share_plus/share_plus/android/src/main/res/xml/flutter_share_file_paths.xml @@ -1,4 +1,5 @@ - - + + + From 488a27c5a6ca2cadb1a27591b5c17a1986cbd8b1 Mon Sep 17 00:00:00 2001 From: Coronon <33808743+Coronon@users.noreply.github.com> Date: Sat, 29 Oct 2022 15:00:30 +0200 Subject: [PATCH 3/3] style(share_plus): adapt to Kotlin style and enhance comments --- .../main/kotlin/dev/fluttercommunity/plus/share/Share.kt | 4 ++-- .../fluttercommunity/plus/share/SharePlusPendingIntent.kt | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) 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 9375657953..95cfca5f06 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 @@ -73,7 +73,7 @@ internal class Share( 0, Intent(context, SharePlusPendingIntent::class.java), PendingIntent.FLAG_UPDATE_CURRENT or immutabilityIntentFlags - ).getIntentSender() + ).intentSender ) } else { Intent.createChooser(shareIntent, null /* dialog title optional */) @@ -131,7 +131,7 @@ internal class Share( 0, Intent(context, SharePlusPendingIntent::class.java), PendingIntent.FLAG_UPDATE_CURRENT or immutabilityIntentFlags - ).getIntentSender() + ).intentSender ) } else { Intent.createChooser(shareIntent, null /* dialog title optional */) diff --git a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt index a3b035a411..284ccd507a 100644 --- a/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt +++ b/packages/share_plus/share_plus/android/src/main/kotlin/dev/fluttercommunity/plus/share/SharePlusPendingIntent.kt @@ -11,13 +11,9 @@ import android.os.Build * When the PendingIntent is sent, the system will instantiate this class and call `onReceive` on it. */ internal class SharePlusPendingIntent: BroadcastReceiver() { - /** - * Companion object to achieve static behaviour. - */ companion object { - @JvmField /** - * Static result to access the result of the system instantiated instance + * Static member to access the result of the system instantiated instance */ var result: String = "" }