从源 WKWebView (window.opener) 访问 javascripts 函数

Posted

技术标签:

【中文标题】从源 WKWebView (window.opener) 访问 javascripts 函数【英文标题】:Access javascripts functions from source WKWebView (window.opener) 【发布时间】:2017-10-07 02:41:10 【问题描述】:

在我的 ios 应用程序中,我有 2 个WKWebView 控件来模拟我们的网络应用程序中 2 个选项卡/窗口的父/子关系,以便我们可以重用所有这些 javascript。问题是这 2 个WKWebViews 之间没有通用的通信通道。

网页架构: - 第一个/主窗口加载我们的内部 javascript 函数,并在第二个/子窗口中打开链接。 - 第二个/子窗口加载第三方网页内容。 - 第三方内容使用javascript表单源窗口与我们的系统通信(使用window.opener / window.parent API桥)。

现在,在本机应用程序中,我正在这样做以重用现有的 javascript 并模拟 Web 架构 -

一个。下面是 1st WKWebView 中网页的 js 调用 -

  window.open("http://localhost/child.html", "myWindow", "width=200,height=100");  

b. WKUIDelegate 拦截此调用 (a) 并打开 2nd WKWebView -

- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures 
    // Here, window.open js calls are handled by loading the request in another/new web view
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    WebViewController *webViewController = [mainStoryboard instantiateViewControllerWithIdentifier:@"WebViewController"];
    webViewController.loadURLString = navigationAction.request.URL.absoluteString;

    // Show controller without interfering the current flow of API call, thus dispatch after a fraction of second
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
        [self.navigationController pushViewController:webViewController animated:YES];
    );
    return nil;

c。在网页/电脑浏览器中,网页应用的子窗口可以使用window.openerwindow.parent访问源js函数

如何在WKWebViews 中实现同样的功能?换句话说,第二个WKWebView中的js函数可以从父/源WKWebView调用js函数?

【问题讨论】:

【参考方案1】:

你绝对不应该从webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:返回nil,而是你的WKWebView的一个实例。

很遗憾,我现在无法验证这一点。但据我记得,诀窍也是不要忽略来自webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures: 委托方法的WKWebViewConfiguration 参数,而是创建第二个WKWebView 实例,将此参数作为initWithFrame:configuration: 参数之一传递。

此外,根据 Apple 文档,如果您返回正确的 Web 视图实例,您似乎不需要自己加载请求。 WebKit 应该为您处理这个问题。

总体而言,您的代码应类似于:

- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures 
    WKWebView *childWebView = [[WKWebView alloc] initWithFrame:CGFrameZero configuration:configuration];
    WebViewController *webViewController = [[WebViewController alloc] initWithWebView: childWebView];

    // looks like this is no longer required, but I can't check it now :(
    // [childWebView loadRequest:navigationAction.request];

    // Show controller without interfering the current flow of API call, thus dispatch after a fraction of second
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
        [self.navigationController pushViewController:webViewController animated:YES];
    );
    return childWebView;

【讨论】:

很好,这看起来是一个很有希望的答案。兴奋的。今天试一试。 确认 1. 具有给定配置的新 WKWebView 实例的组合已通过,以及 2. 从列出的方法返回此新实例使得在这些“子页面”和“父页面”的工作,这真是令人难以置信。加载请求也不是必需的。【参考方案2】:

完成任务的更简单方法是拥有一个 WKWebView,并使用 HTML 分隔标题和细节。最简单的解决方案是拥有一个带有标题和所有细节的 HTML 文档,但如果您需要动态添加细节,也可以使用 DOM。使用这种方法,对标题和细节重用 Javascript 将是最简单的。

【讨论】:

实际上,在 2 个独立的 WKWebViews 中打开数据是一个先决条件,这样我们就可以在我们的应用程序中为该功能重用 Web 应用程序架构。此外,从用户的角度来看,它将在 Web 应用程序和本地应用程序中提供相同的体验。

以上是关于从源 WKWebView (window.opener) 访问 javascripts 函数的主要内容,如果未能解决你的问题,请参考以下文章

从源 WKWebView (window.opener) 访问 javascripts 函数

被`webView.uiDelegate`打开后如何处理`window.close`?

window.open返回值问题

jquery 打开页面window.location和window.open的区别

在window.open打开的窗口里再用window.open办法打开一窗口

window.open被拦截