Android GitHub OAuth登录异常:onResume提前执行致uri为空,onActivityResult未触发
解决GitHub OAuth登录时的回调异常问题
嘿,我帮你分析下你遇到的这个问题——其实这是Android系统处理外部Intent回调的机制导致的,咱们一步步来解决:
问题根源拆解
你现在的流程是:LoginActivity → BrowserActivity → 外部浏览器,当GitHub通过自定义Scheme回调时,会出现两个核心问题:
onResume提前执行且uri为空:BrowserActivity启动外部浏览器后,系统会立刻触发它的onResume,但这时候还没到回调环节,getIntent().getData()自然是启动时的旧数据,也就是null。onCreate被调用而非onActivityResult:当回调触发时,系统会新建一个BrowserActivity实例(而不是回到之前启动的那个),所以旧实例的onActivityResult根本不会被触发,反而新实例的onCreate会执行。这是因为默认的Activity启动模式下,系统会为新的Intent创建新实例。
解决方案:两种修复路径
路径一:简化流程,去掉中间的BrowserActivity(推荐)
其实没必要用BrowserActivity做中转,直接让LoginActivity处理整个流程更简单:
- 修改
AndroidManifest.xml:把原来BrowserActivity的intent-filter移到LoginActivity上:
<activity android:name=".ui.activities.LoginActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!-- 新增OAuth回调的Intent Filter --> <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:host="callback" android:scheme="app" /> </intent-filter> </activity> <!-- 可以删除BrowserActivity的配置了 -->
- 修改
LoginActivity代码:直接启动外部浏览器,并在onNewIntent中处理回调:
public class LoginActivity extends AppCompatActivity { Button loginButton; private static final String OAUTH_URL = "你的OAuth授权地址"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); loginButton = findViewById(R.id.button); Log.d("called","oncreate"); // 处理启动时的回调Intent(比如刚安装后直接从回调打开的情况) handleCallbackIntent(getIntent()); loginButton.setOnClickListener(v -> { Log.d("called","onclick"); attemptLogin(); }); } private void attemptLogin(){ Log.d("called","onattempt"); // 直接启动外部浏览器 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(OAUTH_URL)); startActivity(intent); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 处理回调的Intent handleCallbackIntent(intent); } private void handleCallbackIntent(Intent intent) { Uri uri = intent.getData(); if(uri != null && uri.toString().startsWith("app://callback")) { String code = uri.getQueryParameter("code"); Log.d("called", "拿到的code:" + code); // 这里继续处理code,比如请求token } } }
路径二:保留BrowserActivity,修复回调逻辑
如果你一定要保留BrowserActivity,需要调整它的启动模式和回调处理逻辑:
- 修改
AndroidManifest.xml:给BrowserActivity设置launchMode="singleTask",确保回调时复用已有实例:
<activity android:name=".ui.activities.BrowserActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar" android:launchMode="singleTask"> <!-- 新增启动模式 --> <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:host="callback" android:scheme="app" /> </intent-filter> </activity>
- 修改
BrowserActivity代码:用onNewIntent接收回调的Intent,而不是在onResume里拿旧Intent:
public class BrowserActivity extends AppCompatActivity { public static String CALLBACK_URL = "app://callback"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_browser); Intent intent = getIntent(); if(intent != null && !intent.getDataString().startsWith(CALLBACK_URL)){ // 只有当不是回调Intent时,才启动外部浏览器 String url = intent.getStringExtra("URL"); Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(i); } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 接收回调的新Intent Uri uri = intent.getData(); if(uri != null && uri.toString().startsWith(CALLBACK_URL)) { String code = uri.getQueryParameter("code"); Intent resultIntent = new Intent(); resultIntent.putExtra("code",code); setResult(RESULT_OK, resultIntent); finish(); } } // 移除原来的onResume逻辑,因为它拿的是旧Intent }
这样调整后,当回调触发时,系统会回到原来的BrowserActivity实例,调用onNewIntent处理回调,然后通过setResult把code返回给LoginActivity的onActivityResult。
另外提一句:startActivityForResult在Android 11及以上已经被弃用了,推荐使用ActivityResultContracts.StartActivityForResult,不过上面的代码先解决你当前的核心问题~
内容的提问来源于stack exchange,提问作者Brijesh Shah
相关产品推荐
相关产品推荐

