简体   繁体   English

UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效?

[英]UIWebView delegate method shouldStartLoadWithRequest: equivalent in WKWebView?

I have a module inside my iOS 7+ app which is a UIWebView.我的 iOS 7+ 应用程序中有一个模块,它是一个 UIWebView。 The html page loads a javascript that creates custom-shaped buttons (using the Raphaeljs library). html 页面加载创建自定义形状按钮的 javascript(使用 Raphaeljs 库)。 With UIWebView, I set delegate to self.使用 UIWebView,我将委托设置为 self。 The delegate method webView: shouldStartLoadWithRequest: navigationType: is called each time one of my custom button is pressed.每次按下我的自定义按钮之一时,都会调用委托方法webView: shouldStartLoadWithRequest: navigationType: The requests should not be handled by the html, but rather by the iOS code.请求不应由 html 处理,而应由 iOS 代码处理。 So I used a request convention (read somewhere here on stackoverflow) using "inapp" as the scheme of my requests.所以我使用了一个请求约定(在stackoverflow上的某个地方阅读),使用“inapp”作为我的请求方案。 I then check for the host and take the appropriate action.然后我检查主机并采取适当的措施。

This code works fine on iOS 7. But the web views appear blank on iOS 8 (bug?), so I decided to use WKWebView for iOS 8 devices.此代码在 iOS 7 上运行良好。但在 iOS 8 上 Web 视图显示为空白(错误?),因此我决定将 WKWebView 用于 iOS 8 设备。 The web views now render fine (and amazingly faster!), but my buttons have no effect. Web 视图现在渲染得很好(而且速度惊人地快!),但我的按钮没有效果。

I tried using - (WKNaviation *)loadRequest:(NSURLRequest *)request , but it's not called.我尝试使用- (WKNaviation *)loadRequest:(NSURLRequest *)request ,但它没有被调用。

I can't find a direct equivalent of the UIWebView delegate method webView: shouldStartLoadWithRequest: navigationType: .我找不到 UIWebView 委托方法webView: shouldStartLoadWithRequest: navigationType:的直接等效项。 What's the best way of handling those requests with WKWebView?使用 WKWebView 处理这些请求的最佳方式是什么?

I've been looking for a good explanation myself, but haven't found one. 我自己一直在寻找一个好的解释,但还没找到。 I've used the following in my app and everything seems to work ( Edit: updated based on ccoroom's comment ): 我在我的应用程序中使用了以下内容,一切似乎都有效( 编辑:根据ccoroom的评论更新):

UIWebViewDelegate     - webView:shouldStartLoadWithRequest:navigationType:
WKNavigationDelegate  - webView:decidePolicyForNavigationAction:decisionHandler:

Here's the other UIWebViewDelegate methods: 这是其他UIWebViewDelegate方法:

UIWebViewDelegate     - webViewDidStartLoad:
WKNavigationDelegate  - webView:didCommitNavigation:

UIWebViewDelegate     - webViewDidFinishLoad:
WKNavigationDelegate  - webView:didFinishNavigation:

UIWebViewDelegate     - webView:didFailLoadWithError:
WKNavigationDelegate  - webView:didFailNavigation:withError:
                      - webView:didFailProvisionalNavigation:withError:

I'd love for someone to confirm this for me though. 我喜欢有人为我证实这一点。

Edit: Actually, I've answered the question you had in the title (although I'm no longer confident that webView:didCommitNavigation: is called at the exact same point in the lifecycle), but re-reading your description it looks like what you actually need to know about is how to reimplement a Javascript/Objective-C bridge using WKWebView. 编辑:实际上,我已经回答了你在标题中提到的问题(虽然我不再相信webView:didCommitNavigation:在生命周期中的完全相同的点被调用),但重新阅读你的描述看起来像是什么你真的需要知道如何使用WKWebView重新实现Javascript / Objective-C桥。 So have a look at my other answer. 那么看看我的另一个答案。

To answer the original question, the equivalent of webView:shouldStartLoadWithRequest:navigationType: in UIWebView is webView:decidePolicyForNavigationAction:decisionHandler: in WKWebView. 要回答原始问题,相当于webView:shouldStartLoadWithRequest:navigationType:在UIWebView中是webView:decidePolicyForNavigationAction:decisionHandler:在WKWebView中。 These methods are called before each request is made (including the initial request) and provide the ability to allow/disallow it. 在每个请求发出之前调用这些方法(包括初始请求)并提供允许/禁止它的能力。

Just use the following method , it's a part of WKNavigationDelegate 只需使用以下方法,它就是WKNavigationDelegate的一部分

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    NSURLRequest *request = navigationAction.request;
    NSString *url = [[request URL]absoluteString];

    decisionHandler(WKNavigationActionPolicyAllow);
}

