【问题标题】:WKWebView not opening custom URL scheme (js opens custom scheme link in new window)WKWebView 未打开自定义 URL 方案(js 在新窗口中打开自定义方案链接)
【发布时间】:2017-10-31 16:46:46
【问题描述】:

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

当我点击带有自定义 url 方案“scm://” 的链接时,它什么都不做...

我的代码:

- (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() 永远不会被调用,decisionPolicyForNavigationAction() 也不会。

【问题讨论】:

    标签: ios wkwebview custom-url deeplink


    【解决方案1】:

    好的,想通了...碰巧链接在新窗口中打开,因此添加下一个代码以及设置 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;
    }
    

    【讨论】:

    • Tried setting UIDelegate without luck 好像你之前做错了什么;)
    • 是的,我没有添加方法createWebViewWithConfiguration,因为不幸的是教程实现WKWebView的完整指南没有。跨度>
    【解决方案2】:
    -(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,但可能会导致其他问题。感谢您的反馈!

    【讨论】:

      【解决方案3】:

      以下适用于 iOS 13.1.3 上的 Swift 5.1(@hstdt's answer 的变体),用于 WKWebView 最少处理以下(经过测试的)架构:sms:tel:mailto:

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

      // assign the delegate
      webView.navigationDelegate = self
      

      然后,在类的某处添加以下函数。

      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 似乎无法处理非 http(s) url 架构。
      • 上面的代码在 WKWebView 有机会渲染/加载请求以检查不同的架构之前捕获请求。
      • 我们检查非 http(s) 架构并让 UIApplication 处理它。

      注意:如果您发现使用此解决方案的其他架构有效或无效,请发表评论。

      同样,此解决方案源自 @hstdt's answer 并进行了修改。

      【讨论】:

      • Not working for intent:// - 错误:“此应用不允许查询方案意图”
      • @MdImranChoudhury 哪个应用/服务使用intent:// uri?
      【解决方案4】:

      Swift 5 解决方案: 以下是 mattblessed 对 WKWebView 的回答的变体,它适用于所有应用程序 URL-Schemes,不仅适用于“sms:”、“tel:”和“mailto:”等系统 URL-Schmes

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

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

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

      【讨论】:

        【解决方案5】:

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

        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/

        【讨论】:

        • 这仅适用于 iOS 11+...如何在早期的 iO​​S 版本中修复它?
        • 如果你能读懂一点 Swift 代码,看看这个链接。这是Complete Guide to Implementing WKWebViewsamwize.com/2016/06/08/complete-guide-to-implementing-wkwebview。如果没有,请告诉我;)
        • 碰巧我实现了我的代码,使用您提供的相同教程链接,但它不起作用...检查我的代码,甚至 handleError 方法是相同的
        • 是的,我明白了。好像你忘记添加 webView.UIDelegate = self.对吗?
        • 尝试设置 UIDelegate 没有运气
        【解决方案6】:

        这对我有用:

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

        【讨论】:

          猜你喜欢
          • 2015-07-13
          • 1970-01-01
          • 2011-03-13
          • 1970-01-01
          • 1970-01-01
          • 2014-05-02
          • 1970-01-01
          • 2014-10-18
          • 2011-01-20
          相关资源
          最近更新 更多