Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Keep authentication on the same activity stack #156

Merged
merged 1 commit into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.linusu.flutter_web_auth_2

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.browser.customtabs.CustomTabsIntent

class AuthenticationManagementActivity(
) : Activity() {
companion object {
const val KEY_AUTH_STARTED: String = "authStarted"
const val KEY_AUTH_URI: String = "authUri"
const val KEY_AUTH_OPTION_INTENT_FLAGS: String = "authOptionsIntentFlags"
const val KEY_AUTH_OPTION_TARGET_PACKAGE: String = "authOptionsTargetPackage"

fun createResponseHandlingIntent(context: Context): Intent {
val intent = Intent(context, AuthenticationManagementActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
return intent
}
}
private var authStarted: Boolean = false
private lateinit var authenticationUri: Uri
private var intentFlags: Int = 0
private var targetPackage: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
extractState(intent.extras)
} else {
extractState(savedInstanceState)
}
}

override fun onResume() {
super.onResume()

if (!authStarted) {
val intent = CustomTabsIntent.Builder().build()
intent.intent.addFlags(intentFlags)

if (targetPackage != null) {
intent.intent.setPackage(targetPackage)
}
intent.launchUrl(this, authenticationUri)
authStarted = true
return
}
/* If the authentication was already started and we've returned here, the user either
* completed or cancelled authentication.
* Either way we want to return to our original flutter activity, so just finish here
*/
finish()
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent);
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean(KEY_AUTH_STARTED, authStarted)
outState.putParcelable(KEY_AUTH_URI, authenticationUri)
outState.putInt(KEY_AUTH_OPTION_INTENT_FLAGS, intentFlags)
outState.putString(
KEY_AUTH_OPTION_TARGET_PACKAGE,
targetPackage
)
}

private fun extractState(state: Bundle?) {
if (state == null) {
finish()
return
}
authStarted = state.getBoolean(KEY_AUTH_STARTED, false)
authenticationUri = state.getParcelable(KEY_AUTH_URI)!!
intentFlags = state.getInt(KEY_AUTH_OPTION_INTENT_FLAGS, 0)
targetPackage = state.getString(KEY_AUTH_OPTION_TARGET_PACKAGE)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class CallbackActivity : Activity() {
if (scheme != null) {
FlutterWebAuth2Plugin.callbacks.remove(scheme)?.success(url.toString())
}
finishAndRemoveTask()
startActivity(AuthenticationManagementActivity.createResponseHandlingIntent(this))
finish()
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.linusu.flutter_web_auth_2

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
Expand All @@ -9,16 +10,20 @@ import androidx.browser.customtabs.CustomTabsClient
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.BinaryMessenger
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 java.util.ArrayList

class FlutterWebAuth2Plugin(
private var context: Context? = null,
private var channel: MethodChannel? = null
) : MethodCallHandler, FlutterPlugin {
private var channel: MethodChannel? = null,
private var activity: Activity? = null,
) : MethodCallHandler, FlutterPlugin, ActivityAware {
companion object {
val callbacks = mutableMapOf<String, Result>()
}
Expand Down Expand Up @@ -46,17 +51,11 @@ class FlutterWebAuth2Plugin(
val options = call.argument<Map<String, Any>>("options")!!

callbacks[callbackUrlScheme] = resultCallback
val intent = CustomTabsIntent.Builder().build()
val keepAliveIntent = Intent(context, KeepAliveService::class.java)

intent.intent.addFlags(options["intentFlags"] as Int)
intent.intent.putExtra("android.support.customtabs.extra.KEEP_ALIVE", keepAliveIntent)

val targetPackage = findTargetBrowserPackageName(options)
if (targetPackage != null) {
intent.intent.setPackage(targetPackage)
}
intent.launchUrl(context!!, url)
activity?.startActivity(Intent(activity,AuthenticationManagementActivity::class.java).apply {
putExtra(AuthenticationManagementActivity.KEY_AUTH_URI,url)
putExtra(AuthenticationManagementActivity.KEY_AUTH_OPTION_INTENT_FLAGS, options["intentFlags"] as Int)
putExtra(AuthenticationManagementActivity.KEY_AUTH_OPTION_TARGET_PACKAGE, findTargetBrowserPackageName(options))
})
}

"cleanUpDanglingCalls" -> {
Expand All @@ -71,6 +70,22 @@ class FlutterWebAuth2Plugin(
}
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
}

override fun onDetachedFromActivityForConfigChanges() {
onDetachedFromActivity()
}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
onAttachedToActivity(binding)
}

override fun onDetachedFromActivity() {
activity = null
}

/**
* Find Support CustomTabs Browser.
*
Expand Down Expand Up @@ -145,5 +160,4 @@ class FlutterWebAuth2Plugin(
)
return value == packageName
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity android:name="com.linusu.flutter_web_auth_2.AuthenticationManagementActivity">
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
Expand Down
7 changes: 2 additions & 5 deletions flutter_web_auth_2/lib/src/options.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
/// Default intent flags for opening the custom tabs intent on Android.
/// This is essentially the same as
/// `FLAG_ACTIVITY_SINGLE_TOP | FLAG_ACTIVITY_NEW_TASK`.
const defaultIntentFlags = 1 << 29 | 1 << 28;
const defaultIntentFlags = 0;

/// "Ephemeral" intent flags for opening the custom tabs intent on Android.
/// This is essentially the same as
/// `FLAG_ACTIVITY_SINGLE_TOP | FLAG_ACTIVITY_NEW_TASK
/// | FLAG_ACTIVITY_NO_HISTORY`.
/// FLAG_ACTIVITY_NO_HISTORY`.
const ephemeralIntentFlags = defaultIntentFlags | 1 << 30;

/// Default HTML code that generates a nice callback page.
Expand Down