You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

registerForActivityResult回调未触发,AppAuth授权码获取失败

问题分析与解决

核心问题点

你的代码存在几个关键问题,导致ActivityResultLauncher的回调无法执行、authCode始终为null:

1. ActivityResultLauncher初始化时机错误

在Fragment中直接通过private val authLauncher = registerAuthResultLauncher()初始化时,Fragment尚未依附到Activity,不符合registerForActivityResult要求的组件生命周期注册时机,会导致Launcher无法正确绑定到Fragment生命周期,回调自然不会触发。

2. 同步返回authCode的逻辑错误

obtainAuthCode中调用authLauncher.launch(authIntent)是异步操作,授权需要用户交互后才会返回结果,但你直接同步返回authCode,此时结果还未生成,必然返回null。

3. RedirectUriReceiverActivity配置潜在问题

  • tools:node="replace"可能覆盖AppAuth库中该Activity的默认配置,导致跳转逻辑异常;
  • 需确保authRequest中设置的redirectUri与Manifest里的<data>配置完全一致(包括scheme、host、path,大小写也要匹配)。

修复方案

1. 修正ActivityResultLauncher初始化时机

改用lazy延迟初始化,确保Fragment依附到Activity后再注册:

private val authLauncher by lazy {
    registerAuthResultLauncher()
}

或者在onAttach方法中初始化:

private lateinit var authLauncher: ActivityResultLauncher<Intent>

override fun onAttach(context: Context) {
    super.onAttach(context)
    authLauncher = registerAuthResultLauncher()
}

2. 重构异步结果处理逻辑

放弃同步返回authCode,改用LiveData传递授权结果(也可用回调、Flow实现):

private val authCodeLiveData = MutableLiveData<AuthorizationResponse?>()

private fun registerAuthResultLauncher(): ActivityResultLauncher<Intent> {
    return registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val exception = AuthorizationException.fromIntent(result.data)
            if (exception == null) {
                val response = result.data?.let { AuthorizationResponse.fromIntent(it) }
                authCodeLiveData.postValue(response)
            } else {
                Timber.e(exception, "授权失败")
                authCodeLiveData.postValue(null)
            }
        } else {
            Timber.e("请求失败: ${result.resultCode}")
            authCodeLiveData.postValue(null)
        }
    }
}

// 调整obtainAuthCode,不再返回值
private fun obtainAuthCode() {
    val authIntent = authService.getAuthorizationRequestIntent(authRequest)
    val packageManager = requireContext().packageManager
    if (authIntent.resolveActivity(packageManager) != null) {
        authLauncher.launch(authIntent)
    } else {
        Timber.e("没有可用的Intent处理授权请求")
    }
}

// 在Fragment中观察结果
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    authCodeLiveData.observe(viewLifecycleOwner) { response ->
        response?.let {
            // 拿到授权码,执行换取令牌逻辑
            exchangeToken(it.authorizationCode)
        } ?: run {
            // 处理授权失败或取消的情况
        }
    }
}

3. 修正Manifest配置

将tools:node="replace"改为tools:node="merge",避免覆盖默认配置:

<activity
    android:name="net.openid.appauth.RedirectUriReceiverActivity"
    android:exported="true"
    tools:node="merge">
    <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>

同时严格检查authRequest中的redirectUri是否与上述配置完全一致,示例:

val redirectUri = Uri.parse("https://myapp.example.com/oauth2redirect")
val authRequest = AuthorizationRequest.Builder(
    serviceConfiguration,
    clientId,
    ResponseTypeValues.CODE,
    redirectUri
).build()

内容的提问来源于stack exchange,提问作者ArkadiuszZiemian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 03:55:20