WKWebView is a new component introduced by apple in iOS8, the purpose of which is to give a new high-performance WebView solution, get rid of the old and bulky UIWebView, especially the problem of huge memory usage. This article mainly wants to discuss the use of iOS control WKWebView through the middle page load H5 SDK, and according to the enterprise development needs to configure the H5 SDK under different environments (test, online, pre-release), before discussing this problem will be a little long winded summary of WKWebView load mode and basic API

WKWebView load H5 mode

1. Load network resources using url addresses

- (void)loadWithUrl{
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com/"]]];
    [self.view addSubview:self.webView];
}
Copy the code



2. Load local resources using HTML

The HTML file

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>iOS and JS</title> <style type="text/css"> * { font-size: 40px; } </style> </head> <body> <div style="margin-top: 10px"> <h1 style="color: red;" > Load local HTML file </h1><br/> </div> </body> </ HTML >Copy the code

The load function

- (void)loadWithHtml {
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
    NSURL *path = [[NSBundle mainBundle] URLForResource:@"text" withExtension:@"html"];
    [self.webView loadRequest:[NSURLRequest requestWithURL:path]];
    [self.view addSubview:self.webView];
}
Copy the code



3. Load the HTML code directly

- (void)loadWithHtmlStr { self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; <h1 style = "color: red; \"> load HTMLSTR </h1>"; [self.webView loadHTMLString:HTMLData baseURL:nil]; [self.view addSubview:self.webView]; }Copy the code



Basic API WKWebView

Basic API in blog.csdn.net/baihuaxiu12 WKWebView… It has been introduced in detail, so I don’t want to say too much here, just pick out the more commonly used ones.

WKUserContentController Content interaction controller

@property (nonatomic, readonly, copy) NSArray<WKUserScript *> *userScripts; // inject JS - (void)addUserScript:(WKUserScript *)userScript; // Remove all injected JS - (void)removeAllUserScripts; // Add scriptMessageHandler to all frames, Can pass the / / the window. Its. MessageHandlers. < name >. PostMessage (< messageBody >) messages / / / /, for example, JS to invoke our native methods, - (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name; / / by name to remove the injection scriptMessageHandler - (void) removeScriptMessageHandlerForName (nsstrings *) name;Copy the code

We can when creating WKWebView config. For its userContentController add handler, Void userContentController:(WKUserContentController *)userContentController DidReceiveScriptMessage :(WKScriptMessage *)message{} listen

WKScriptMessageHandler

@protocol WKScriptMessageHandler <NSObject>

@required

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

@end
Copy the code

Combined with the example

OC: config. UserContentController = [[WKUserContentController alloc] init]; [config.userContentController addScriptMessageHandler:self name:@"AppModel"]; self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config]; JS:  <script type="text/javascript"> function text(option) { Window. Its. MessageHandlers. AppModel. PostMessage (" pass the data to the OC "); } </script> protocol listener in OC:  - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{if ([message.name isEqualToString:@"AppModel"]) {NSLog(@" callback listener === %@", message.body); // Print result: data passed to OC}}Copy the code

In the above example, we added a handler named “AppModel” to the WKWebView instantiation. Once the text method is triggered in JS, Js through the window. Its. MessageHandlers. AppModel. PostMessage () can give OC message, on the OC end monitoring methods to deal with.

WKNavigationDelegate

@protocol WKNavigationDelegate <NSObject> @optional // Determines the navigation action, usually used to handle whether links across domains can be navigated. WebKit does not allow cross-domain security checks, so we will treat links that cannot cross domains // separately. However, Safari allows cross-domain, so you don't have to do that. / / this is deciding whether or not the Request - (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler; // To get a response, Through WKNavigationResponse object access - (void) webView: (WKWebView *) webView decidePolicyForNavigationResponse: (WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler; // When the main frame navigation starts requesting, Will invoke this method - (void) webView: (WKWebView *) webView didStartProvisionalNavigation: (null_unspecified WKNavigation *) navigation; // When the main frame receives a service redirect, Will back this method - (void) webView: (WKWebView *) webView didReceiveServerRedirectForProvisionalNavigation: (null_unspecified WKNavigation *)navigation; // When the main frame fails to start loading data, Callback - (void) webView: (WKWebView *) webView didFailProvisionalNavigation: (null_unspecified WKNavigation *) navigation withError:(NSError *)error; // When the web content of the main frame starts arriving, - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation; // When the main frame navigation is complete, - (void)webView (WKWebView *)webView didFinishNavigation (Null_Unspecified WKNavigation *) Navigation; // When the main frame finally fails to download data, - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error; // This is similar to the API used for authorization validation, - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler; / / when the web content processing is completed, the callback - (void) webViewWebContentProcessDidTerminate: (WKWebView *) webView NS_AVAILABLE (10 _11, 9 _0); @endCopy the code

The most used proxy protocol, WKNavigationDelegate, is didFinishNavigation, which can be used in conjunction with evaluateJavaScript to actively call some JS methods when the navigation load is complete.

- (void)webView (WKWebView *)webView didFinishNavigation (WKNavigation *) Navigation evaluateJavaScript:@"text()" completionHandler:^(id _Nullable res, NSError * _Nullable error) { NSLog(@"respose = %@ -- error = %@", res, error); }]; NSString *text = [NSString stringWithFormat:@"text('%@')", self.userid]; [self.webView evaluateJavaScript:text completionHandler:^(id _Nullable res, NSError * _Nullable error) { NSLog(@"respose = %@ -- error = %@", res, error); }]; }Copy the code

