diff --git a/packages/sign_in_with_apple/CHANGELOG.md b/packages/sign_in_with_apple/CHANGELOG.md index fc411856..c4bbfb91 100644 --- a/packages/sign_in_with_apple/CHANGELOG.md +++ b/packages/sign_in_with_apple/CHANGELOG.md @@ -1,5 +1,6 @@ -## TBD +## 2.4.0 +- Manual closes of the Chrome Custom Tab on Android are now reported through a `SignInWithAppleAuthorizationException` with the `code` `AuthorizationErrorCode.canceled` (same as on iOS) - `AppleLogoPainter` is now exposed, so consumers can use it to build their own buttons ## 2.3.0 diff --git a/packages/sign_in_with_apple/android/src/main/kotlin/com/aboutyou/dart_packages/sign_in_with_apple/SignInWithApplePlugin.kt b/packages/sign_in_with_apple/android/src/main/kotlin/com/aboutyou/dart_packages/sign_in_with_apple/SignInWithApplePlugin.kt index c424c57c..c01ebdec 100644 --- a/packages/sign_in_with_apple/android/src/main/kotlin/com/aboutyou/dart_packages/sign_in_with_apple/SignInWithApplePlugin.kt +++ b/packages/sign_in_with_apple/android/src/main/kotlin/com/aboutyou/dart_packages/sign_in_with_apple/SignInWithApplePlugin.kt @@ -1,28 +1,29 @@ package com.aboutyou.dart_packages.sign_in_with_apple -import android.app.Activity; -import android.os.Bundle; -import androidx.annotation.NonNull; +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.annotation.NonNull +import androidx.browser.customtabs.CustomTabsIntent import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result +import io.flutter.plugin.common.PluginRegistry.ActivityResultListener import io.flutter.plugin.common.PluginRegistry.Registrar - -import android.net.Uri -import android.content.Intent -import androidx.browser.customtabs.CustomTabsIntent - -import io.flutter.embedding.engine.plugins.activity.ActivityAware -import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.flutter.Log /** SignInWithApplePlugin */ -public class SignInWithApplePlugin: FlutterPlugin, MethodCallHandler, ActivityAware { +public class SignInWithApplePlugin: FlutterPlugin, MethodCallHandler, ActivityAware, ActivityResultListener { + private val CUSTOM_TABS_REQUEST_CODE = 1001; + private var channel: MethodChannel? = null - var activity: Activity? = null - + var binding: ActivityPluginBinding? = null override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.aboutyou.dart_packages.sign_in_with_apple") @@ -58,7 +59,7 @@ public class SignInWithApplePlugin: FlutterPlugin, MethodCallHandler, ActivityAw when (call.method) { "isAvailable" -> result.success(true) "performAuthorizationRequest" -> { - val _activity = activity + val _activity = binding?.activity if (_activity == null) { result.error("MISSING_ACTIVITY", "Plugin is not attached to an activity", call.arguments) @@ -72,24 +73,30 @@ public class SignInWithApplePlugin: FlutterPlugin, MethodCallHandler, ActivityAw return } - SignInWithApplePlugin.lastAuthorizationRequestResult?.error("NEW_REQUEST", "A new request came in while this was still pending. The previous request (this one) was then cancelled.", null) - if (SignInWithApplePlugin.triggerMainActivityToHideChromeCustomTab != null) { - SignInWithApplePlugin.triggerMainActivityToHideChromeCustomTab!!() + lastAuthorizationRequestResult?.error("NEW_REQUEST", "A new request came in while this was still pending. The previous request (this one) was then cancelled.", null) + if (triggerMainActivityToHideChromeCustomTab != null) { + triggerMainActivityToHideChromeCustomTab!!() } - SignInWithApplePlugin.lastAuthorizationRequestResult = result - SignInWithApplePlugin.triggerMainActivityToHideChromeCustomTab = { - val notificationIntent = _activity.getPackageManager().getLaunchIntentForPackage(_activity.getPackageName()); + lastAuthorizationRequestResult = result + triggerMainActivityToHideChromeCustomTab = { + val notificationIntent = _activity.packageManager.getLaunchIntentForPackage(_activity.packageName); notificationIntent.setPackage(null) // Bring the Flutter activity back to the top, by popping the Chrome Custom Tab - notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP; _activity.startActivity(notificationIntent) } val builder = CustomTabsIntent.Builder(); val customTabsIntent = builder.build(); customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - customTabsIntent.launchUrl(_activity, Uri.parse(url)); + customTabsIntent.intent.data = Uri.parse(url) + + _activity.startActivityForResult( + customTabsIntent.intent, + CUSTOM_TABS_REQUEST_CODE, + customTabsIntent.startAnimationBundle + ) } else -> { result.notImplemented() @@ -98,7 +105,8 @@ public class SignInWithApplePlugin: FlutterPlugin, MethodCallHandler, ActivityAw } override fun onAttachedToActivity(binding: ActivityPluginBinding) { - activity = binding.activity + this.binding = binding + binding.addActivityResultListener(this) } override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { @@ -110,7 +118,23 @@ public class SignInWithApplePlugin: FlutterPlugin, MethodCallHandler, ActivityAw } override fun onDetachedFromActivity() { - activity = null + binding?.removeActivityResultListener(this) + binding = null + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { + if (requestCode == CUSTOM_TABS_REQUEST_CODE) { + val _lastAuthorizationRequestResult = lastAuthorizationRequestResult + + if (_lastAuthorizationRequestResult != null) { + _lastAuthorizationRequestResult.error("authorization-error/canceled", "The user closed the Custom Tab", null) + + lastAuthorizationRequestResult = null + triggerMainActivityToHideChromeCustomTab = null + } + } + + return false } } @@ -126,6 +150,8 @@ public class SignInWithAppleCallback: Activity { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + // Note: The order is important here, as we first need to send the data to Flutter and then close the custom tab + // That way we can detect a manually closed tab in `SignInWithApplePlugin.onActivityResult` (by detecting that we're still waiting on data) val lastAuthorizationRequestResult = SignInWithApplePlugin.lastAuthorizationRequestResult if (lastAuthorizationRequestResult != null) { lastAuthorizationRequestResult.success(intent?.data?.toString()) diff --git a/packages/sign_in_with_apple/example/pubspec.lock b/packages/sign_in_with_apple/example/pubspec.lock index 9f682690..cc58f077 100644 --- a/packages/sign_in_with_apple/example/pubspec.lock +++ b/packages/sign_in_with_apple/example/pubspec.lock @@ -136,7 +136,7 @@ packages: path: ".." relative: true source: path - version: "2.3.0" + version: "2.4.0" sky_engine: dependency: transitive description: flutter diff --git a/packages/sign_in_with_apple/lib/src/sign_in_with_apple.dart b/packages/sign_in_with_apple/lib/src/sign_in_with_apple.dart index d66715ce..74ad91ab 100644 --- a/packages/sign_in_with_apple/lib/src/sign_in_with_apple.dart +++ b/packages/sign_in_with_apple/lib/src/sign_in_with_apple.dart @@ -228,13 +228,17 @@ class SignInWithApple { }, ).toString(); - final result = await channel.invokeMethod( - 'performAuthorizationRequest', - { - 'url': uri, - }, - ); + try { + final result = await channel.invokeMethod( + 'performAuthorizationRequest', + { + 'url': uri, + }, + ); - return parseAuthorizationCredentialAppleIDFromDeeplink(Uri.parse(result)); + return parseAuthorizationCredentialAppleIDFromDeeplink(Uri.parse(result)); + } on PlatformException catch (exception) { + throw SignInWithAppleException.fromPlatformException(exception); + } } } diff --git a/packages/sign_in_with_apple/pubspec.yaml b/packages/sign_in_with_apple/pubspec.yaml index 86ce4332..d76e2cff 100644 --- a/packages/sign_in_with_apple/pubspec.yaml +++ b/packages/sign_in_with_apple/pubspec.yaml @@ -1,6 +1,6 @@ name: sign_in_with_apple description: Flutter bridge to initiate Sign in with Apple (on iOS, macOS, and Android). Includes support for keychain entries as well as signing in with an Apple ID. -version: 2.3.0 +version: 2.4.0 homepage: https://github.com/aboutyou/dart_packages/tree/master/packages/sign_in_with_apple repository: https://github.com/aboutyou/dart_packages