普通に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版です。
(※ 上記はプロトコルWKNavigationDelegate
とwebView.navigationDelegate = self
を指定することで動きますが、こちらはWKUIDelegate
とwebView.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);
}