From 473a99514d4a9f55ac2214a5ae02e53116ba079e Mon Sep 17 00:00:00 2001 From: Thanh Truong Date: Mon, 15 Mar 2021 13:25:27 +0700 Subject: [PATCH 1/4] UIActivityViewController crashing on iPads --- ios/Classes/SocialSharePlugin.m | 44 ++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/ios/Classes/SocialSharePlugin.m b/ios/Classes/SocialSharePlugin.m index 94af5d1..743c407 100644 --- a/ios/Classes/SocialSharePlugin.m +++ b/ios/Classes/SocialSharePlugin.m @@ -290,23 +290,39 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([image isEqual:[NSNull null]] || [ image length] == 0 ){ //when image is not included NSArray *objectsToShare = @[content]; - UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil]; - UIViewController *controller =[UIApplication sharedApplication].keyWindow.rootViewController; - [controller presentViewController:activityVC animated:YES completion:nil]; - result([NSNumber numberWithBool:YES]); + UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil]; + UIViewController *controller =[UIApplication sharedApplication].keyWindow.rootViewController; + + // Check if user is on iPad and present popover + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { + if ([activityVC respondsToSelector:@selector(popoverPresentationController)]) { + activityVC.popoverPresentationController.sourceView = controller.view; + } + } + + [controller presentViewController:activityVC animated:YES completion:nil]; + result([NSNumber numberWithBool:YES]); }else{ //when image file is included NSFileManager *fileManager = [NSFileManager defaultManager]; - BOOL isFileExist = [fileManager fileExistsAtPath: image]; - UIImage *imgShare; - if (isFileExist) { - imgShare = [[UIImage alloc] initWithContentsOfFile:image]; - } - NSArray *objectsToShare = @[content, imgShare]; - UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil]; - UIViewController *controller =[UIApplication sharedApplication].keyWindow.rootViewController; - [controller presentViewController:activityVC animated:YES completion:nil]; - result([NSNumber numberWithBool:YES]); + BOOL isFileExist = [fileManager fileExistsAtPath: image]; + UIImage *imgShare; + if (isFileExist) { + imgShare = [[UIImage alloc] initWithContentsOfFile:image]; + } + NSArray *objectsToShare = @[content, imgShare]; + UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil]; + UIViewController *controller =[UIApplication sharedApplication].keyWindow.rootViewController; + + // Check if user is on iPad and present popover + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { + if ([activityVC respondsToSelector:@selector(popoverPresentationController)]) { + activityVC.popoverPresentationController.sourceView = controller.view; + } + } + + [controller presentViewController:activityVC animated:YES completion:nil]; + result([NSNumber numberWithBool:YES]); } } else if([@"checkInstalledApps" isEqualToString:call.method]){ From c355d09b3f4b64d3c4c2941a6997c3a138a71690 Mon Sep 17 00:00:00 2001 From: Thanh Truong Date: Sun, 27 Mar 2022 23:30:51 +0700 Subject: [PATCH 2/4] Update SocialSharePlugin.kt --- .../social_share/SocialSharePlugin.kt | 99 ++++++++++++------- 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/android/src/main/kotlin/com/shekarmudaliyar/social_share/SocialSharePlugin.kt b/android/src/main/kotlin/com/shekarmudaliyar/social_share/SocialSharePlugin.kt index 39a01c6..bd389c1 100644 --- a/android/src/main/kotlin/com/shekarmudaliyar/social_share/SocialSharePlugin.kt +++ b/android/src/main/kotlin/com/shekarmudaliyar/social_share/SocialSharePlugin.kt @@ -8,8 +8,9 @@ import android.net.Uri import android.os.Build import android.util.Log import androidx.annotation.NonNull -import androidx.annotation.RequiresApi -import androidx.core.content.ContextCompat.startActivity +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import androidx.core.content.FileProvider import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel @@ -18,19 +19,21 @@ import io.flutter.plugin.common.MethodChannel.Result import io.flutter.plugin.common.PluginRegistry.Registrar import java.io.File -/** SocialSharePlugin */ -class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { +class SocialSharePlugin:FlutterPlugin, MethodCallHandler, ActivityAware { + private lateinit var channel: MethodChannel + private var activity: Activity? = null + private var activeContext: Context? = null + private var context: Context? = null - companion object { - @JvmStatic - fun registerWith(registrar: Registrar) { - val channel = MethodChannel(registrar.messenger(), "social_share") - channel.setMethodCallHandler(SocialSharePlugin(registrar)) - } + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + context = flutterPluginBinding.applicationContext + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "social_share") + channel.setMethodCallHandler(this) } - @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { + activeContext = if (activity != null) activity!!.applicationContext else context!! + if (call.method == "shareInstagramStory") { //share on instagram story val stickerImage: String? = call.argument("stickerImage") @@ -39,29 +42,28 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { val backgroundTopColor: String? = call.argument("backgroundTopColor") val backgroundBottomColor: String? = call.argument("backgroundBottomColor") val attributionURL: String? = call.argument("attributionURL") - val file = File(registrar.activeContext().cacheDir,stickerImage) - val stickerImageFile = FileProvider.getUriForFile(registrar.activeContext(), registrar.activeContext().applicationContext.packageName + ".com.shekarmudaliyar.social_share", file) + val file = File(activeContext!!.cacheDir,stickerImage) + val stickerImageFile = FileProvider.getUriForFile(activeContext!!, activeContext!!.applicationContext.packageName + ".com.shekarmudaliyar.social_share", file) val intent = Intent("com.instagram.share.ADD_TO_STORY") intent.type = "image/*" intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.putExtra("interactive_asset_uri", stickerImageFile) if (backgroundImage!=null) { //check if background image is also provided - val backfile = File(registrar.activeContext().cacheDir,backgroundImage) - val backgroundImageFile = FileProvider.getUriForFile(registrar.activeContext(), registrar.activeContext().applicationContext.packageName + ".com.shekarmudaliyar.social_share", backfile) + val backfile = File(activeContext!!.cacheDir,backgroundImage) + val backgroundImageFile = FileProvider.getUriForFile(activeContext!!, activeContext!!.applicationContext.packageName + ".com.shekarmudaliyar.social_share", backfile) intent.setDataAndType(backgroundImageFile,"image/*") } - intent.putExtra("content_url", attributionURL) intent.putExtra("top_background_color", backgroundTopColor) intent.putExtra("bottom_background_color", backgroundBottomColor) - Log.d("", registrar.activity().toString()) + Log.d("", activity!!.toString()) // Instantiate activity and verify it will resolve implicit intent - val activity: Activity = registrar.activity() - activity.grantUriPermission("com.instagram.android", stickerImageFile, Intent.FLAG_GRANT_READ_URI_PERMISSION) - if (activity.packageManager.resolveActivity(intent, 0) != null) { - registrar.activeContext().startActivity(intent) + activity!!.grantUriPermission("com.instagram.android", stickerImageFile, Intent.FLAG_GRANT_READ_URI_PERMISSION) + if (activity!!.packageManager.resolveActivity(intent, 0) != null) { + activeContext!!.startActivity(intent) result.success("success") } else { result.success("error") @@ -74,22 +76,22 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { val attributionURL: String? = call.argument("attributionURL") val appId: String? = call.argument("appId") - val file = File(registrar.activeContext().cacheDir,stickerImage) - val stickerImageFile = FileProvider.getUriForFile(registrar.activeContext(), registrar.activeContext().applicationContext.packageName + ".com.shekarmudaliyar.social_share", file) + val file = File(activeContext!!.cacheDir,stickerImage) + val stickerImageFile = FileProvider.getUriForFile(activeContext!!, activeContext!!.applicationContext.packageName + ".com.shekarmudaliyar.social_share", file) val intent = Intent("com.facebook.stories.ADD_TO_STORY") intent.type = "image/*" intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.putExtra("com.facebook.platform.extra.APPLICATION_ID", appId) intent.putExtra("interactive_asset_uri", stickerImageFile) intent.putExtra("content_url", attributionURL) intent.putExtra("top_background_color", backgroundTopColor) intent.putExtra("bottom_background_color", backgroundBottomColor) - Log.d("", registrar.activity().toString()) + Log.d("", activity!!.toString()) // Instantiate activity and verify it will resolve implicit intent - val activity: Activity = registrar.activity() - activity.grantUriPermission("com.facebook.katana", stickerImageFile, Intent.FLAG_GRANT_READ_URI_PERMISSION) - if (activity.packageManager.resolveActivity(intent, 0) != null) { - registrar.activeContext().startActivity(intent) + activity!!.grantUriPermission("com.facebook.katana", stickerImageFile, Intent.FLAG_GRANT_READ_URI_PERMISSION) + if (activity!!.packageManager.resolveActivity(intent, 0) != null) { + activeContext!!.startActivity(intent) result.success("success") } else { result.success("error") @@ -103,8 +105,8 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { if (image!=null) { //check if image is also provided - val imagefile = File(registrar.activeContext().cacheDir,image) - val imageFileUri = FileProvider.getUriForFile(registrar.activeContext(), registrar.activeContext().applicationContext.packageName + ".com.shekarmudaliyar.social_share", imagefile) + val imagefile = File(activeContext!!.cacheDir,image) + val imageFileUri = FileProvider.getUriForFile(activeContext!!, activeContext!!.applicationContext.packageName + ".com.shekarmudaliyar.social_share", imagefile) intent.type = "image/*" intent.putExtra(Intent.EXTRA_STREAM,imageFileUri) } else { @@ -116,16 +118,17 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { //create chooser intent to launch intent //source: "share" package by flutter (https://github.com/flutter/plugins/blob/master/packages/share/) val chooserIntent: Intent = Intent.createChooser(intent, null /* dialog title optional */) + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - registrar.activeContext().startActivity(chooserIntent) + activeContext!!.startActivity(chooserIntent) result.success(true) } else if (call.method == "copyToClipboard") { //copies content onto the clipboard val content: String? = call.argument("content") - val clipboard =registrar.context().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clipboard =context!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("", content) - clipboard.primaryClip = clip + clipboard.setPrimaryClip(clip) result.success(true) } else if (call.method == "shareWhatsapp") { //shares content on WhatsApp @@ -135,7 +138,7 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { whatsappIntent.setPackage("com.whatsapp") whatsappIntent.putExtra(Intent.EXTRA_TEXT, content) try { - registrar.activity().startActivity(whatsappIntent) + activity!!.startActivity(whatsappIntent) result.success("true") } catch (ex: ActivityNotFoundException) { result.success("false") @@ -149,7 +152,7 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { intent.data = Uri.parse("sms:" ) intent.putExtra("sms_body", content) try { - registrar.activity().startActivity(intent) + activity!!.startActivity(intent) result.success("true") } catch (ex: ActivityNotFoundException) { result.success("false") @@ -164,7 +167,7 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { val intent = Intent(Intent.ACTION_VIEW) intent.data = Uri.parse(urlScheme) try { - registrar.activity().startActivity(intent) + activity!!.startActivity(intent) result.success("true") } catch (ex: ActivityNotFoundException) { result.success("false") @@ -178,7 +181,7 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { telegramIntent.setPackage("org.telegram.messenger") telegramIntent.putExtra(Intent.EXTRA_TEXT, content) try { - registrar.activity().startActivity(telegramIntent) + activity!!.startActivity(telegramIntent) result.success("true") } catch (ex: ActivityNotFoundException) { result.success("false") @@ -189,7 +192,7 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { //creating a mutable map of apps var apps:MutableMap = mutableMapOf() //assigning package manager - val pm: PackageManager =registrar.context().packageManager + val pm: PackageManager =context!!.packageManager //get a list of installed apps. val packages = pm.getInstalledApplications(PackageManager.GET_META_DATA) //intent to check sms app exists @@ -211,4 +214,24 @@ class SocialSharePlugin(private val registrar: Registrar): MethodCallHandler { result.notImplemented() } } + + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + } + + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + activity = binding.getActivity() + } + + override fun onDetachedFromActivityForConfigChanges() { + activity = null + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + activity = binding.activity + } + + override fun onDetachedFromActivity() { + activity = null + } } From 23970884ceddcd078ea69619fcadc8fa302241ba Mon Sep 17 00:00:00 2001 From: Thanh Truong Date: Sun, 27 Mar 2022 23:33:37 +0700 Subject: [PATCH 3/4] Update build.gradle --- android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 4f75b60..bb6aeb8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,14 +2,14 @@ group 'com.shekarmudaliyar.social_share' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.5.30' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:4.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } From 0f84c2b2ae4eaa941d6d31f5c4173273e050d7f4 Mon Sep 17 00:00:00 2001 From: Thanh Truong Date: Sun, 27 Mar 2022 23:37:25 +0700 Subject: [PATCH 4/4] Update AndroidManifest.xml --- android/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index d754bee..36967f7 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ +