Wkwebview usage and interaction

Time:2022-1-15

reference resources:IOS native and JS interactionReference demo address

Tips: it is necessary to learn some web technology

Uiwebview has been abandoned by Apple’s father. Let’s just say that wkwebview actually has similar methods and ideas
Demo address

Basic use

Load web page

  • Import
#import <WebKit/WebKit.h>
  • Lazy loading
@property(nonatomic,strong)WKWebView *webView;
- (WKWebView *)webView
{
    if (!_webView) {
        WKWebView *view = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        [self.view addSubview:view];
        _webView = view;
    }
    return _webView;
}
  • Load local, network
//Network
NSString *url = @"https://www.baidu.com";
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];

//Local
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"index" ofType:@"html"];
NSURL *baseUrl = [[NSBundle mainBundle]bundleURL];
NSString *sourceString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[self.webView loadHTMLString:sourceString baseURL:baseUrl];

Swift version:

lazy var webView: WKWebView = {
    var webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
    self.view.addSubview(webView)
    return webView
}()

let url = "https://www.baidu.com"
webView.load(URLRequest.init(url: URL.init(string: url)!))
Wkwebview usage and interaction

image.png

Wkwebview usage and interaction

image.png

agent

Compliance agentnavigationDelegateIt mainly handles some jump and load operations
Compliance agentUIDelegate, mainly dealing with JS script, confirmation box, warning box, etc

navigationDelegate

Handle jumps, loads, etc
There are also many agency methods. Let’s talk about a few

  • Authentication is basically not used
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;

The company wants to connect to a third-party platform, and then has a wonderful logic. After the user fills in the relevant information, click Submit, and then the server returns the source code of a web page... The web page needs to be loaded with WebView. When implementing, I found that the simple web page source code I wrote can be loaded, but what the server returns is that it cannot be loaded. Later, after saving the source code as a file, I opened it with a browser and found that the site linked to the web page is an untrusted site. It should be untrusted because the server certificate is invalid.

- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
    NSLog(@"didReceiveAuthenticationChallenge");
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,card);
    }
}
  • decidePolicyForNavigationActiondecidePolicyForNavigationResponse
    Whether to jump before the request and whether to jump after the request response (the method will be called many times because there is jump)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction preferences:(WKWebpagePreferences *)preferences decisionHandler:(void (^)(WKNavigationActionPolicy, WKWebpagePreferences *))decisionHandler API_AVAILABLE(macos(10.15), ios(13.0));

Either of the two methods

typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
    WKNavigationActionPolicyCancel,
    WKNavigationActionPolicyAllow,
} API_AVAILABLE(macos(10.10), ios(8.0));

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSLog(@"decidePolicyForNavigationAction");
    decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    NSLog(@"decidePolicyForNavigationResponse");
    decisionHandler(WKNavigationResponsePolicyAllow);
}

Wknavigationactionpolicyallow: Web pages can jump normally
Wknavigationactionpolicycancel: cancel page Jump
This method can be used to intercept URL interaction with the web
Get protocol, domain name, full path, relative path, port, path, search, parameter
example:

NSLog(@"scheme:%@",navigationAction.request.URL.scheme);
NSLog(@"host:%@",navigationAction.request.URL.host);
NSLog(@"absoluteString:%@",navigationAction.request.URL.absoluteString);
NSLog(@"relativePath:%@",navigationAction.request.URL.relativePath);
NSLog(@"port:%@",navigationAction.request.URL.port);
NSLog(@"path:%@",navigationAction.request.URL.path);
NSLog(@"pathComponents:%@",navigationAction.request.URL.pathComponents);
NSLog(@"query:%@",navigationAction.request.URL.query);
NSLog(@"decidePolicyForNavigationAction");

