aws-amplify / amplify-android

The fastest and easiest way to use AWS from your Android app.
https://docs.amplify.aws/lib/q/platform/android/
Apache License 2.0
247 stars 117 forks source link

Is there a way to force signInWithWebUI to always use Chrome? #2878

Closed tfreeman82 closed 3 months ago

tfreeman82 commented 3 months ago

We are receiving reports from customers that the signInWithWebUI call isn't initiating a browser session or showing any activity. We suspect this might be due to our application being set as the default web browser in their device settings, but we are currently awaiting confirmation of this.

How does Amplify determine which web browser to utilize for the signInWithWebUI functionality? Also, is there a way to ensure that Amplify always uses Chrome?

mattcreaser commented 3 months ago

Hi @tfreeman82. By default signInWithWebUi will use the system default app to handle the intent, so you're probably right that your users have an incorrect app set as the default.

It is possible to explicitly specify the package to use like this:

    val options = AWSCognitoAuthWebUISignInOptions.builder()
        .browserPackage("setPackageNameHere")
        .build()

    Amplify.Auth.signInWithWebUI(activity, options, { /* success */ }, { /* error */ })

Hope that helps. Please let us know if you have any other questions.

tfreeman82 commented 3 months ago

Ok, I just implemented your suggestion, passing in the chrome package name. It tries to open chrome but the application closes with no crash reported in the logcat.

Here's a screen recording of what's happening. https://github.com/user-attachments/assets/d3fcdaf1-bff3-48f5-98b0-811b5b29a080

tfreeman82 commented 3 months ago

When I install Firefox and change the package name to force it to use that, it works fine. The issue seems to be only with Chrome.

tylerjroach commented 3 months ago

@tfreeman82 Before digging further into the issue, I wanted to make sure its not assumed that all devices have Chrome installed. It would be best to have some fallback logic to attempt other browsers if Chrome is not available.

In the video you posted, it appears that a Chrome custom tab is being displayed. I can't tell what is happening after that. It almost looks like the redirect may be received (if you were already logged in on Chrome).

Can you add AndroidLoggingPlugin(LogLevel.VERBOSE) as the first configured Amplify plugin, and then post logs Amplify logs for a sign in attempt. That should help us figure out what is happening.

tfreeman82 commented 3 months ago

@tylerjroach I was hoping it would be as easy as to assume Chrome can't be uninstalled but didn't expect it to be. My backup concept would be to find a way to query the system for any browser applications installed and force one from the list.

I added the logging plugin and ran through the steps. These are the amplify logs.

_2024-07-30 12:19:21.284 27167-27252 amplify:aw...AuthPlugin V Auth State Change: Configured(authNState=SigningOut(signOutState=NotStarted(id=)), authZState=Configured(id=))

2024-07-30 12:19:21.284 27167-27243 amplify:aw...AuthPlugin V InitSignOut Starting execution

2024-07-30 12:19:21.285 27167-27243 amplify:aw...AuthPlugin V InitSignOut Sending event SignOutLocally

2024-07-30 12:19:21.289 27167-27252 amplify:aw...AuthPlugin V Auth State Change: Configured(authNState=SigningOut(signOutState=SigningOutLocally(signedInData=null)), authZState=Configured(id=))

2024-07-30 12:19:21.290 27167-27243 amplify:aw...AuthPlugin V LocalSignOut Starting execution

2024-07-30 12:19:21.290 27167-27243 amplify:aw...AuthPlugin V LocalSignOut Sending event SignedOutSuccess

2024-07-30 12:19:21.290 27167-27252 amplify:aw...AuthPlugin V Auth State Change: Configured(authNState=SignedOut(signedOutData=SignedOutData(lastKnownUsername=null, hostedUIErrorData=null, globalSignOutErrorData=null, revokeTokenErrorData=null)), authZState=Configured(id=))

2024-07-30 12:19:21.291 27167-27242 Marketscape CRM D cognito signout success

2024-07-30 12:19:21.797 27167-27252 amplify:aw...AuthPlugin V Auth State Change: Configured(authNState=SigningIn(signInState=NotStarted(id=)), authZState=SigningIn(id=))

2024-07-30 12:19:21.797 27167-27254 amplify:aw...AuthPlugin V InitiateSignInAction Starting execution

2024-07-30 12:19:21.798 27167-27254 amplify:aw...AuthPlugin V InitiateSignInAction Sending event InitiateHostedUISignIn

2024-07-30 12:19:21.798 27167-27252 amplify:aw...AuthPlugin V Auth State Change: Configured(authNState=SigningIn(signInState=SigningInWithHostedUI(hostedUISignInState=NotStarted(id=))), authZState=SigningIn(id=)) 2024-07-30 12:19:21.799 27167-27254 amplify:aw...AuthPlugin V StartHostedUIAuth Starting execution

