From 5ead559cd9c1fe5c9fdd86c6a178875968e262d7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 9 Jan 2026 01:31:27 +0000
Subject: [PATCH 1/8] Initial plan
From 733adb0fcb405d4b29d16e258b9df7d1e111dbd6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 9 Jan 2026 01:35:25 +0000
Subject: [PATCH 2/8] Add intent-filter for OAuth callback URL handling
Co-authored-by: CarGuo <10770362+CarGuo@users.noreply.github.com>
---
app/src/main/AndroidManifest.xml | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 565bddf..abd90df 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -45,7 +45,18 @@
+ android:windowSoftInputMode="adjustResize"
+ android:launchMode="singleTask">
+
+
+
+
+
+
+
+
Date: Fri, 9 Jan 2026 01:44:43 +0000
Subject: [PATCH 3/8] Fix WebView User-Agent to display Continue button after
2FA
Co-authored-by: CarGuo <10770362+CarGuo@users.noreply.github.com>
---
.../github/kotlin/module/login/LoginOAuthWebFragment.kt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
index 8e30c37..962c846 100644
--- a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
+++ b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
@@ -68,6 +68,12 @@ class LoginOAuthFragment : BaseFragment() {
settings.domStorageEnabled = true
settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS
settings.cacheMode = LOAD_CACHE_ELSE_NETWORK
+
+ // Set a standard Chrome User-Agent to avoid GitHub detecting WebView
+ val userAgent = settings.userAgentString
+ if (!userAgent.contains("Chrome")) {
+ settings.userAgentString = userAgent.replace("wv", "").replace("; )", "; Chrome/120.0.0.0)")
+ }
val webViewClient: WebViewClient = object : WebViewClient() {
From 8cf9f5358e2824fe03cfc765189a82b09dda0668 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 9 Jan 2026 01:45:48 +0000
Subject: [PATCH 4/8] Improve User-Agent handling to be more robust
Co-authored-by: CarGuo <10770362+CarGuo@users.noreply.github.com>
---
.../github/kotlin/module/login/LoginOAuthWebFragment.kt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
index 962c846..636239c 100644
--- a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
+++ b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
@@ -72,7 +72,11 @@ class LoginOAuthFragment : BaseFragment() {
// Set a standard Chrome User-Agent to avoid GitHub detecting WebView
val userAgent = settings.userAgentString
if (!userAgent.contains("Chrome")) {
- settings.userAgentString = userAgent.replace("wv", "").replace("; )", "; Chrome/120.0.0.0)")
+ // Build a proper Chrome User-Agent string
+ settings.userAgentString = "$userAgent Chrome/122.0.0.0 Mobile Safari/537.36"
+ } else if (userAgent.contains(" wv)")) {
+ // Remove WebView identifier if present
+ settings.userAgentString = userAgent.replace(" wv)", ")")
}
val webViewClient: WebViewClient = object : WebViewClient() {
From 9653c895b772fafb7ecc96c3b12a17a07e58d441 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 9 Jan 2026 01:46:40 +0000
Subject: [PATCH 5/8] Refactor User-Agent handling to be clearer and handle all
cases
Co-authored-by: CarGuo <10770362+CarGuo@users.noreply.github.com>
---
.../module/login/LoginOAuthWebFragment.kt | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
index 636239c..b9002d6 100644
--- a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
+++ b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
@@ -70,14 +70,19 @@ class LoginOAuthFragment : BaseFragment() {
settings.cacheMode = LOAD_CACHE_ELSE_NETWORK
// Set a standard Chrome User-Agent to avoid GitHub detecting WebView
- val userAgent = settings.userAgentString
+ var userAgent = settings.userAgentString
+
+ // Remove WebView identifier if present
+ if (userAgent.contains(" wv)")) {
+ userAgent = userAgent.replace(" wv)", ")")
+ }
+
+ // Ensure Chrome is present in User-Agent
if (!userAgent.contains("Chrome")) {
- // Build a proper Chrome User-Agent string
- settings.userAgentString = "$userAgent Chrome/122.0.0.0 Mobile Safari/537.36"
- } else if (userAgent.contains(" wv)")) {
- // Remove WebView identifier if present
- settings.userAgentString = userAgent.replace(" wv)", ")")
+ userAgent = "$userAgent Chrome/122.0.0.0 Mobile Safari/537.36"
}
+
+ settings.userAgentString = userAgent
val webViewClient: WebViewClient = object : WebViewClient() {
From 67f9d5b831e35bdac5802ed2001df1c2ce56a564 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 9 Jan 2026 01:56:37 +0000
Subject: [PATCH 6/8] Replace WebView with external browser for OAuth to avoid
X-Requested-With header
Co-authored-by: CarGuo <10770362+CarGuo@users.noreply.github.com>
---
.../kotlin/module/StartNavigationActivity.kt | 23 +++++
.../module/login/LoginOAuthWebFragment.kt | 96 ++++++-------------
2 files changed, 54 insertions(+), 65 deletions(-)
diff --git a/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt b/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt
index e2f95c9..b0ab434 100644
--- a/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt
+++ b/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt
@@ -33,6 +33,29 @@ class StartNavigationActivity : AppCompatActivity(), HasSupportFragmentInjector
//如果是调试版本,启动后台服务测试AIDL
startService(Intent(this, LocalService::class.java))
}
+
+ handleOAuthCallback(intent)
+ }
+
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ setIntent(intent)
+ handleOAuthCallback(intent)
+ }
+
+ private fun handleOAuthCallback(intent: Intent?) {
+ val uri = intent?.data
+ if (uri != null && uri.scheme == "gsygithubapp" && uri.host == "authed") {
+ // OAuth callback received, navigate to OAuth fragment if not already there
+ val fragment = supportFragmentManager.primaryNavigationFragment
+ if (fragment is NavHostFragment) {
+ val navController = fragment.navController
+ // Always navigate to OAuth fragment to handle the callback
+ if (navController.currentDestination?.id != R.id.loginOAuthFragment) {
+ navController.navigate(R.id.loginOAuthFragment)
+ }
+ }
+ }
}
//实现 HasSupportFragmentInjector 的接口,表示有Fragment需要注入
diff --git a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
index b9002d6..bec6f55 100644
--- a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
+++ b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
@@ -1,13 +1,9 @@
package com.shuyu.github.kotlin.module.login
-import android.graphics.Bitmap
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
import android.view.View
-import android.webkit.WebResourceRequest
-import android.webkit.WebSettings
-import android.webkit.WebSettings.LOAD_CACHE_ELSE_NETWORK
-import android.webkit.WebView
-import android.webkit.WebViewClient
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
@@ -50,72 +46,42 @@ class LoginOAuthFragment : BaseFragment() {
activity?.toast(R.string.LoginFailTip)
}
})
- initWeb()
-
+
+ // Check if we're being called back from OAuth
+ activity?.intent?.data?.let { uri ->
+ if (uri.scheme == "gsygithubapp" && uri.host == "authed") {
+ val code = uri.getQueryParameter("code")
+ if (code != null) {
+ binding!!.oauthWebviewLoadingBar.visibility = View.VISIBLE
+ loginViewModel.oauth(context!!, code)
+ // Clear the intent data to avoid re-processing
+ activity?.intent?.data = null
+ return
+ }
+ }
+ }
+
+ // Launch OAuth in external browser instead of WebView
+ launchOAuthInBrowser()
}
override fun getLayoutId(): Int {
return R.layout.fragment_login_oauth
}
-
- private fun initWeb() {
- val settings = binding!!.oauthWebview.settings
- settings.javaScriptEnabled = true
- settings.loadWithOverviewMode = true
- settings.builtInZoomControls = false
- settings.displayZoomControls = false
- settings.domStorageEnabled = true
- settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS
- settings.cacheMode = LOAD_CACHE_ELSE_NETWORK
+ private fun launchOAuthInBrowser() {
+ val url = "https://github.com/login/oauth/authorize?" +
+ "client_id=${BuildConfig.CLIENT_ID}&" +
+ "state=app&" +
+ "redirect_uri=gsygithubapp://authed"
- // Set a standard Chrome User-Agent to avoid GitHub detecting WebView
- var userAgent = settings.userAgentString
-
- // Remove WebView identifier if present
- if (userAgent.contains(" wv)")) {
- userAgent = userAgent.replace(" wv)", ")")
- }
-
- // Ensure Chrome is present in User-Agent
- if (!userAgent.contains("Chrome")) {
- userAgent = "$userAgent Chrome/122.0.0.0 Mobile Safari/537.36"
+ try {
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ // Add FLAG_ACTIVITY_NEW_TASK to open in external browser
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ startActivity(intent)
+ } catch (e: Exception) {
+ activity?.toast(R.string.LoginFailTip)
}
-
- settings.userAgentString = userAgent
-
- val webViewClient: WebViewClient = object : WebViewClient() {
-
- override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
- }
-
- override fun onPageFinished(view: WebView?, url: String?) {
- binding!!.oauthWebviewLoadingBar.visibility = View.GONE
- }
-
- override fun shouldOverrideUrlLoading(
- view: WebView?, request: WebResourceRequest?
- ): Boolean {
- if (request != null && request.url != null && request.url.toString()
- .startsWith("gsygithubapp://authed")
- ) {
- val code = request.url.getQueryParameter("code")
- if (code != null) {
- loginViewModel.oauth(context!!, code)
- };
- return true
- }
- return false
- }
- }
-
-
- binding!!.oauthWebview.webViewClient = webViewClient
-
-
- val url =
- "https://github.com/login/oauth/authorize?" + "client_id=${BuildConfig.CLIENT_ID}&" + "state=app&redirect_uri=gsygithubapp://authed";
-
- binding!!.oauthWebview.loadUrl(url)
}
}
\ No newline at end of file
From a07c1b70434709a31ebbee404669de63224fc278 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 9 Jan 2026 01:58:02 +0000
Subject: [PATCH 7/8] Fix null safety issue with context in OAuth callback
Co-authored-by: CarGuo <10770362+CarGuo@users.noreply.github.com>
---
.../shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
index bec6f55..6b67e4d 100644
--- a/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
+++ b/app/src/main/java/com/shuyu/github/kotlin/module/login/LoginOAuthWebFragment.kt
@@ -53,7 +53,9 @@ class LoginOAuthFragment : BaseFragment() {
val code = uri.getQueryParameter("code")
if (code != null) {
binding!!.oauthWebviewLoadingBar.visibility = View.VISIBLE
- loginViewModel.oauth(context!!, code)
+ context?.let { ctx ->
+ loginViewModel.oauth(ctx, code)
+ }
// Clear the intent data to avoid re-processing
activity?.intent?.data = null
return
From f97e13d617149c783c122b2f172561fb756b04cc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 9 Jan 2026 01:59:13 +0000
Subject: [PATCH 8/8] Fix null safety in onNewIntent
Co-authored-by: CarGuo <10770362+CarGuo@users.noreply.github.com>
---
.../com/shuyu/github/kotlin/module/StartNavigationActivity.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt b/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt
index b0ab434..48ac807 100644
--- a/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt
+++ b/app/src/main/java/com/shuyu/github/kotlin/module/StartNavigationActivity.kt
@@ -39,7 +39,7 @@ class StartNavigationActivity : AppCompatActivity(), HasSupportFragmentInjector
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
- setIntent(intent)
+ intent?.let { setIntent(it) }
handleOAuthCallback(intent)
}