WKWebView not opening custom URL scheme (js opens custom scheme link in new window)

WKWebView not opening custom URL scheme (js opens custom scheme link in new window)

我的应用程序中有一个 WKWebView。我不使用 UIWebView,因为某些奇怪的原因,它无法正确打开包含大量 JS 代码的网页。

当我使用 自定义 url 方案 "scm://" 点击 link 时,它 什么都不做...

我的代码:

- (void)viewDidLoad {
    // ...

    WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
    if ([configuration respondsToSelector:@selector(setDataDetectorTypes:)])
        [configuration setDataDetectorTypes:WKDataDetectorTypeLink];

    myWebView = [[WKWebView alloc] initWithFrame:webFrame configuration:configuration];
    myWebView.navigationDelegate = self;

    [self.view addSubview:myWebView];
}

#pragma mark - WKNavigationDelegate

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSURL *requestURL = navigationAction.request.URL;
    UIApplication *app = [UIApplication sharedApplication];
    if ([requestURL.scheme.lowercaseString isEqualToString:@"scm"] && [app canOpenURL:requestURL]) {
        [app openURL:requestURL];
        decisionHandler(WKNavigationActionPolicyCancel);
    }
    else
        decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    [self handleError:error];
}

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    [self handleError:error];
}

#pragma mark - Handle web view errors.

- (void)handleError:(NSError *)error
{
    UIApplication *app = [UIApplication sharedApplication];
    app.networkActivityIndicatorVisible = NO;

    NSURL *failedUrl = error.userInfo[NSURLErrorFailingURLErrorKey];

    if ([failedUrl.scheme.lowercaseString isEqualToString:@"scm"]) {
        [app openURL:failedUrl];
    }
}

当我点击自定义 url 时,handleError() 不会被调用,decidePolicyForNavigationAction() 也不会被调用。

我想这就是您想要的关于自定义方案的一切;)

https://medium.com/glose-team/custom-scheme-handling-and-wkwebview-in-ios-11-72bc5113e344

您可以使用 setURLSchemeHandler:forURLScheme: 为给定的 URL 方案添加 URL 方案处理程序对象。

如果您想通过 Swift 添加自定义方案,了解更多 http://samwize.com/2016/06/08/complete-guide-to-implementing-wkwebview/

好的,明白了...碰巧 link 在新的 window 中打开,所以添加下一个代码以及设置 UIDelegate 使其工作

    // Somewhere in viewDidLoad()...
    myWebView.UIDelegate = self;
}

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
    NSLog(@"createWebViewWithConfiguration %@ %@", navigationAction, windowFeatures);
    if (!navigationAction.targetFrame.isMainFrame) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
        [(WKWebView *)_webView loadRequest:navigationAction.request];
    }
    return nil;
}
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{

    NSURLRequest *request = navigationAction.request;
    if(![request.URL.absoluteString hasPrefix:@"http://"] && ![request.URL.absoluteString hasPrefix:@"https://"]) {
        if([[UIApplication sharedApplication] canOpenURL:request.URL]) {
            //urlscheme, tel, mailto, etc.
            [[UIApplication sharedApplication] openURL:request.URL];
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

注意:这个答案只是关注urlscheme,但可能会导致其他问题。感谢您的反馈!

这对我有用:

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
    handleError(error: error as NSError)
}

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
    handleError(error: error as NSError)
}

func handleError(error: NSError) {
    if let failingUrl = error.userInfo[NSURLErrorFailingURLStringErrorKey] as? String {
        if let url = NSURL(string: failingUrl) {
            UIApplication.shared.openURL(url as URL)
        }
    }
}

以下在 Swift 5.1 on iOS 13.1.3( 的变体)中工作,WKWebView 最低限度地处理以下(测试)模式:sms:tel:,以及 mailto:

将以下内容添加到您设置 WKWebView 的任何位置。

// assign the delegate
webView.navigationDelegate = self

然后,在 class.

的某处添加以下函数
func webView(_ webView: WKWebView,
             decidePolicyFor navigationAction: WKNavigationAction,
             decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

    // if the request is a non-http(s) schema, then have the UIApplication handle
    // opening the request
    if let url = navigationAction.request.url,
        !url.absoluteString.hasPrefix("http://"),
        !url.absoluteString.hasPrefix("https://"),
        UIApplication.shared.canOpenURL(url) {

        // have UIApplication handle the url (sms:, tel:, mailto:, ...)
        UIApplication.shared.open(url, options: [:], completionHandler: nil)

        // cancel the request (handled by UIApplication)
        decisionHandler(.cancel)
    }
    else {
        // allow the request
        decisionHandler(.allow)
    }
}

解释:

  • WKWebView 似乎无法处理非 httpurl 模式。
  • 以上代码在 WKWebView 有机会 render/load 检查不同的模式之前捕获请求。
  • 我们检查非 http(s) 架构并让 UIApplication 处理它。

注意:如果您发现其他模式在使用此解决方案时有效或无效,请发表评论。

同样,此解决方案来源于

Swift5 的解决方案: 以下是 mattblessed 对 WKWebView 的回答的变体,它适用于所有应用程序 URL-Schemes,而不仅仅是系统 URL-Schmes,例如 "sms:"、"tel:" 和 "mailto:"

此解决方案无需通过 LSApplicationQueriesSchemes 将自定义 URL 方案添加到您的应用 plist 文件即可工作。 (这是必需的,因为 iOS 10 - 有关详细信息,请参阅本文:canOpenURL not working in ios 10

WKNavigationDelegate 的以下实现添加到您的 class:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if let requestUrl = navigationAction.request.url, requestUrl.isCustomUrlScheme() {
        decisionHandler(.cancel)

        // try to open URLs like e.g. "whatsapp://"
        UIApplication.shared.open(requestUrl, options: [:]) { success in
            if !success {
                //TODO 
                // add your code for handling URLs that can't be opened here - 
                // maybe show an error alert
            }
        }
    } else {
        // allow the request
        decisionHandler(.allow)
    }
}

URL 的以下扩展添加到您的 class:

extension URL {

    func isCustomUrlScheme() -> Bool {
        let webUrlPrefixes = ["http://", "https://", "about:"]

        let urlStringLowerCase = self.absoluteString.lowercased()
        for webUrlPrefix in webUrlPrefixes {
            if urlStringLowerCase.hasPrefix(webUrlPrefix) {
            return false
        }

        return urlStringLowerCase.contains(":")
    }
}