------ ViewController. M ------ line 65 ------ scheme: HTTPS
------ ViewController. M ------ line 66 ------ host: hqhhtest hqhh520. cn
------ ViewController. M ------ line 67 ------ absolutestring: https://hqhhtest.hqhh520.cn/h5/#/carRental?classId=9
------ ViewController. M ------ line 68 ------ relativepath: / H5
------ ViewController. M ------ line 69 ------ port: (null)
------ ViewController. M ------ line 70 ------ path: / H5
------ ViewController. M ------ line 71 ------ pathcomponents:(
    "/",
    h5
)
------ ViewController. M ------ line 72 ------ query: (null)

If the local interface is loaded, the action and response methods will not be called actively

  • The page starts loadingContent return. loading completedLoading failed*
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
    NSLog(@"didStartProvisionalNavigation");
}
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
{
    NSLog(@"didCommitNavigation");
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    NSLog(@"didFinishNavigation");
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    NSLog(@"didFailNavigation");
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    //If the response is not allowed after the response, the load will fail
    NSLog(@"didFailProvisionalNavigation");
}

UIDelegate

Handle JS script, confirmation box, warning box, etc
JS add pop-up box code Oh

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
    Uialertcontroller * alert = [uialertcontroller alertcontrollerwithtitle: @ "reminder" message: message preferredstyle: uialertcontrollerstylealert];
    [alert Addaction: [uialertaction actionwithtitle: @ "got it" style: uialertactionstylecancel handler: ^ (uialertaction * _nonullaction){
        completionHandler();
    }]];
    [self presentViewController:alert animated:YES completion:nil];
}

Small function

Return and advance to the previous interface
if (self.webView.canGoBack) {
    [self.webView goBack];
}
if (self.webView.canGoForward) {
    [self.webView goForward];
}
Get title, get loading progress

Remember to destroy dealloc and remove listening

[_webView removeObserver:self forKeyPath:@"title"];
[_webView removeObserver:self forKeyPath:@"estimatedProgress"];
[_webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
- (void)addObserver
{
    [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
    [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
    [self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"keyPath:%@",keyPath);
    if ([keyPath isEqualToString:@"title"]) {
        self.title = self.webView.title;
    } else if ([keyPath isEqualToString:@"estimatedProgress"]) {
        NSLog(@"%f",self.webView.estimatedProgress);
    } else if ([keyPath isEqualToString:@"contentSize"]) {
        NSLog(@"%@",object);
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

interactive

url redirection

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSLog(@"URL:%@",navigationAction.request.URL);
    decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    NSLog(@"decidePolicyForNavigationResponse");
    decisionHandler(WKNavigationResponsePolicyAllow);
}

Determine URL

Messagehandler (native)

Extension points: configuration, usercontentcontroller

Initialization settings

- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
//Set preferences
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
//The default value is 0. In fact, it is not recommended to set it here
config.preferences.minimumFontSize = 10;
//Is JavaScript supported
config.preferences.javaScriptEnabled = YES;
//Can I open a window without user interaction
config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
Click JS native response

To test:Prepare the HTML file locally, the JS method and the three parties here
The writing method of WebView JavaScript bridge is slightly different

To test:Prepare the HTML file locally. The JS method here is slightly different from the writing method of the three-party WebView JavaScript bridge
To test:Prepare the HTML file locally. The JS method here is slightly different from the writing method of the three-party WebView JavaScript bridge

window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
Wkwebview usage and interaction

image.png

Setting up usercontentcontroller compliance agentWKScriptMessageHandlerImplementation method

WKUserContentController *userContentController = config.userContentController;
[userContentController addScriptMessageHandler:self name:@"showMobile"];
[userContentController addScriptMessageHandler:self name:@"showName"];
[userContentController addScriptMessageHandler:self name:@"showSendMsg"];

remove

WKUserContentController *controller = self.webView.configuration.userContentController;
[controller removeScriptMessageHandlerForName:@"showMobile"];
[controller removeScriptMessageHandlerForName:@"showName"];
[controller removeScriptMessageHandlerForName:@"showSendMsg"];

agent

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"%@",message.body);
    NSLog(@"%@",message.name);
}
Native driven JS response evaluatejavascript

You can write several buttons to trigger
JS code

Wkwebview usage and interaction

image.png
[self.webView evaluateJavaScript:@"alertMobile()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
    //JS return result
    NSLog(@"%@ %@",response,error);
}];
[self.webView evaluateJavaScript:@"alertName('wpp')" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
    //JS return result
    NSLog(@"%@ %@",response,error);
}];
[self. WebView evaluatejavascript: @ "alertsendmsg ('wpp ',' 20 ')" completionhandler: ^ (ID _nullableresponse, nserror * _nullableerror){
    //JS return result
    NSLog(@"%@ %@",response,error);
}];

