IOS進(jìn)階之WKWebView

2016-10-26o翻滾的牛寶寶oCocoaChina

▲點(diǎn)擊上方“CocoaChina”關(guān)注即可免費(fèi)學(xué)習(xí)iOS開發(fā)

原文鏈接:http://www.lxweimin.com/p/4fa8c4eb1316

前言

Xcode8發(fā)布以后,編譯器開始不支持IOS7,所以很多應(yīng)用在適配IOS10之后都不在適配IOS7了,其中包括了很多大公司,網(wǎng)易新聞,滴滴出行等。因此,我們公司的應(yīng)用也打算淘汰IOS7。

支持到IOS8,第一個(gè)要改的自然是用WKWebView替換原來的UIWebView。WKWebView有很多明顯優(yōu)勢(shì):

更多的支持HTML5的特性

官方宣稱的高達(dá)60fps的滾動(dòng)刷新率以及內(nèi)置手勢(shì)

將UIWebViewDelegate與UIWebView拆分成了14類與3個(gè)協(xié)議,以前很多不方便實(shí)現(xiàn)的功能得以實(shí)現(xiàn)。文檔

Safari相同的JavaScript引擎

占用更少的內(nèi)存

UIWebView

WKWebView

因此,使用WkWebview替換UIWebView還是很有必要的。

基本使用方法

WKWebView有兩個(gè)delegate,WKUIDelegateWKNavigationDelegate

WKNavigationDelegate主要處理一些跳轉(zhuǎn)、加載處理操作,WKUIDelegate主要處理JS腳本,確認(rèn)框,警告框等。因此WKNavigationDelegate更加常用。

比較常用的方法:

#pragma mark - lifeCircle

- (void)viewDidLoad {

[super viewDidLoad];

webView = [[WKWebView alloc]init];

[self.view addSubview:webView];

[webView mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(self.view);

make.right.equalTo(self.view);

make.top.equalTo(self.view);

make.bottom.equalTo(self.view);

}];

webView.UIDelegate = self;

webView.navigationDelegate = self;

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];

}

#pragma mark - 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{

}

// 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求之后調(diào)用

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{

}

// 在收到響應(yīng)后,決定是否跳轉(zhuǎn)

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{

NSLog(@"%@",navigationResponse.response.URL.absoluteString);

//允許跳轉(zhuǎn)

decisionHandler(WKNavigationResponsePolicyAllow);

//不允許跳轉(zhuǎn)

//decisionHandler(WKNavigationResponsePolicyCancel);

}

// 在發(fā)送請(qǐng)求之前,決定是否跳轉(zhuǎn)

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{

NSLog(@"%@",navigationAction.request.URL.absoluteString);

//允許跳轉(zhuǎn)

decisionHandler(WKNavigationActionPolicyAllow);

//不允許跳轉(zhuǎn)

//decisionHandler(WKNavigationActionPolicyCancel);

}

#pragma mark - WKUIDelegate

// 創(chuàng)建一個(gè)新的WebView

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{

return [[WKWebView alloc]init];

}

// 輸入框

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler{

completionHandler(@"http");

}

// 確認(rèn)框

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{

completionHandler(YES);

}

// 警告框

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{

NSLog(@"%@",message);

completionHandler();

}

OC與JS交互

WKWebview提供了API實(shí)現(xiàn)js交互 不需要借助JavaScriptCore或者webJavaScriptBridge。使用WKUserContentController實(shí)現(xiàn)js native交互。簡單的說就是先注冊(cè)約定好的方法,然后再調(diào)用。

JS調(diào)用OC方法

oc代碼(有誤,內(nèi)存不釋放):

@interface ViewController (){

WKWebView * webView;

WKUserContentController* userContentController;

}

@end

@implementation ViewController

#pragma mark - lifeCircle

- (void)viewDidLoad {

[super viewDidLoad];

//配置環(huán)境

WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];

userContentController =[[WKUserContentController alloc]init];

configuration.userContentController = userContentController;

webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, 100, 100) configuration:configuration];

//注冊(cè)方法

[userContentController addScriptMessageHandler:self ?name:@"sayhello"];//注冊(cè)一個(gè)name為sayhello的js方法

[self.view addSubview:webView];

[webView mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(self.view);

make.right.equalTo(self.view);

make.top.equalTo(self.view);

make.bottom.equalTo(self.view);

}];

webView.UIDelegate = self;

webView.navigationDelegate = self;

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.test.com"]]];

}

- (void)dealloc{

//這里需要注意,前面增加過的方法一定要remove掉。

[userContentController removeScriptMessageHandlerForName:@"sayhello"];

}

#pragma mark - WKScriptMessageHandler

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

NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);

}

@end

上面的OC代碼如果認(rèn)證測(cè)試一下就會(huì)發(fā)現(xiàn)dealloc并不會(huì)執(zhí)行,這樣肯定是不行的,會(huì)造成內(nèi)存泄漏。原因是[userContentController addScriptMessageHandler:self ?name:@"sayhello"];這句代碼造成無法釋放內(nèi)存。(ps:試了下用weak指針還是不能釋放,不知道是什么原因。)因此還需要進(jìn)一步改進(jìn),正確的寫法是用一個(gè)新的controller來處理,新的controller再繞用delegate繞回來。

