preface
Recently, the UIWebView in the project was replaced with WKWebView, so let's summarize.
Example Demo: Use of WKWebView
This article will introduce WKWebView from the following aspects:
1. Some classes involved in WKWebView
2. Proxy methods involved in WKWebView
3. Implementation of web content loading progress bar and title
4. Interaction between JS and OC
5. Implementation of local HTML file
6. WKWebView+UITableView mixed row
7. WKWebView offline cache function
1, Some classes involved in WKWebView
WKWebView: rendering and presentation of web pages
be careful: #import <WebKit/WebKit.h> //initialization _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:config]; // UI agent _webView.UIDelegate = self; // Navigation agent _webView.navigationDelegate = self; // Whether to allow the gesture to slide left to return to the previous level, similar to the left slide return of navigation control _webView.allowsBackForwardNavigationGestures = YES; //A list of pages that can be returned to store web pages that have been opened WKBackForwardList * backForwardList = [_webView backForwardList]; // NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.chinadaily.com.cn"]]; // [request addValue:[self readCurrentCookieWithDomain:@"http://www.chinadaily.com.cn"] forHTTPHeaderField:@"Cookie"]; // [_webView loadRequest:request]; //Page back [_webView goBack]; //Page forward [_webView goForward]; //Refresh current page [_webView reload]; NSString *path = [[NSBundle mainBundle] pathForResource:@"JStoOC.html" ofType:nil]; NSString *htmlString = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; //Load local html file [_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
WKWebView configuration: adds WKWebView configuration information for
//Create web page configuration object WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; // Create settings object WKPreferences *preference = [[WKPreferences alloc]init]; //Minimum font size when the JavaScript enabled property is set to NO, you can see a significant effect preference.minimumFontSize = 0; //Sets whether javaScript is supported. It is supported by default preference.javaScriptEnabled = YES; // On iOS, the default value is NO, which indicates whether javaScript can automatically open windows without user interaction preference.javaScriptCanOpenWindowsAutomatically = YES; config.preferences = preference; // Whether to play online with h5 video player or full screen with native player config.allowsInlineMediaPlayback = YES; //Set whether the video needs to be played manually by the user. If set to NO, automatic playback will be allowed config.requiresUserActionForMediaPlayback = YES; //Set whether to allow picture in picture technology to work on a specific device config.allowsPictureInPictureMediaPlayback = YES; //Available after setting the application name iOS9 in the requested user agent information config.applicationNameForUserAgent = @"ChinaDailyForiPad"; //The custom WKScriptMessageHandler is used to solve the problem that memory is not released WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self]; //This class is mainly used to manage the interaction between native and JavaScript WKUserContentController * wkUController = [[WKUserContentController alloc] init]; //Register a js method with the name jsToOcNoPrams [wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"jsToOcNoPrams"]; [wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"jsToOcWithPrams"]; config.userContentController = wkUController;
WKUserScript: used for JavaScript injection
// The following code adapts to the text size. After changing from UIWebView to WKWebView, you will find that the font is much smaller. This should be the compatibility between WKWebView and html. The solution is to modify the original web page, or we can manually inject JS NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"; // For JavaScript injection WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [config.userContentController addUserScript:wkUScript];
WKUserContentController: this class is mainly used to manage the interaction between native and JavaScript
//This class is mainly used to manage the interaction between native and JavaScript WKUserContentController * wkUController = [[WKUserContentController alloc] init]; //Register a JS method with the name jsToOcNoPrams, and set the agent that handles receiving JS methods [wkUController addScriptMessageHandler:self name:@"jsToOcNoPrams"]; [wkUController addScriptMessageHandler:self name:@"jsToOcWithPrams"]; config.userContentController = wkUController; //Remember to remove after use //Remove registered js methods [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcNoPrams"]; [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcWithPrams"];
WKScriptMessageHandler: this protocol class is specially used to handle listening JavaScript methods to call native OC methods. It is used with WKUserContentController.
Note: the WKScriptMessageHandler protocol is followed, and the proxy is set by WKUserContentControl
//Callback method for capturing by name of receiving JS outgoing message - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo); //Use message Body get the parameter body from JS NSDictionary * parameter = message.body; //JS calls OC if([message.name isEqualToString:@"jsToOcNoPrams"]){ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js Call to oc" message:@"Without parameters" preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { }])]; [self presentViewController:alertController animated:YES completion:nil]; }else if([message.name isEqualToString:@"jsToOcWithPrams"]){ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js Call to oc" message:parameter[@"params"] preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { }])]; [self presentViewController:alertController animated:YES completion:nil]; } }
2, Proxy methods involved in WKWebView
WKNavigationDelegate: mainly handles some jump and load operations
// Called when the page starts loading - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { } // Called when the page fails to load - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { [self.progressView setProgress:0.0f animated:NO]; } // Called when the content begins to return - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation { } // After the page is loaded, it is called. - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { [self getCookie]; } //Called when a commit error occurs - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error { [self.progressView setProgress:0.0f animated:NO]; } // After the server jump request is redirected, it is called later. - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation { } // Whether to jump is determined according to WebView's HTTP request header information and related information - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { NSString * urlStr = navigationAction.request.URL.absoluteString; NSLog(@"Send jump request:%@",urlStr); //Self defined protocol header NSString *htmlHeadString = @"github://"; if([urlStr hasPrefix:htmlHeadString]){ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"By interception URL call OC" message:@"You want to go to my Github homepage?" preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:([UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }])]; [alertController addAction:([UIAlertAction actionWithTitle:@"open" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { NSURL * url = [NSURL URLWithString:[urlStr stringByReplacingOccurrencesOfString:@"github://callName_?" withString:@""]]; [[UIApplication sharedApplication] openURL:url]; }])]; [self presentViewController:alertController animated:YES completion:nil]; decisionHandler(WKNavigationActionPolicyCancel); }else{ decisionHandler(WKNavigationActionPolicyAllow); } } // Whether the client can jump is determined according to the server response header and response related information received by the client - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{ NSString * urlStr = navigationResponse.response.URL.absoluteString; NSLog(@"Current jump address:%@",urlStr); //Allow jump decisionHandler(WKNavigationResponsePolicyAllow); //Jump not allowed //decisionHandler(WKNavigationResponsePolicyCancel); } //It is called when the response authentication is required. Similarly, the user identity certificate needs to be passed in the block - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{ //User identity information NSURLCredential * newCred = [[NSURLCredential alloc] initWithUser:@"user123" password:@"123" persistence:NSURLCredentialPersistenceNone]; //Provide a credential for the sender of the challenge [challenge.sender useCredential:newCred forAuthenticationChallenge:challenge]; completionHandler(NSURLSessionAuthChallengeUseCredential,newCred); } //Called when the process is terminated - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{ }
WKUIDelegate: mainly deals with JS scripts, confirmation boxes, warning boxes, etc
/** * web Called when a warning box pops up in the interface * * @param webView Implement the webview of the agent * @param message Content in warning box * @param completionHandler Warning box disappear call */ - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"HTML Pop up box for" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { completionHandler(); }])]; [self presentViewController:alertController animated:YES completion:nil]; } // Confirmation box //After JavaScript calls the confirm method, the callback method confirm is the confirmation box in js, and the user's selection needs to be passed in the block - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { completionHandler(NO); }])]; [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { completionHandler(YES); }])]; [self presentViewController:alertController animated:YES completion:nil]; } // Input box //The callback method after JavaScript calls the prompt method. Prompt is the input box in js, and the information entered by the user needs to be passed in the block - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert]; [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { textField.text = defaultText; }]; [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { completionHandler(alertController.textFields[0].text?:@""); }])]; [self presentViewController:alertController animated:YES completion:nil]; } // The page is a pop-up window_ blank processing - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { if (!navigationAction.targetFrame.isMainFrame) { [webView loadRequest:navigationAction.request]; } return nil; }
3, Implementation of web content loading progress bar and title
//Add an observer to monitor the progress of web page loading [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:0 context:nil]; //Add an observer to monitor the title of the page title [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil]; //kvo monitoring progress must implement this method -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{ if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == _webView) { NSLog(@"Page loading progress = %f",_webView.estimatedProgress); self.progressView.progress = _webView.estimatedProgress; if (_webView.estimatedProgress >= 1.0f) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.progressView.progress = 0; }); } }else if([keyPath isEqualToString:@"title"] && object == _webView){ self.navigationItem.title = _webView.title; }else{ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } //Remove observer [_webView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))]; [_webView removeObserver:self forKeyPath:NSStringFromSelector(@selector(title))];
4, Interaction between JS and OC
JS calls OC
This implementation mainly relies on two classes: WKScriptMessageHandler protocol class and WKUserContentController: the WKUserContentController object is responsible for registering JS methods and setting the agent for processing and receiving JS methods. The agent complies with WKScriptMessageHandler and implements the callback method for capturing JS messages. For details, see the introduction of these two classes in step 1.
//This class is mainly used to manage the interaction between native and JavaScript WKUserContentController * wkUController = [[WKUserContentController alloc] init]; //Register a JS method with the name jsToOcNoPrams, and set the agent that handles receiving JS methods [wkUController addScriptMessageHandler:self name:@"jsToOcNoPrams"]; [wkUController addScriptMessageHandler:self name:@"jsToOcWithPrams"]; config.userContentController = wkUController; Note: Observe WKScriptMessageHandler Agreement, the agent is WKUserContentControl set up //The callback method of capturing through the name of the js outgoing message is called OC - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo); }
OC calls JS
//OC calls JS changecolor(), which is the JS method name, and completionHandler is the asynchronous callback block NSString *jsString = [NSString stringWithFormat:@"changeColor('%@')", @"Js parameter"]; [_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) { NSLog(@"change HTML Background color of"); }]; //Change the font size and call the native JS method NSString *jsFont = [NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", arc4random()%99 + 100]; [_webView evaluateJavaScript:jsFont completionHandler:nil];
5, Implementation of local HTML file
because Sample Demo My needs and knowledge are limited. I wrote an HTML file with only a little skin of HTML, CSS and JavaScript. It's amateur. Don't spray it 😁😁
If Xiaobai wants to learn this knowledge, you can see here: http://www.w3school.com.cn/index.html
I use MAC's own text editing tool to generate a file, change the suffix, and force it to At the same time, you also need to set text editing to display the code when opening the HTML file (as shown in the figure below), and then edit the code.
6. WKWebView+UITableView shuffling and 7. WKWebView offline caching function iOS_Tips-12 Check here.
For more information, please go to my Github: Use of WKWebView