UIWebView 打开新tab

Web知识

在此之前,最好还是先了解一下,Web开发中,是如何打开新页的。它有两种方式:

为什么它们行为相似,它们之间必有关联(我查过了:joy:)
结论是target属性指定了在何处打开链接,它可以指定为以下的值

_blank - 在新窗口或tab打开链接
_self  - 在当前frame打开链接
_parent
_top
framename

a标签需要明确指定target=_blank,因为它默认是 _self
而window.open()默认 _blank,所以默认是打开新页的。它也可以指定target的,它的完整定义是window.open(URL,target,specs,replace)

那接下来,我们的问题可换为,如何在UIWebView里识别链接的target属性

正文

UIWebView 有一个代理对象,可以在网页加载过程中收到回调,获取一些信息。从UIWebViewDelegate中看看,它有哪些代理方法

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;

很快我们就找到了入口

- (BOOL)webView:shouldStartLoadWithRequest:navigationType:

这个方法会在链接加载之前被调用,target判断只能从它的两个参数入手了request&navigationType

navigationType是一个枚举值,能识别出是否是超链接、表格提交、前进后退、刷新、表格重复提交,但就是没有target或frame之类的识别
全村的希望只能放在request的身上了,但它只是个标准的http request,根本不会携带frame这种UI层的信息...

好在Google是万能的:joy:,我们还是找到了解决方案:
希望还是在request,我们可以让打开新页的request.url携带上一些特殊的信息...

这之后,当收到一个链接形如ftnewtab:url的request时,就可以明确,嗯,这是个要打开新页面的链接

修改URL

接下来且看如何修改 a.href 以及重写 window.open()

这样的事当然是要交给强大的JS了

  1. 定义JS function

    // 修改a.href
    function MyIPhoneApp_ModifyLinkTargets(newtabScheme) {
        var allLinks = document.getElementsByTagName('a');
        if (allLinks) {
            var i;
            for (i=0; i 0) {
                        if (!target) target = "_blank";
                        if (target == '_blank') {
                            location.href = newtabScheme+':'+escape(url);
                        } else {
                            location.href = url;
                        }
                    }
                }
    }
    
  2. 在WebView加载结束时,注入以及调用这两个函数

    // OC Code
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        // 注入js方法
        [webView stringByEvaluatingJavaScriptFromString:FTNewTabJSCode];
        
        // 调用js方法
        [webView stringByEvaluatingJavaScriptFromString:@"MyIPhoneApp_ModifyLinkTargets('ftnewtab')"];
        [webView stringByEvaluatingJavaScriptFromString:@"MyIPhoneApp_ModifyWindowOpen('ftnewtab')"];
    }
    

处理URL

经过JS注入后,发起一个新页请求时,就会得到一个特殊的URL了,当然也需要特殊处理一下

// OC Code
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *URL = request.URL;
    if ([URL.scheme isEqualToString:'ftnewtab'] == NO) {
        // 不是新开页,正常执行
       return YES;
    }
    
    NSString *baseURLString = [self stringByEvaluatingJavaScriptFromString:@"document.location.href"];
    NSURL *baseURL = [NSURL URLWithString:baseURLString];
    NSString *urlString = [[url resourceSpecifier] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    url = [NSURL URLWithString:urlString relativeToURL:baseURL];
    [self openNewTabWithURL:url];
    return NO;
}

优化

  • 实际运行中,webViewDidFinishLoad会等到html、css、js、image等所有资源文件下载完成后再调用。而实际上,页面早已部分渲染,此时的a标签已可点击。所以会出现js还未注入却被用户意外点击了开新页的请求。针对这种情况,我们将JS注入提前到了webViewDidStartLoad

    - (void)webViewDidStartLoad:(UIWebView *)webView {
        [webView injectAndExecuteNewTabJSCode];
    }
    

你可能感兴趣的:(UIWebView 打开新tab)