2024-07-30 12:19:21.799 27167-27254 amplify:aw...AuthPlugin V StartHostedUIAuth Sending event ShowHostedUI

2024-07-30 12:19:21.800 27167-27252 amplify:aw...AuthPlugin V Auth State Change: Configured(authNState=SigningIn(signInState=SigningInWithHostedUI(hostedUISignInState=ShowingUI(hostedUIOptions=HostedUIOptions(callingActivity= .ui.base.MainActivity@7701b8b, scopes=[], providerInfo=HostedUIProviderInfo(authProvider=null, idpIdentifier=null), browserPackage=com.android.chrome)))), authZState=SigningIn(id=))

2024-07-30 12:19:21.800 27167-27254 amplify:aw...AuthPlugin V InitHostedUIAuth Starting execution_

tylerjroach commented 3 months ago

Are there no logs after 2024-07-30 12:19:21.800 27167-27254 amplify:aw...AuthPlugin V InitHostedUIAuth Starting execution_?

Is the app crashing or just going into the background?

It would be helpful to see what is logged after that line? If that is the last log, I'll try and reproduce by setting my sample app as the default app for web browsing (I've never observed this scenario before).

tfreeman82 commented 3 months ago

I just ran it again and these are the logs for the next several lines in the logcat. They're mostly Pendo, OneSignal, or LeakCanary logs. The app closes in a way that makes it look like it shrinks back into the app icon but there's no indication of a crash in the logcat or any of our crash tracking solutions.

_2024-07-30 15:39:57.436 31842-31842 OneSignal D onActivityPaused: .ui.base.MainActivity@e4d5c6a

2024-07-30 15:39:57.436 31842-31842 OneSignal D ActivityLifecycleHandler Handling lost focus

2024-07-30 15:39:57.437 31842-31842 OneSignal D curActivity is NOW: null

2024-07-30 15:39:57.438 31842-32067 OneSignal D Application stopped focus time: 112817649 timeElapsed: 40

2024-07-30 15:39:57.438 31842-32067 OneSignal D FocusTimeProcessorUnattributed:saveUnsentActiveData with lastFocusTimeInfluences: [SessionInfluence{influenceChannel=iam, influenceType=DISABLED, ids=null}, SessionInfluence{influenceChannel=notification, influenceType=DISABLED, ids=null}]

2024-07-30 15:39:57.438 31842-32067 OneSignal D FocusTimeProcessorUnattributed:getUnsentActiveTime: 50

2024-07-30 15:39:57.438 31842-32067 OneSignal D FocusTimeProcessorUnattributed:saveUnsentActiveTime: 90

2024-07-30 15:39:57.446 31842-31842 PingHandler D stop ping 2024-07-30 15:39:57.494 31842-31842 OneSignal D onActivityResumed: com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity@18d4e34

2024-07-30 15:39:57.494 31842-31842 OneSignal D curActivity is NOW: com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity:com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity@18d4e34

2024-07-30 15:39:57.494 31842-31842 OneSignal D ActivityLifecycleHandler handleFocus, nextResumeIsFirstActivity: false

2024-07-30 15:39:57.494 31842-31842 OneSignal D ActivityLifecycleHandler cancel background lost focus worker

2024-07-30 15:39:57.512 31842-31907 Pendo W ScreenManager onActivityResumed -> root view is null

2024-07-30 15:39:57.633 31842-31842 OneSignal D onActivityPaused: com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity@18d4e34

2024-07-30 15:39:57.633 31842-31842 OneSignal D ActivityLifecycleHandler Handling lost focus

2024-07-30 15:39:57.633 31842-31842 OneSignal D curActivity is NOW: null

2024-07-30 15:39:57.634 31842-32070 OneSignal D Application stopped focus time: 112817649 timeElapsed: 40

2024-07-30 15:39:57.634 31842-32070 OneSignal D FocusTimeProcessorUnattributed:saveUnsentActiveData with lastFocusTimeInfluences: [SessionInfluence{influenceChannel=iam, influenceType=DISABLED, ids=null}, SessionInfluence{influenceChannel=notification, influenceType=DISABLED, ids=null}]

2024-07-30 15:39:57.634 31842-32070 OneSignal D FocusTimeProcessorUnattributed:getUnsentActiveTime: 90

2024-07-30 15:39:57.634 31842-32070 OneSignal D FocusTimeProcessorUnattributed:saveUnsentActiveTime: 130

2024-07-30 15:39:57.638 31842-31938 EGL_emulation D app_time_stats: avg=5449.38ms min=3.06ms max=38104.22ms count=7