oc代碼(正確寫法):

@interface ViewController (){

WKWebView * webView;

WKUserContentController* userContentController;

}

@end

@implementation ViewController

#pragma mark - lifeCircle

- (void)viewDidLoad {

[super viewDidLoad];

//配置環(huán)境

WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];

userContentController =[[WKUserContentController alloc]init];

configuration.userContentController = userContentController;

webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, 100, 100) configuration:configuration];

//注冊(cè)方法

WKDelegateController * delegateController = [[WKDelegateController alloc]init];

delegateController.delegate = self;

[userContentController addScriptMessageHandler:delegateController ?name:@"sayhello"];

[self.view addSubview:webView];

[webView mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(self.view);

make.right.equalTo(self.view);

make.top.equalTo(self.view);

make.bottom.equalTo(self.view);

}];

webView.UIDelegate = self;

webView.navigationDelegate = self;

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.test.com"]]];

}

- (void)dealloc{

//這里需要注意,前面增加過的方法一定要remove掉。

[userContentController removeScriptMessageHandlerForName:@"sayhello"];

}

#pragma mark - WKScriptMessageHandler

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

NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);

}

@end

WKDelegateController代碼:

#import

#import

@protocol WKDelegate

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

@end

@interface WKDelegateController : UIViewController

@property (weak , nonatomic) id delegate;

@end

.m代碼:

#import "WKDelegateController.h"

@interface WKDelegateController ()

@end

@implementation WKDelegateController

- (void)viewDidLoad {

[super viewDidLoad];

}

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

if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) {

[self.delegate userContentController:userContentController didReceiveScriptMessage:message];

}

}

@end

h5代碼:

function say()

{

//前端需要用 window.webkit.messageHandlers.注冊(cè)的方法名.postMessage({body:傳輸?shù)臄?shù)據(jù)} 來給native發(fā)送消息

window.webkit.messageHandlers.sayhello.postMessage({body: 'hello world!'});

}

hello world

say hello

打印出的log:

name:sayhello

body:{

body = "hello world!";

}

frameInfo: { URL: http://www.test.com/ }>

注意點(diǎn)

addScriptMessageHandler要和removeScriptMessageHandlerForName配套出現(xiàn),否則會(huì)造成內(nèi)存泄漏。

h5只能傳一個(gè)參數(shù),如果需要多個(gè)參數(shù)就需要用字典或者json組裝。

oc調(diào)用JS方法

代碼如下:

- (void)webView:(WKWebView *)tmpWebView didFinishNavigation:(WKNavigation *)navigation{

//say()是JS方法名,completionHandler是異步回調(diào)block

[webView evaluateJavaScript:@"say()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {

NSLog(@"%@",result);

}];

}

h5代碼同上。

WebViewJavascriptBridge

一般來說,一個(gè)好的UI總有一個(gè)大神會(huì)開發(fā)出一個(gè)好的第三方封裝框架。WebViewJavascriptBridge的作者也做了一套支持WKWebView與JS交互的第三方框架:WKWebViewJavascriptBridge。

cocoaPods: pod 'WebViewJavascriptBridge', '~> 5.0.5'

github地址https://github.com/marcuswestin/WebViewJavascriptBridge

主要方法如下:

//初始化方法

+ (instancetype)bridgeForWebView:(WKWebView*)webView;

+ (void)enableLogging;

//注冊(cè)函數(shù)名

- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler;

//調(diào)用函數(shù)名

- (void)callHandler:(NSString*)handlerName;

- (void)callHandler:(NSString*)handlerName data:(id)data;

- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback;

//重置

- (void)reset;

//設(shè)置WKNavigationDelegate

- (void)setWebViewDelegate:(id)webViewDelegate;

基本的實(shí)現(xiàn)方法和上面寫的差不多,就是封裝了一下,有興趣的童鞋可以自己pod下來使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,115評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,234評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,621評(píng)論 1 326
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,822評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,380評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,128評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,319評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,548評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評(píng)論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,048評(píng)論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,285評(píng)論 2 376

推薦閱讀更多精彩內(nèi)容

  • Xcode8發(fā)布以后,編譯器開始不支持IOS7,所以很多應(yīng)用在適配IOS10之后都不在適配IOS7了,其中包括了很...
    王憲嶺閱讀 1,161評(píng)論 0 0
  • 前言 Xcode8發(fā)布以后,編譯器開始不支持IOS7,所以很多應(yīng)用在適配IOS10之后都不在適配IOS7了,其中包...
    Zoneday閱讀 2,059評(píng)論 0 2
  • 1、加載網(wǎng)頁 WKWebView *webView = [[WKWebView alloc] initWithFr...
    LearningCoding閱讀 3,139評(píng)論 0 2
  • 前言 關(guān)于UIWebView的介紹,相信看過上文的小伙伴們,已經(jīng)大概清楚了吧,如果有問題,歡迎提問。 本文是本系列...
    CoderLF閱讀 9,007評(píng)論 2 12
  • 銅管樂器以及感知力 音樂表達(dá)更多的是,抽象內(nèi)涵,多數(shù)難以用簡單的畫面,色彩,圖形展示。。音色也是豐富,穿透力,朦朧...
    咔辣辣閱讀 166評(píng)論 0 0