WKWebView與UIWebView的區(qū)別
iOS8以后,蘋果推出了新框架Wekkit,提供了替換UIWebView的組件WKWebView。使用WKWebView,速度會(huì)更快,占用內(nèi)存少。
WKWebView的特性:
在性能、穩(wěn)定性、功能方面有很大提升,直觀體現(xiàn)是內(nèi)存占用變少;
允許JavaScript的Nitro庫加載并使用(UIWebView中限制);
支持了更多的HTML5特性;
高達(dá)60fps的滾動(dòng)刷新率以及內(nèi)置手勢;
將UIWebViewDelegate與UIWebView重構(gòu)成了14類與3個(gè)協(xié)議(詳見SDK);
本文將從以下幾個(gè)方面說下WKWebView的基本用法:
- 加載網(wǎng)頁
- 加載的狀態(tài)回調(diào)
- 新的WKUIDelegate協(xié)議
- 動(dòng)態(tài)加載并運(yùn)行JS代碼
- webView 執(zhí)行JS代碼
- JS調(diào)用App注冊過的方法
一、加載網(wǎng)頁
加載網(wǎng)頁或HTML代碼的方式與UIWebView相同,代碼示例如下:
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"xx"]]];
[self.view addSubview:webView];
二、加載的狀態(tài)回調(diào) (WKNavigationDelegate)
用來追蹤加載過程(頁面開始加載、加載完成、加載失敗)的方法:
// 頁面開始加載時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 當(dāng)內(nèi)容開始返回時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 頁面加載失敗時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
頁面跳轉(zhuǎn)的代理方法:
// 接收到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到響應(yīng)后,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在發(fā)送請求之前,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
三、新的WKUIDelegate協(xié)議
這個(gè)協(xié)議主要用于WKWebView處理web界面的三種提示框(警告框、確認(rèn)框、輸入框),下面是警告框的例子:
/**
* web界面中有彈出警告框時(shí)調(diào)用
*
* @param webView 實(shí)現(xiàn)該代理的webview
* @param message 警告框中的內(nèi)容
* @param frame 主窗口
* @param completionHandler 警告框消失調(diào)用
*/
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;
四、動(dòng)態(tài)加載并運(yùn)行JS代碼
用于在客戶端內(nèi)部加入JS代碼,并執(zhí)行,示例如下:
// 圖片縮放的js代碼
NSString *js = @"var count = document.images.length;for (var i = 0; i < count; i++) {var image = document.images[i];image.style.width=320;};window.alert('找到' + count + '張圖');";
// 根據(jù)JS字符串初始化WKUserScript對象
WKUserScript *script = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
// 根據(jù)生成的WKUserScript對象,初始化WKWebViewConfiguration
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config.userContentController addUserScript:script];
_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
[_webView loadHTMLString:@"<head></head><imgea src='http://www.nsu.edu.cn/v/2014v3/img/background/3.jpg' />"baseURL:nil];
[self.view addSubview:_webView];
五、webView 執(zhí)行JS代碼
用戶調(diào)用用JS寫過的代碼,一般指服務(wù)端開發(fā)的:
//javaScriptString是JS方法名,completionHandler是異步回調(diào)block
[self.webView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
六、JS調(diào)用App注冊過的方法
再WKWebView里面注冊供JS調(diào)用的方法,是通過WKUserContentController類下面的方法:
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
scriptMessageHandler是代理回調(diào),JS調(diào)用name方法后,OC會(huì)調(diào)用scriptMessageHandler指定的對象。
JS在調(diào)用OC注冊方法的時(shí)候要用下面的方式:
window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
注意,name(方法名)是放在中間的,messageBody只能是一個(gè)對象,如果要傳多個(gè)值,需要封裝成數(shù)組,或者字典。整個(gè)示例如下:
//OC注冊供JS調(diào)用的方法
[[_webView configuration].userContentController addScriptMessageHandler:self name:@"closeMe"];
//OC在JS調(diào)用方法做的處理
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
NSLog(@"JS 調(diào)用了 %@ 方法,傳回參數(shù) %@",message.name,message.body);
}
//JS調(diào)用
window.webkit.messageHandlers.closeMe.postMessage(null);
如果你在self的dealloc打個(gè)斷點(diǎn),會(huì)發(fā)現(xiàn)self沒有釋放!這顯然是不行的!谷歌后看到一種解決方法,如下:
@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>
@property (nonatomic, weak) id<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
思路是另外創(chuàng)建一個(gè)代理對象,然后通過代理對象回調(diào)指定的self,
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
[userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"closeMe"];
運(yùn)行代碼,self釋放了,WeakScriptMessageDelegate卻沒有釋放啊啊啊!
還需在self的dealloc里面 添加這樣一句代碼:
[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"closeMe"];
目前,大多數(shù)App需要支持iOS7以上的版本,而WKWebView只在iOS8后才能用,所以需要一個(gè)兼容性方案,既iOS7下用UIWebView,iOS8后用WKWebView。
作者:CheeryLau
來源:CSDN
原文:https://blog.csdn.net/liuq0725/article/details/60573024
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!