registerForActivityResult callback isn't triggered

428 Views Asked by At

I'm trying to obtain an authorization code in order to exchange it for a token with AppAuth.

Inside a Fragment I registered an ActivityResultLauncher

private fun registerAuthResultLauncher(): ActivityResultLauncher<Intent> {
    return registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { //didn't call
            result: ActivityResult ->
        if (result.resultCode == Activity.RESULT_OK)
            when (val e = AuthorizationException.fromIntent(result.data)) {
                null -> authCode =
                    result.data?.let { innerIt -> AuthorizationResponse.fromIntent(innerIt) }
                else -> throw e
            }
        else
            Timber.e("Unsuccessful request: ${result.resultCode}")
    }
}

Then I assigned it to a variable

    private val authLauncher = registerAuthResultLauncher()

and launched from onCreateView after button was clicked

   private fun obtainAuthCode(): AuthorizationResponse? {
    val authIntent = authService.getAuthorizationRequestIntent(authRequest)
    val packageManager = requireContext().packageManager
    if (authIntent.resolveActivity(packageManager) != null)
        authLauncher.launch(authIntent)
    else
        Timber.e("No Intent available to handle the code retrieval")
    return authCode
}

However as title says, the code inside the lambda is unreachable.

In effect request isn't handled and authCode value remains null.

This is how an activity looks like inside a manifest

        <activity
        android:name="net.openid.appauth.RedirectUriReceiverActivity"
        android:exported="true"
        tools:node="replace">
        <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="https"
                android:host="myapp.example.com"
                android:path="/oauth2redirect"/>
        </intent-filter>
    </activity>
1

There are 1 best solutions below

0
ArkadiuszZiemian On

The problem was related to asynchrony. I had an additional function obtainAccessToken relying on a result from the lambda but I called them both in same click listener so lambda code had no chance to finish. In effect authCode remained null. To deal with this issue I called obtainAccessToken within lambda. I refactored the code since posting the question, notably I moved lambda to launchAuthRequest function. This is how both functions look now:

    fun launchAuthRequest(result: ActivityResult) {
    if (result.resultCode == Activity.RESULT_OK)
        when (val e = AuthorizationException.fromIntent(result.data)) {
            null -> {
                val authCode = AuthorizationResponse.fromIntent(result.data!!)
                authState.update(authCode, null)
                obtainAccessToken(authCode)
            }
            else -> throw e
        }
    else
        Timber.e("Unsuccessful request: ${result.resultCode}")
}

private fun obtainAccessToken(authCode: AuthorizationResponse?) {
    if (authCode == null)
        throw IllegalStateException("Authorization code wasn't retrieved successfully")
    else {
        authComponent.getAuthServ().performTokenRequest(
            authCode.createTokenExchangeRequest(), ClientSecretBasic(secret)
        ) { tokenResponse, e ->
            if (e != null) throw e
            if (tokenResponse != null) {
                authState.update(tokenResponse, null)
                viewModelScope.launch { dataStore.save(authState) }
                _isLoggedIn.value = true
            } else throw IllegalStateException("Response token is empty")
        }
    }
}