使用WKWebView替換UIWebView
開發App的過程中,常常會遇到在App內部載入網頁,通常用
UIWebView
載入。這個自iOS2開始使用的網頁載入器一直是開發的心病
:載入速度慢,佔用記憶體多,優化困難。如果載入網頁多,還可能因為過量佔用記憶體而給系統kill
掉。各種優化的方法效果也不那麼明顯(點選檢視常用優化方法)。
iOS8以後,蘋果推出了新框架Webkit
,提供了替換UIWebView
的元件WKWebView
。各種UIWebView
的問題沒有了,速度更快了,佔用記憶體少了,一句話,WKWebView
是App內部載入網頁的最佳選擇!
先看下 WKWebView
的特性:
- 在效能、穩定性、功能方面有很大提升(最直觀的體現就是載入網頁是佔用的記憶體,模擬器載入百度與開源中國網站時,WKWebView佔用23M,而UIWebView佔用85M);
- 允許JavaScript的Nitro庫載入並使用(UIWebView中限制);
- 支援了更多的HTML5特性;
- 高達60fps的滾動重新整理率以及內建手勢;
- 將UIWebViewDelegate與UIWebView重構成了14類與3個協議(檢視蘋果官方文件);
然後從以下幾個方面說下WKWebView
的基本用法:
- 載入網頁
- 載入的狀態回撥
- 新的
WKUIDelegate
協議 - 動態載入並執行
JS
程式碼 - webView 執行
JS
程式碼 -
JS
呼叫App註冊過的方法
一、載入網頁
載入網頁或HTML程式碼的方式與UIWebView
相同,程式碼示例如下:
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[self.view addSubview:webView];
二、載入的狀態回撥 (WKNavigationDelegate)
用來追蹤載入過程(頁面開始載入、載入完成、載入失敗)的方法:
// 頁面開始載入時呼叫
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 當內容開始返回時呼叫
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 頁面載入完成之後呼叫
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 頁面載入失敗時呼叫
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
頁面跳轉的代理方法:
// 接收到伺服器跳轉請求之後呼叫
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到響應後,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在傳送請求之前,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
三、新的WKUIDelegate
協議
這個協議主要用於WKWebView
處理web介面的三種提示框(警告框、確認框、輸入框),下面是警告框的例子:
/**
* web介面中有彈出警告框時呼叫
*
* @param webView 實現該代理的webview
* @param message 警告框中的內容
* @param frame 主視窗
* @param completionHandler 警告框消失呼叫
*/
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;
四、動態載入並執行JS
程式碼
用於在客戶端內部加入JS
程式碼,並執行,示例如下:
// 圖片縮放的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 + '張圖');";
// 根據JS字串初始化WKUserScript物件
WKUserScript *script = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
// 根據生成的WKUserScript物件,初始化WKWebViewConfiguration
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config.userContentController addUserScript:script];
_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
[_webView loadHTMLString:@"<head></head><image src='http://www.nsu.edu.cn/v/2014v3/img/background/3.jpg' />"baseURL:nil];
[self.view addSubview:_webView];
五、webView 執行JS
程式碼
使用者呼叫用JS
寫過的程式碼,一般指服務端開發的:
//javaScriptString是JS方法名,completionHandler是非同步回撥block
[self.webView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
六、JS
呼叫App註冊過的方法
再WKWebView
裡面註冊供JS呼叫的方法,是通過WKUserContentController
類下面的方法:
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
scriptMessageHandler
是代理回撥,JS
呼叫name
方法後,OC
會呼叫scriptMessageHandler
指定的物件。
JS
在呼叫OC
註冊方法的時候要用下面的方式:
window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
注意,name(方法名)是放在中間的,messageBody只能是一個物件,如果要傳多個值,需要封裝成陣列,或者字典。整個示例如下:
//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);
如果你在self
的dealloc
打個斷點,會發現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
思路是另外建立一個代理物件,然後通過代理物件回撥指定的self
,
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
[userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"closeMe"];
執行程式碼,self
釋放了,WeakScriptMessageDelegate
卻沒有釋放啊啊啊!
還需在self
的dealloc
裡面 新增這樣一句程式碼:
[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"closeMe"];
OK,圓滿解決問題!
目前,大多數App需要支援iOS7以上的版本,而WKWebView
只在iOS8後才能用,所以需要一個相容性方案,既iOS7下用UIWebView
,iOS8後用WKWebView
。這個庫提供了這種相容性方案:https://github.com/wangyangcc/IMYWebView
以上部分內容參考自:http://www.brighttj.com/ios/ios-wkwebview-new-features-and-use.html
在本人播客中地址:http://www.wangyangdev.com/2015/11/13/使用WKWebView替換UIWebView/
相關文章
- UIWebview 與WKWebviewUIWebView
- 從 UIWebView 到 WKWebViewUIWebView
- iOS UIWebView、WKWebView注入CookieiOSUIWebViewCookie
- iOS 中UIWebView與WKWebViewiOSUIWebView
- Hybrid治理(UIWebView&WKWebView)UIWebView
- wkwebview和UIWebView除錯技巧WebViewUI除錯
- ios uiwebview wkwebview注意點小記iOSUIWebView
- UIWebView/WKWebView對標籤攔截UIWebView
- 【iOS開發】從UIWebView到WKWebViewiOSUIWebView
- WkWebView攔截替換本地音訊,圖片WebView音訊
- 比UIWebView更強大好用的WKWebViewUIWebView
- iOS UIScrollVIew UITableView UIwebView WKWebView 截全圖,生成全圖方法iOSUIWebView
- iOS 和 H5 互動那些事 (UIWebView、WKWebView 總結篇)iOSH5UIWebView
- HTML 替換元素與非替換元素HTML
- WKWebView 的使用WebView
- Redis 中使用 scan 替換 keysRedis
- 替換tabBartabBar
- 替換(substitution)
- UIWebView的使用小結UIWebView
- iOS WKWebView的使用iOSWebView
- iOS WKWebView 基本使用iOSWebView
- 簡單,使用WKWebViewWebView
- SQL中的替換函式replace()使用SQL函式
- 使用變數替換批量部署GoldenGate變數Go
- js replace替換字串,同時替換多個方法JS字串
- SQL Server 替換SQLServer
- 08:字元替換字元
- RACSubject替換代理
- sed 字串替換字串
- ACM 字串替換ACM字串
- asp字元替換字元
- vi替換命令
- 替換橫槓
- 替換空格 將一個字串中的空格替換成“ ”字串
- WKWebview 的使用及坑WebView
- spring cloud: 使用consul來替換eurekaSpringCloud
- 使用 Ignition 替換 whoops 報錯提示OOP
- 使用列舉ENUM替換Switch或If-Else