2024-07-30 15:39:58.252 31842-31889 TrafficStats D tagSocket(215) with statsTag=0xffffffff, statsUid=-1 2024-07-30 15:39:58.440 31842-31842 VRI[MainActivity] D visibilityChanged oldVisibility=true newVisibility=false

2024-07-30 15:39:58.441 31842-31842 VRI[MainActivity] D visibilityChanged oldVisibility=true newVisibility=false

2024-07-30 15:39:58.478 31842-31842 MediaPlayer V resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false

2024-07-30 15:39:58.478 31842-31842 MediaPlayer V cleanDrmObj: mDrmObj=null mDrmSessionId=null

2024-07-30 15:39:58.478 31842-31842 MediaPlayer V resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false

2024-07-30 15:39:58.478 31842-31842 MediaPlayer V cleanDrmObj: mDrmObj=null mDrmSessionId=null

2024-07-30 15:39:59.087 31842-31842 OneSignal D onActivityStopped: com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity@18d4e34

2024-07-30 15:39:59.087 31842-31842 OneSignal D curActivity is NOW: null

2024-07-30 15:39:59.087 31842-31842 OneSignal D Running destroyTimeout with runnable: com.onesignal.OSFocusHandler$$ExternalSyntheticLambda0@7aa628f

2024-07-30 15:39:59.087 31842-31842 OneSignal D Running startTimeout with timeout: 1500 and runnable: com.onesignal.OSFocusHandler$$ExternalSyntheticLambda0@7aa628f

