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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:45:54