Flutter中文网

Flutter中文网

Flutter InAppWebView Google登录失败

80
2024-07-23

前段时间用户反馈应用内部网页使用X(原Twitter)的时候Google登录按钮一直在Loading,部分用户没有Google登录选项,极少数用户出现了Google登录按钮,但是点击跳转之后白屏。经多方查找资料,问题解决,这里记录一下处理过程。

声明:以下均在iOS设备上调试,Android上表现不太一致,但产生的原因和解决方式一样

环境

Flutter:3.22.2

flutter_inappwebview:6.0.0

运行设备:iOS 17.5.1

现象

如果下图所示,Google登录按钮一直在Loading,

X的Google登录按钮Loading

有少部分用户加载出登录按钮,但是跳转之后白屏。

排查过程

因为使用的flutter_inappwebview,第一反应到它Github仓库的issues搜索了一下关键词google sign in。看了所有的搜索结果没想到还真有发现,都指向了这里,虽然表现出来的现象都不太一样:

Authorisation Error,Error 403:disallowed_useragent

Google授权登录403错误

Access blocked: This app's request is invalid

Google授权登录报错:Access blocked

似乎都与userAgent有关,评论里很多人都回复设置了一个userAgent后,Google登录恢复正常,但也有人很表示该方法无效。

我也尝试了一下,随便网上找了一个userAgent,设置发现😂:

X不再支持此浏览器

看来X有检测UserAgent,找的太旧了换一个新的

Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/119.0.6045.169 Mobile/15E148 Safari/604.1

X的Google登录正常出现

正当我以为事情这么简单的时候,点击Google登录然后打开一页白屏!

这时候我注意到控制台打印:

[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onTitleChanged" using {title: X。尽是新鲜事 / X}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onWindowFocus" using []
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onWindowFocus" using []
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onCreateWindow" using {isForMainFrame: false, targetFrame: null, navigationType: -1, shouldPerformDownload: false, windowId: 4, hasGesture: null, windowFeatures: {width: 350.0, height: 550.0, y: 147.0, statusBarVisibility: false, toolbarsVisibility: false, allowsResizing: false, menuBarVisibility: false, x: 20.0}, request: {headers: {Referer: https://x.com/}, allowsCellularAccess: true, httpShouldUsePipelining: false, networkServiceType: 0, body: null, timeoutInterval: 2147483647.0, attribution: 0, method: GET, allowsConstrainedNetworkAccess: true, allowsExpensiveNetworkAccess: true, mainDocumentURL: null, url: https://accounts.google.com/gsi/select?client_id=49625052041-kgt0hghf445lmcmhijv46b715m2mpbct.apps.googleusercontent.com&ux_mode=popup&ui_mode=bottom_sheet&as=DiJIrUBftb5akVzSPBW8Kw&channel_id=9b9a69a2a67be16b5a1a42ac0bd12249f44b307330d80f07e39e1eba1909d5a8&origin=https%3A%2F%2Fx.com, cachePolicy: 0, httpShouldHandleCookies: true, assumesHTTP3Capable:...
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: null, url: https://accounts.google.com/gsi/select?client_id=49625052041-kgt0hghf445lmcmhijv46b715m2mpbct.apps.googleusercontent.com&ux_mode=popup&ui_mode=bottom_sheet&as=DiJIrUBftb5akVzSPBW8Kw&channel_id=9b9a69a2a67be16b5a1a42ac0bd12249f44b307330d80f07e39e1eba1909d5a8&origin=https%3A%2F%2Fx.com}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onLoadStart" using {url: https://accounts.google.com/gsi/select?client_id=49625052041-kgt0hghf445lmcmhijv46b715m2mpbct.apps.googleusercontent.com&ux_mode=popup&ui_mode=bottom_sheet&as=DiJIrUBftb5akVzSPBW8Kw&channel_id=9b9a69a2a67be16b5a1a42ac0bd12249f44b307330d80f07e39e1eba1909d5a8&origin=https%3A%2F%2Fx.com}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onProgressChanged" using {progress: 30}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onTitleChanged" using {title: }
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onPageCommitVisible" using {url: https://accounts.google.com/gsi/select?client_id=49625052041-kgt0hghf445lmcmhijv46b715m2mpbct.apps.googleusercontent.com&ux_mode=popup&ui_mode=bottom_sheet&as=DiJIrUBftb5akVzSPBW8Kw&channel_id=9b9a69a2a67be16b5a1a42ac0bd12249f44b307330d80f07e39e1eba1909d5a8&origin=https%3A%2F%2Fx.com}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onTitleChanged" using {title: Sign In - Google Accounts}
[IOSInAppWebViewController] (iOS) WebView ID 0 calling "onProgressChanged" using {progress: 100}

注意看第4行onCreateWindow ,联想到平时在PC上Google 登录确实有新开一个窗口,于是做以下尝试:

onCreateWindow: (controller,action) async {

          showDialog(
            context: context,
            builder: (context) {
              return AlertDialog(
                content: SizedBox(
                  width: MediaQuery.of(context).size.width,
                  height: 400,
                  child: InAppWebView(
                    // 这里设置windowId非常重要
                    windowId: action.windowId,
                    initialSettings: InAppWebViewSettings(
                      userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/119.0.6045.169 Mobile/15E148 Safari/604.1',
                    ),
                  ),
                ),
              );
            },
          );
          return true;
        }

实现了InAppWebView的onCreateWindow

⚠️注意,这里Dialog里的InAppWebView也必须设置userAgent

再次尝试竟然好了

成功调起Google登录

成功登录Twitter,至此问题解决。

总结

解决这个问题有两步:

  1. 设置UserAgent

  2. 如上文所示,实现onCreateWindow 方法,注意设置windowId和Dialog里InAppWebView的userAgent

UserAgent闲聊

我一直认为InAppWebView有默认的userAgent,看代码发现默认的是空字符串。但是无论是页面加载成功后用JS方法获取,还是拦截网络请求,都能看到有正确的userAgent,自己手动设置后,均变为设置后的值。没有深入研究这个问题,猜测可能是:对应iOS或Android的原生WebView有默认值,Flutter侧只是提供了一个修改手段。

写死一个userAgent虽然不影响功能,但可能产生一些未知的问题,建议需要手动设置的时候还是根据规则生成。

查资料的时候还发现一个很有趣的问题,你猜为什么不同平台不同浏览器的UserAgent都以Mozilla开头?