Webviewjavascriptbridge (third party)

  • Prepare HTML files separately
  • The best are the latest libraries, and the old ones may collapse
  • Set minimumfontsize to 40, otherwise the interface control is a little small
  • The navigationdelegate agent cannot be set separately because the bridge needs to set it
  • set a property
#import "WebViewJavascriptBridge.h"
@property(nonatomic,strong)WebViewJavascriptBridge *bridge;
self.bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView];
[self.bridge setWebViewDelegate:self];
  • Set WebView for listening
- (void)addRegisterHandler
{
    [self.bridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        Nslog (@ "sweep% @", data);
        Responsecallback (@ "callback");
    }];
    [self.bridge registerHandler:@"locationClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        Nslog (@ "address% @", data);
        Responsecallback (@ "callback");
    }];
    [self.bridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        Nslog (@ "change color% @", data);
        Responsecallback (@ "callback");
    }];
    [self.bridge registerHandler:@"shareClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        Nslog (@ "share% @", data);
        Responsecallback (@ "callback");
    }];
    [self.bridge registerHandler:@"payClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        Nslog (@ "pay% @", data);
        Responsecallback (@ "callback");
    }];
    [self.bridge registerHandler:@"shakeClick" handler:^(id data, WVJBResponseCallback responseCallback) {
        Nslog (@ "shake% @", data);
        Responsecallback (@ "callback");
    }];
    [self.bridge registerHandler:@"goback" handler:^(id data, WVJBResponseCallback responseCallback) {
        Nslog (@ "return% @", data);
        Responsecallback (@ "callback");
    }];
}
  • JS interaction
[self.bridge callhandler: @ "testjsfunction" data: @ "a string" responsecallback: ^ (ID responsedata){
        NSLog(@"%@",responseData);
    }];

Demo address

Little tip

Height of budget view

//Avoid constant height callback
@property(nonatomic,assign)CGFloat webViewHeight;
//Callback height
@property(nonatomic,copy)void (^refreshUIBlock)(void);
if ([keyPath isEqualToString:@"contentSize"]) {
    if (self.webViewHeight == self.webView.scrollView.contentSize.height) {
        return;
    }
    self.webView.height = self.webView.scrollView.contentSize.height;
    self.height = self.webView.height;
    self.webViewHeight = self.webView.height;
    !self.refreshUIBlock ?: self.refreshUIBlock ();
    self.webViewHeight = self.webView.scrollView.contentSize.height;
}

progress bar

Cannot be displayed and added to Scrollview
[self.webView.scrollView addSubview:self.progressView];

@property(nonatomic,strong)UIProgressView *progressView;

- (UIProgressView *)progressView
{
    if (!_progressView) {
        UIProgressView *view = [[UIProgressView alloc]initWithFrame:CGRectMake(0, 0, self.width, 0)];
        [self.webView addSubview:view];
        view.progressTintColor = kThemeColor;
        //view.trackTintColor = [UIColor lightGrayColor];
        _progressView = view;
    }
    return _progressView;
}

if ([keyPath isEqualToString:@"estimatedProgress"]) {
    //NSLog(@"%f",self.webView.estimatedProgress);
    [self.progressView setProgress:self.webView.estimatedProgress animated:YES];
    self.progressView.hidden = self.webView.estimatedProgress == 1.0 ? YES : NO;
}