I recently crashed in the iOS10 system with UIWebView loading connection.
You need to replace UIWebView with the latest Wkwebview
The following is a description of the relevant content (from the link: http://www.wangyangdev.com/2015/11/13/using Wkwebview replacement uiwebview/)
In the process of developing an app, you will often experience loading pages inside the app, usually UIWebView loaded. This web loader, which has been in use since iOS2, has been developed 心病 : loading is slow, memory is occupied, and optimization is difficult. If you load more Web pages, you may also lose the system due to excessive memory consumption kill . The effects of the various optimizations are also less obvious (click to view Common optimization methods).
After IOS8, Apple introduced a new framework Webkit that provided replacement UIWebView components WKWebView . All kinds UIWebView of problems, faster, less memory, a word, the WKWebView app is the best choice to load the page!
First look at WKWebView the following features:
- In the performance, stability, function has a great improvement (the most intuitive embodiment is the loading of the page is occupied memory, simulator load Baidu and open source China website, Wkwebview occupy 23M, and UIWebView occupy 85M);
- Allows JavaScript's nitro library to be loaded and used (limited in UIWebView);
- Support for more HTML5 features;
- Up to 60fps scrolling refresh rate and built-in gestures;
- Uiwebviewdelegate and UIWebView are composed of 14 classes and 3 protocols (view Apple official documents);
Then from the following aspects WKWebView of the basic usage:
- Loading Web pages
- State callback for loading
- The new
WKUIDelegate protocol
- Dynamically loading and running
JS code
- WebView
JS Code Execution
JSCall the app to register a method
First, load the Web page
Load the Web page or HTML code in the UIWebView same way that the code example looks like:
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];[self.view addSubview:webView];
Second, the state callback of the load (wknavigationdelegate)
Used to track the loading process (page start load, load complete, load failed) method:
//page starts loading when called-(webview: (Wkwebview *) WebView Didstartprovisionalnavigation: (wknavigation *) navigation; //called when content starts to return-(void) webView: ( Wkwebview *) WebView didcommitnavigation: (wknavigation *) navigation; //the page is loaded after the completion of the call-(void) webView: ( Wkwebview *) WebView didfinishnavigation: (wknavigation *) navigation; //page load failed when called-(void) webView: ( Wkwebview *) WebView didfailprovisionalnavigation: (wknavigation *) navigation;
Proxy method for page jumps:
Called after a server jump request has been received-(void)WebView:(Wkwebview *)WebViewDidreceiveserverredirectforprovisionalnavigation:(wknavigation *)NavigationAfter receiving the response, decide whether to jump-(void)WebView:(Wkwebview *)WebViewDecidepolicyfornavigationresponse:(Wknavigationresponse *) navigationresponse decisionhandler:(void (^) (wknavigationresponsepolicy))Decisionhandler; Before sending a request, decide whether to jump -(void)WebView:(Wkwebview *)webView decidepolicyfornavigationaction:( Wknavigationaction *)navigationaction decisionhandler:(void (^) (wknavigationactionpolicy)) Decisionhandler;
Third, the new
WKUIDelegateAgreement
This protocol is mainly used to WKWebView process the Web interface three kinds of prompt boxes (warning boxes, confirmation boxes, input boxes), the following is an example of the warning box:
/** * web界面中有弹出警告框时调用 * * @param webView 实现该代理的webview * @param message 警告框中的内容 * @param frame 主窗口 * @param completionHandler 警告框消失调用 */- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;
Four, dynamic loading and running
JSCode
Used to add JS code to the client and execute it, as an example:
Picture-scaled JS codeNSString *js =@ "var count = Document.images.length;for (var i = 0; i < count; i++) {var image = Document.images[i];image.style.width= 320;}; Window.alert (' find ' + count + ' map ');Initializes a Wkuserscript object based on a JS stringwkuserscript *script = [[wkuserscript Alloc] InitWithSource : JS injectiontime:wkuserscriptinjectiontimeatdocumentend ForMainFrameOnly:yes]; //initializes wkuserscript Wkwebviewconfigurationwkwebviewconfiguration Alloc] init];[ Config.usercontentcontroller Adduserscript:script];_webview = [[WKWebView alloc] Initwithframe:self.view.bounds Configuration:config]; [_webview loadhtmlstring:@ "nil]; [self.view Addsubview:_webview];
V. Implementation of WebView
JSCode
The user invokes the JS code written, generally referred to by the server development:
//javaScriptString是JS方法名,completionHandler是异步回调block[self.webView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
Six
JSCall the app to register a method
The WKWebView method that registers for JS to call again is through WKUserContentController the following method of the class:
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
scriptMessageHandlerIs the proxy callback, which invokes JS name OC the specified object after the method is called scriptMessageHandler .
JSUse the OC following methods when calling the registration method:
window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
Note that name (method name) is placed in the middle, messagebody can only be an object, if you want to pass multiple values, you need to encapsulate an array, or a dictionary. The entire example is as follows:
//OC注册供JS调用的方法[[_webView configuration].userContentController addScriptMessageHandler:self name:@"closeMe"];//OC在JS调用方法做的处理- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ NSLog(@"JS 调用了 %@ 方法,传回参数 %@",message.name,message.body);}//JS调用 window.webkit.messageHandlers.closeMe.postMessage(null);
If you self dealloc hit a breakpoint, you will find self no release! This is obviously not going to work! Google later saw a workaround, as follows:
@interfaceWeakscriptmessagedelegate:nsobject<Wkscriptmessagehandler>@property (Nonatomic,Weakid<Wkscriptmessagehandler> scriptdelegate;-(Instancetype) Initwithdelegate: (id<wkscriptmessagehandler>) Scriptdelegate;@end @implementation weakscriptmessagedelegate-(instancetype) Initwithdelegate: (id< wkscriptmessagehandler>) scriptdelegate{self = [super INIT]; if (self) {_scriptdelegate = scriptdelegate;} return self;} -(void) Usercontentcontroller: (wkusercontentcontroller *) Usercontentcontroller didreceivescriptmessage: (wkscriptmessage *) message{[self.scriptdelegate Usercontentcontroller:usercontentcontroller DidReceiveScriptMessage:message] ;} @end
The idea is to create another proxy object, which is then specified by a proxy object callback self ,
WKUserContentController *userContentController = [[WKUserContentController alloc] init]; [userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"closeMe"];
Run code, self released, WeakScriptMessageDelegate but not released AH Ah!
You also need self to dealloc add this code to the inside:
[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"closeMe"];
OK, solve the problem satisfactorily!
Currently, most apps need to support iOS7 and above, but WKWebView only after iOS8, so a compatibility scheme is required, both iOS7 UIWebView and IOS8 WKWebView . This library provides this compatibility scenario: Https://github.com/wangyangcc/IMYWebView
Part of the above is referenced from: http://www.brighttj.com/ios/ios-wkwebview-new-features-and-use.html
Replace UIWebView with Wkwebview