WKWebView middle page loads H5 SDK

Having said that, we finally get to the point where OC development inevitably needs to display H5 pages and interact with them. Generally, the SDK launched by enterprises includes three access modes of iOS, Android and H5. H5 is not only applicable to Web but also can be accessed by iOS and Android. In this example, use [NetEase Qiyu]qiyukf.com/docs/guide/… For example, access the chat function of customer service consultation of H5 SDK in iOS (this example is for reference only, it is not recommended to do so in real development, after all, access to H5 SDK will lose some functions originally belonging to SDK. The SDK in the above example can be accessed by URL and local HTML file, but some parameters of URL address stitching are invalid (anonymous user), so the access mode of HTML file can only be excluded. Typically, the SDK is initialized for different environments (development, testing). We can define a JS method in an HTML file that fires and initializes with the required parameters

html: function register(isDev, appkey, uid, name){ var url; If (isDev) {/ / different environment domain name is not the same url = {appkey} ` https://aaa.aaa.aaa/script/$. Js? hidden=1`; } else { url = `https://bbb.bbb.bbb/script/${appkey}.js? hidden=1`; } / / initialization (function (w, d, n, a, j) [n] = {w w [n] | | function () {(w [n]. [n]. A = w a | | []), push (the arguments); }; j = d.createElement('script'); j.async = true; j.src =`${url}`; d.body.appendChild(j); })(window, document, 'ysf'); / / to ysf user (' config '{uid: ${uid} ` `, name: ${name} ` `, data: JSON. The stringify (XXX), success: function() { window.webkit.messageHandlers.AppModel.postMessage('true'); }, error: function() { window.webkit.messageHandlers.AppModel.postMessage('fase'); }}); }Copy the code

In the HTML file above, isDev is used to distinguish the development environment from the online environment, appkey is used to initialize the SDK, UID and name are used to configure the reporting of user information

- (NSString *)javascriptStr { NSString *domain = xxx; NSString *account = xxx; If (setting == Online) {return [NSString stringWithFormat:@"register(0,'%@','%@','%@')",kOnlineAppKey, account]; If (setting == Test) {return [NSString stringWithFormat:@"register(1,'%@','%@','%@')",kTestAppKey, account]; If (setting == OnlinePre) {return [NSString stringWithFormat:@"register(0,'%@','%@','%@')",kPreAppKey, domain, account]; } return @""; } #pragma mark - WKNavigationDelegate - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{// Get the configuration string NSString *javascriptStr = [self javascript]; if (! [nsstrings isEmptyStr: javascriptStr]) {/ / JS code to execute [self. WebView evaluateJavaScript: javascriptStr completionHandler: ^ (id _Nullable res, NSError * _Nullable error) { // NSLog(@"res = %@ -- error = %@", res, error); }]; } else {NSLog(@"Toast prompt ")}} #pragma mark - WKScriptMessageHandler - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ if ([message.name isEqualToString:@"AppModel"]) { if ([message.body isEqualToString:@"true"]) { NSLog(@" initialization failed ") -- (execute OC or JS code etc)} else {NSLog(@" initialization failed ") -- (Toast prompt etc)}}}Copy the code

EvaluateJavaScript is called in the OC file after the intermediate page is loaded: to perform the HTML JS code initialization and reporting of user information, etc. The callback after the operation is executed is listened in the WKScriptMessageHandler. The corresponding success failure is in other business logic processing.

conclusion

WKWebView, as an OC side, is used to display interactive H5 important controls. It contains many proxy methods that can execute JS code well and sense callback after JS operation, which is very convenient and flexible. It is necessary to pay attention to local file reading and cross-domain problems when executing local HTML files.