简体   繁体   English

WKWebView 未打开自定义 URL 方案(js 在新窗口中打开自定义方案链接)

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

I have a WKWebView in my application.我的应用程序中有一个WKWebView I don't use UIWebView , because for some strange reason it doesn't open properly a web page with a lot of JS code in it.我不使用UIWebView ,因为出于某种奇怪的原因,它无法正确打开包含大量 JS 代码的网页。

When I tap on the link with custom url scheme "scm://" , it does nothing ...当我点击带有自定义 url 方案 "scm://"的链接时,它什么都不做......

My code:我的代码:

- (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];
    }
}

When I click custom url, handleError() is never called, neither decidePolicyForNavigationAction().当我单击自定义 url 时,从不调用 handleError(),也不会调用 decisionPolicyForNavigationAction()。

Ok, figured this out... happens that the link was opening in new window, so adding next code along with setting UIDelegate made it work好的,想通了...碰巧链接在新窗口中打开,因此添加下一个代码以及设置 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);
}

Note : This answer is just focus on urlscheme, but maybe lead to other problems.注意:此答案仅针对 urlscheme,但可能会导致其他问题。 Thanks for your feedback!感谢您的反馈意见!

The following works in Swift 5.1 on iOS 13.1.3 (variation of @hstdt's answer ) for WKWebView handling minimally the following (tested) schemas: sms: , tel: , and mailto: .以下适用于 iOS 13.1.3( @hstdt 答案的变体)上的 Swift 5.1,用于 WKWebView 最低限度地处理以下(经过测试的)模式: sms:tel:mailto:

Add the following to whereever you're setting up your WKWebView .将以下内容添加到您设置WKWebView任何WKWebView

// assign the delegate
webView.navigationDelegate = self

Then, add the following function somewhere in your 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)
    }
}

Explanation:解释:

  • WKWebView seems to be unequipped to handle non-http(s) url schemas. WKWebView 似乎无法处理非 http(s) url 模式。
  • The above code catches the request before WKWebView has a chance to render/load it to check for a different schema.上面的代码在 WKWebView 有机会渲染/加载它以检查不同的模式之前捕获请求。
  • We check for a non-http(s) schema and have the UIApplication handle it instead.我们检查非 http(s) 模式并让 UIApplication 处理它。

Note: Comment if you find other schemas working or not working using this solution.注意:如果您发现其他模式在使用此解决方案时有效或无效,请发表评论。

Again, this solution was sourced and modified from @hstdt's answer .同样,这个解决方案是从@hstdt 的答案中获取和修改

Solution for Swift 5: The following is a variation of mattblessed's answer for WKWebView which works for all application URL-Schemes not only the system URL-Schmes like "sms:", "tel:", and "mailto:" Swift 5 的解决方案:以下是 mattblessed 对 WKWebView 的回答的变体,它适用于所有应用程序 URL-Schemes,不仅适用于系统 URL-Schmes,如“sms:”、“tel:”和“mailto:”

This solution will work without adding custom URL Schemes to your apps plist file via LSApplicationQueriesSchemes .此解决方案无需通过LSApplicationQueriesSchemes向您的应用程序 plist 文件添加自定义 URL Schemes 即可工作。 (Which is necessary since iOS 10 - for detail see this article: canOpenURL not working in ios 10 ) (自 iOS 10 起这是必需的 - 有关详细信息,请参阅本文: canOpenURL 在 ios 10 中不起作用

Add the following implementation of WKNavigationDelegate to your class:WKNavigationDelegate的以下实现添加到您的类中:

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)
    }
}

Add the following Extension of URL to your class:将以下URL扩展添加到您的类中:

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(":")
    }
}

I think this is everything you want about custom scheme ;)我认为这就是您想要的关于自定义方案的一切;)

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

You can use setURLSchemeHandler:forURLScheme: to adds an URL scheme handler object for a given URL scheme.您可以使用setURLSchemeHandler:forURLScheme:为给定的 URL 方案添加 URL 方案处理程序对象。

If you want to add custom scheme by Swift, learn more http://samwize.com/2016/06/08/complete-guide-to-implementing-wkwebview/如果您想通过 Swift 添加自定义方案,请了解更多http://samwize.com/2016/06/08/complete-guide-to-implementing-wkwebview/

This worked for me:这对我有用:

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)
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM