iOS8之后,蘋果推出了WebKit這個框架,用來替換原有的UIWebView,新的控件優點多多,不一一敘述。由于一直在適配iOS7,就沒有去替換,現在仍掉了iOS7,以為很簡單的就替換過來了,然而在替換的過程中,卻遇到了很多坑。
WKWebView使用及注意點
WKWebView只能用代碼創建,而且自身就支持了右滑返回手勢allowsBackForwardNavigationGestures和加載進度estimatedPRogress等一些UIWebView不具備卻非常好用的屬性。在創建的時候,指定初始化方法中要求傳入一個WKWebViewConfiguration對象,一般我們使用默認配置就好,但是有些地方是要根據自己的情況去做更改。比如,配置中的allowsInlineMediaPlayback這個屬性,默認為NO,如果不做更改,網頁中的視頻將彈出一個全屏的控制器來播放,設置為YES,將內嵌在網頁中播放。更改User-Agent
有時我們需要在User-Agent添加一些額外的信息,這時就要更改默認的User-Agent.self.wkWebView = [[WKWebView alloc] initWithFrame:CGRectZero];//獲取默認User-Agent[self.wkWebView evaluatejavaScr需要注意的是App內所有Web請求的User-Agent全部被修改。在iOS9,WKWebView提供了一個非常便捷的屬性去更改User-Agent,就是customUserAgent屬性。這樣使用起來不僅方便,也不會全局更改User-Agent,可惜的是iOS9才有,如果適配iOS8,還是要使用上面的方法。
用來追蹤加載過程(頁面開始加載、加載完成、加載失敗)的方法: // 頁面開始加載時調用 -(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;
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"];新聞熱點
疑難解答