2024-07-30 15:39:59.090 31842-31842 LeakCanary D Watching instance of androidx.lifecycle.ReportFragment (androidx.lifecycle.ReportFragment received Fragment#onDestroy() callback) with key d27ee794-ada8-44d0-a9fc-c225c63115f3

2024-07-30 15:39:59.091 31842-31842 LeakCanary D Watching instance of com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity (com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity received Activity#onDestroy() callback) with key 91c64905-f9fe-45e3-989d-7640b7fcbef3

2024-07-30 15:39:59.091 31842-31842 OneSignal D onActivityDestroyed: com.amplifyframework.auth.cognito.activities.CustomTabsManagerActivity@18d4e34

2024-07-30 15:39:59.091 31842-31842 OneSignal D curActivity is NOW: null_

tylerjroach commented 3 months ago

Given the uniqueness of your implementation, can you share more information on your manifest configuration.

For example, when checking for which package to use as the default browser, we check that it has custom tab service support for CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION: https://github.com/aws-amplify/amplify-android/blob/825f02f532208ed9e0985ac39dabb1c9c980c717/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/BrowserHelper.kt#L60

I'm attempting to modify a sample app that I use to replicate the behavior you are seeing.

tfreeman82 commented 3 months ago

In our manifest, we have the amplify activity required for the hosted ui:

<activity
            android:name="com.amplifyframework.auth.cognito.activities.HostedUIRedirectActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="playmaker" />
            </intent-filter>
        </activity>

Our main activity:

<activity
            android:name=".ui.base.MainActivity"
            android:configChanges="orientation|screenSize|keyboardHidden"
            android:exported="true"
            android:theme="@style/Theme.App.Starting">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <nav-graph android:value="@navigation/navigation" />

            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="${host}"
                    android:scheme="https" />
            </intent-filter>
        </activity>

and an activity for Pendo:

<activity
            android:name="sdk.pendo.io.activities.PendoGateActivity"
            android:exported="true"
            android:launchMode="singleInstance">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="pendo-********" />
            </intent-filter>
        </activity>

We also have one intent listed in the queries tag

 <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="https" />
        </intent>

I've been trying to find a way to remove our application as an option in the device default browser settings since that seems to be the primary cause of our users issues. As far as I can tell, our Android app links implementation is causing it to show up.

tylerjroach commented 3 months ago

@tfreeman82 What activity is used to call signInWithWebUI? I see some of your activities have a launchMode type of singleInstance which can be problematic due to a bug with Android 14 (https://github.com/aws-amplify/aws-sdk-android/issues/3530#issuecomment-1944149153). Can you change the launchMode to try and test. If the issue resolves itself after changing the launchMode, but you determine that singleInstance is still necessary for your use case, see the workaround I proposed in that link. It is written for our AWS Android SDK, but the AuthLauncherActivity wrapper would still be relevant.

If this doesn't appear to be the problem, can I get a bit more information.

  1. Does this issue only happen if your app is set as default browser? What if Chrome is the devices default browser? Do you still see the issue?
  2. Can you clear app data for both your app and chrome, then post another video of attempting to sign in. I would expect to see the Chrome intro screen show, and your sign in attempt. Its hard to tell from the video if a previous sign in session is trying to redirect back into the application, or if the chrome tab is closing for some other reason.
tfreeman82 commented 3 months ago

@tylerjroach MainActivity is the only one we have. The PendoGateActivity, where you see the launchMode, is what their SDK says we need to have for page tagging and guide testing capabilities. The only other activity we have listed is the one required for the hosted web UI.

I removed the launch mode completely and ran through the steps again but got the same result.

I cleared the app data for ours and Chrome and ran through the steps again for this screen recording. The initial press of our SSO button does launch Chrome. Chrome runs through the initial setup screens again, then immediately redirects back to our app. After that point, the SSO button does nothing until I reinstall our application.

I've only seen this issue when our application is set as the default browser and I try to force Chrome as the web UI browser. It's been a little while since I tried the steps with Firefox, so I can do that next.

As I stated before, the primary cause of this issue is the fact that our application is showing up as an option in the device settings for default browser. If I can figure out why that's happening and address it, this entire thing becomes unnecessary.

Is there anything that you know of within the Amplify auth dependencies that might cause our app to show as a default browser option?

https://github.com/user-attachments/assets/b148808d-8918-43c3-bf34-18b8f7e031b6

tylerjroach commented 3 months ago

As I stated before, the primary cause of this issue is the fact that our application is showing up as an option in the device settings for default browser. If I can figure out why that's happening and address it, this entire thing becomes unnecessary.

I would take a look at the generated manifest thats actually used in your application.

In quick testing on my device it takes both

<data android:scheme="http" />
<data android:scheme="https"/>

to list my app in the defaults screen. As soon as a host is added, it no longer shows in the list.

I'm not sure why your app would be showing as a default-able browser, but Amplify would not be adding anything to the manifest that would do this (check other SDKs).

I see your web login is labeled as SSO. Is Cognito redirecting to a login url that matches your app's host in the manifest? If so, that could be the conflict. Something outside of Amplify is interfering here because you aren't even being given the chance to type in your credentials in the custom tab browser that is launched.

tylerjroach commented 3 months ago

One quick thing to add to the above, is your app showing in the global default screen in the settings, or is the default prompt displaying during any part of the sign in flow? Your app will be allowable as default for the "host" that you provided since it is included in the manifest.

tfreeman82 commented 3 months ago

The app is showing in the global default settings screen and does not have any type of prompt to set it as a default browser.

We're using a SignInRedirectURI and SignOutRedirectURI that is unique to our application using the app://signin & app://signout format. This redirect url matches the scheme set in the manifest for the HostedUIRedirectActivity

tfreeman82 commented 3 months ago

I was looking through the merged manifest yesterday and going through dependencies one at a time when I saw that the was-auth-cognito dependency does reference but I'm not sure if this could be related to what we're experiencing. I didn't find any other dependencies that use a scheme at all.

The only other possible cause I can think of would be our Android App Links implementation in our navigation graph xml.

Screenshot 2024-08-01 at 9 43 33 AM

tylerjroach commented 3 months ago

I downloaded your app and inspected the manifest and you have an intent-filter that is missing a host. This is why it is showing as a default browser option.

<intent-filter
    android:autoVerify="true">

    <action
        android:name="android.intent.action.VIEW" />

    <category
        android:name="android.intent.category.DEFAULT" />

    <category
        android:name="android.intent.category.BROWSABLE" />

    <data
        android:scheme="http" />

    <data
        android:scheme="https" />

    <data
        android:pathPrefix="/getView/id," />
</intent-filter>
tfreeman82 commented 3 months ago

I just went through our navigation xml deep links, commented them all out, and added them back one by one until the application showed back up as a default option. I was able to confirm which one is causing the issue and only need to figure out why it's causing the issue.

I still don't understand why forcing Chrome as the browser for our hosted UI is behaving like it is when our application is set as default browser but this gives me a solid path forward.

Thank you for your help solving this, I really appreciate it!

tylerjroach commented 3 months ago

No problem. I believe what is happening is that the SSO redirect from Cognito is attempting to open the link from the default browser (your app) not Chrome. While we can control the browser the CustomTab is launched from, we cannot control if the SSO page then tries to launch into a different browser. It appears that Firefox doesn't see this redirect as an opportunity to switch back out into the default browser.

github-actions[bot] commented 3 months ago

This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.

tylerjroach commented 3 months ago

@tfreeman82 I'm not sure if you saw, but I posted the one that was the issue and why (it was missing a host). I've gone ahead and closed this issue because I believe it is fully resolved once that is removed. If not, feel free to re-open.