136
136

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

WKWebViewでtarget="_blank"なリンクが開かない時の対処法

Last updated at Posted at 2014-08-30

普通にWKWebViewを実装したらtarget="_blank"なリンクが押されたときに無反応になるので対処してみました。別の回避方法がありましたらコメント欄にて教えて下さい。

ついでにアプリリンク(iTunes)や他アプリへのURL Schemeの対応も書いています。

(※ WKNavigationDelegateプロトコルとwebView.navigationDelegate = selfとすることをお忘れなく。)

Swift 3.0版

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    
    guard let url = navigationAction.request.url else {
        decisionHandler(.cancel)
        return
    }
    
    if url.absoluteString.range(of: "//itunes.apple.com/") != nil {
        if UIApplication.shared.responds(to: #selector(UIApplication.open(_:options:completionHandler:))) {
            UIApplication.shared.open(url, options: [UIApplicationOpenURLOptionUniversalLinksOnly:false], completionHandler: { (finished: Bool) in
            })
        }
        else {
            // iOS 10 で deprecated 必要なら以降のopenURLも振り分ける
            // iOS 10以降は UIApplication.shared.open(url, options: [:], completionHandler: nil)
            UIApplication.shared.openURL(url)
        }
        decisionHandler(.cancel)
        return
    }
    else if !url.absoluteString.hasPrefix("http://")
        && !url.absoluteString.hasPrefix("https://") {
        // URL Schemeをinfo.plistで公開しているアプリか確認
        if UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.openURL(url)
            decisionHandler(.cancel)
            return
        }
        //                // 確認せずとりあえず開く
        //                UIApplication.shared.openURL(url)
        //                decisionHandler(.cancel)
        //                return
    }
    
    switch navigationAction.navigationType {
    case .linkActivated:
        if navigationAction.targetFrame == nil
            || !navigationAction.targetFrame!.isMainFrame {
            // <a href="..." target="_blank"> が押されたとき
            webView.load(URLRequest(url: url))
            decisionHandler(.cancel)
            return
        }
    case .backForward:
        break
    case .formResubmitted:
        break
    case .formSubmitted:
        break
    case .other:
        break
    case .reload:
        break
    } // 全要素列挙した場合はdefault不要 (足りない要素が追加されたときにエラーを吐かせる目的)
    
    decisionHandler(.allow)
}

別法

コメント欄に @taketo1024 さんが書いてくださった方法のSwift 3.0版です。
(※ 上記はプロトコルWKNavigationDelegatewebView.navigationDelegate = selfを指定することで動きますが、こちらはWKUIDelegatewebView.uiDelegate = selfと指定します。)

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    guard let url = navigationAction.request.url else {
        return nil
    }
    
    guard let targetFrame = navigationAction.targetFrame, targetFrame.isMainFrame else {
        webView.load(URLRequest(url: url))
        return nil
    }
    return nil
}

Objective-C

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSURL *url = navigationAction.request.URL;
    
    // iTunes: アプリのリンクなど
    if ([url.absoluteString rangeOfString:@"//itunes.apple.com/"].location != NSNotFound) {
        [[UIApplication sharedApplication] openURL:url];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    // http(s) 以外のプロトコル: 他のアプリへ移動する場合
    else if (![url.absoluteString hasPrefix:@"http://"]
             && [url.absoluteString hasPrefix:@"https://"]) {
        // URL Schemeをinfo.plistで公開しているかを確認
        // if ([[UIApplication sharedApplication] canOpenURL:url]]) {
        //     [[UIApplication sharedApplication] openURL:url];
        //     decisionHandler(WKNavigationActionPolicyCancel);
        // }
        // or 確認せず開く
        [[UIApplication sharedApplication] openURL:url];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    
    switch (navigationAction.navigationType) {
        case WKNavigationTypeLinkActivated: {
            NSLog(@"WKNavigationTypeLinkActivated::");
            // <a href="..." target="_blank"> が押されたとき
            if (!navigationAction.targetFrame
                || !navigationAction.targetFrame.isMainFrame) {
                [webView loadRequest:[NSURLRequest requestWithURL:url]];
                decisionHandler(WKNavigationActionPolicyCancel);
                return;
            }
            break;
        }
        case WKNavigationTypeFormSubmitted: {
            NSLog(@"WKNavigationTypeFormSubmitted::");
            break;
        }
        case WKNavigationTypeBackForward: {
            NSLog(@"WKNavigationTypeBackForward::");
            break;
        }
        case WKNavigationTypeReload: {
            NSLog(@"WKNavigationTypeReload::");
            break;
        }
        case WKNavigationTypeFormResubmitted: {
            NSLog(@"WKNavigationTypeFormResubmitted::");
            break;
        }
        case WKNavigationTypeOther: {
            NSLog(@"WKNavigationTypeOther::");
            break;
        }
    } // 全要素列挙した場合はdefault不要 (足りない要素が追加されたときにエラーを吐かせる目的)
    
    decisionHandler(WKNavigationActionPolicyAllow);
}
136
136
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
136
136

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?