Re-reading your description it looks like what you actually need to know about is how to reimplement a Javascript/Objective-C bridge using WKWebView. 重新阅读您的描述看起来您真正需要了解的是如何使用WKWebView重新实现Javascript / Objective-C桥接。

I've just done this myself, following the tutorial at http://tetontech.wordpress.com/2014/07/17/objective-c-wkwebview-to-javascript-and-back/ and the info at http://nshipster.com/wkwebkit/ 我刚刚完成了这个,按照http://tetontech.wordpress.com/2014/07/17/objective-c-wkwebview-to-javascript-and-back/上的教程和http://上的信息nshipster.com/wkwebkit/

WKWebView has a built-in way of communicating between Javascript and Objective-C/Swift: WKScriptMessageHandler . WKWebView有一种内置的Javascript和Objective-C / Swift: WKScriptMessageHandler之间的通信方式。

First, include the WebKit headers and WKScriptMessageHandler protocol in your view controller's header: 首先,在视图控制器的标题中包含WebKit标头和WKScriptMessageHandler协议:

#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@interface ViewController : UIViewController <WKScriptMessageHandler>

@end

The when initialising your WKWebView , you need to configure it with a script message handler. 初始化WKWebView ,需要使用脚本消息处理程序对其进行配置。 Name it whatever you want, but to me it seems like naming it for your app makes sense. 把它命名为你想要的任何东西,但对我来说,似乎为你的应用程序命名它是有道理的。

    WKWebViewConfiguration *theConfiguration = 
          [[WKWebViewConfiguration alloc] init];
    [theConfiguration.userContentController 
          addScriptMessageHandler:self name:@"myApp"];

    _theWebView = [[WKWebView alloc] initWithFrame:self.view.frame 
                      configuration:theConfiguration];
    [_theWebView loadRequest:request];
    [self.view addSubview:_theWebView];

Now, implement userContentController:didReceiveScriptMessage: . 现在,实现userContentController:didReceiveScriptMessage: . This fires when your webview receives a message, so it does the work you were previously doing with webView:shouldStartLoadWithRequest:navigationType: . 当您的webview收到消息时会触发此消息,因此它执行您之前使用webView:shouldStartLoadWithRequest:navigationType:执行的工作webView:shouldStartLoadWithRequest:navigationType: .

- (void)userContentController:(WKUserContentController *)userContentController 
                        didReceiveScriptMessage:(WKScriptMessage *)message {
    NSDictionary *sentData = (NSDictionary *)message.body;
    NSString *messageString = sentData[@"message"];
    NSLog(@"Message received: %@", messageString);
}

You're now ready to receive messages from Javascript. 您现在已准备好接收来自Javascript的消息。 The function call you need to add to your Javascript is this: 你需要添加到你的Javascript函数调用是这样的:

window.webkit.messageHandlers.myApp.postMessage({"message":"Hello there"});

In Swift you can do something like this: Swift中,您可以执行以下操作:

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {

    switch navigationAction.request.URLString {
    case "http://action.is.needed/some-action":
        self.someFunc()
        decisionHandler(.Cancel)
        break
    default:
        decisionHandler(.Allow)
        break
    }

}

And this is the link in web page: 这是网页中的链接:

<a href="http://action.is.needed/some-action">Hello world!</a>

for swift 4.2 : (taking from Yifei He 何一非. ) 对于swift 4.2 :(取自Yifei He何一非。)

 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {

        let url = navigationAction.request.url
        let urlStr = url?.absoluteString
        switch urlStr {
        case BASE_URL:
            //self.someFunc()
            decisionHandler(.cancel)
            break
        default:
            decisionHandler(.allow)
            break
        }

    }

You can add Observer for your WKWebView 您可以为WKWebView添加Observer

 static void* keyValueObservingContext = &keyValueObservingContext;

[webView addObserver:self forKeyPath:@"URL" options:0 context:keyValueObservingContext];


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
 {

if ([keyPath isEqualToString:@"URL"]){
// do something
  }
}

Don't forget to remove it in viewWillDisappear 不要忘记在viewWillDisappear中删除它

-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[webView removeObserver:self forKeyPath:@"URL"];
}

Using for Delegate methods on migrate for UIWebview to WKWebview使用 for Delegate 方法将UIWebview迁移到WKWebview

UIWebViewDelegate => WKNavigationDelegate UIWebViewDelegate => WKNavigationDelegate

  1. delegate => NavigationDelegate委托 => 导航委托
  2. didFailLoadWithError => didFailNavigation didFailLoadWithError => didFailNavigation
  3. webViewDidFinishLoad => didFinishNavigation webViewDidFinishLoad => didFinishNavigation
  4. webViewDidStartLoad => didStartProvisionalNavigation webViewDidStartLoad => didStartProvisionalNavigation
  5. shouldStartLoadWithRequest => decidePolicyForNavigationAction shouldStartLoadWithRequest => 决定PolicyForNavigationAction

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

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