iOS17.5+中WKWebView的Google OAuth弹窗window.opener为null问题
WKWebView中Google OAuth弹窗window.opener为null(iOS17.5+失效)
项目中使用WKWebView展示Google OAuth弹窗,该功能在iOS17.0及之前版本正常,但从iOS17.5开始失效,iOS18.0测试结果相同——弹窗出现后JS的window.opener始终为null,导致原窗口无法通过回调获取授权token。
该功能在SFSafariViewController中可正常工作,但因需要隐藏导航栏和状态栏,无法使用该组件。
HTML代码
<html> <head> <script src="https://accounts.google.com/gsi/client" async></script> </head> <script type="text/javascript"> var global = {}; window.addEventListener("message", function (event) { console.log("Trying to catch Google OAuth"); console.log(event); }); function client() { if (global.client === undefined) { global.client = google.accounts.oauth2.initTokenClient({ client_id: '<client_id>', scope: 'https://www.googleapis.com/auth/userinfo.email \ https://www.googleapis.com/auth/userinfo.profile', callback: function (responseToken) { console.log("=== Callback ==="); console.log(responseToken); let auth = document.getElementById("auth"); auth.textContent = 'Token: ' + responseToken.access_token } }); } return global.client; } function googleOauthClient() { console.log("Trying to login"); let auth = document.getElementById("auth"); auth.textContent = 'In Progress...'; client().requestAccessToken(); } </script> <body> <div id="center"> <a onclick="googleOauthClient()"><h1>Google Login Attempt</h1></a> <h2 id="auth"></h2> </div> </body> </html>
iOS端弹窗实现代码(Objective-C)
#import "WebViewController.h" #import "SafariServices/SafariServices.h" @interface WebViewController () <WKNavigationDelegate, WKUIDelegate> { WKWebView *web; WKWebView *popupWebView; } @end @implementation WebViewController - (void)loadView { [super loadView]; WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; [[config preferences] setJavaScriptEnabled:YES]; [[config preferences] setJavaScriptCanOpenWindowsAutomatically:NO]; [[config defaultWebpagePreferences] setAllowsContentJavaScript:YES]; [config setAllowsInlineMediaPlayback:YES]; web = [[WKWebView alloc] initWithFrame:self.view.frame configuration:config]; [web setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; [web setAllowsLinkPreview:YES]; [web setNavigationDelegate:self]; [web setUIDelegate:self]; [web setInspectable:YES]; [web setCustomUserAgent:[[web valueForKey:@"userAgent"] stringByAppendingString:@" Safari"]]; [[self view] addSubview:web]; } - (void)viewDidLoad { [super viewDidLoad]; NSString *url = @"http://localhost:8080/oauth"; // A simple Spring Boot App where HTML is hosted [web loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; } - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { decisionHandler(WKNavigationActionPolicyAllow); } - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { if (navigationAction.targetFrame == nil) { popupWebView = [[WKWebView alloc] initWithFrame:webView.frame configuration:configuration]; [popupWebView setCustomUserAgent: [webView customUserAgent]]; [popupWebView setUIDelegate:self]; [popupWebView setNavigationDelegate:self]; [popupWebView setInspectable:true]; [[[popupWebView configuration] defaultWebpagePreferences] setAllowsContentJavaScript:YES]; [[[popupWebView configuration] preferences] setJavaScriptCanOpenWindowsAutomatically:NO]; [[[popupWebView configuration] preferences] setJavaScriptEnabled:YES]; [[popupWebView configuration] setSuppressesIncrementalRendering:YES]; [webView addSubview:popupWebView]; [popupWebView loadRequest:[navigationAction.request copy]]; return popupWebView; } return nil; } - (void)webViewDidClose:(WKWebView *)webView { [webView removeFromSuperview]; popupWebView = nil; } - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { NSLog(@"didFailProvisionalNavigation: %@", [error description]); } - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { NSLog(@"didFailNavigation: %@", [error description]); } - (void)webView:(WKWebView *)webView requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame type:(WKMediaCaptureType)type decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler { decisionHandler(WKPermissionDecisionGrant); } - (void)webView:(WKWebView *)webView requestDeviceOrientationAndMotionPermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler { decisionHandler(WKPermissionDecisionGrant); } - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler { completionHandler(nil); } @end
已尝试的解决方法
- 在Safari设置中关闭Cross-Origin-Opener-Policy、Cross-Origin-Embedder-Policy,禁用第三方Cookie拦截(ITP)
- 关闭弹窗拦截
- 在Info.plist中添加
NSAllowsArbitraryLoads及其他相关安全策略 - 在Info.plist中添加
NSCrossWebsiteTrackingUsageDescription,并在应用设置中开启跨网站追踪权限
请问哪里操作有误?或有没有替代方案可从弹窗中获取Google OAuth token?
内容的提问来源于stack exchange,提问作者Vlady
相关产品推荐
相关产品推荐

