WKWebView與Js實(shí)戰(zhàn)

通過本篇文章,至少可以學(xué)習(xí)到:

OC如何給JS注入對(duì)象及JS如何給IOS發(fā)送數(shù)據(jù)

JS調(diào)用alert给郊、confirm淆九、prompt時(shí)炭庙,不采用JS原生提示煌寇,而是使用iOS原生來實(shí)現(xiàn)

如何監(jiān)聽web內(nèi)容加載進(jìn)度阀溶、是否加載完成

如何處理去跨域問題

創(chuàng)建配置類

在創(chuàng)建WKWebView之前银锻,需要先創(chuàng)建配置對(duì)象,用于做一些配置:

WKWebViewConfiguration*config=[[WKWebViewConfigurationalloc]init];

配置偏好設(shè)置

偏好設(shè)置也沒有必須去修改它腐碱,都使用默認(rèn)的就可以了症见,除非你真的需要修改它:

// 設(shè)置偏好設(shè)置

config.preferences=[[WKPreferencesalloc]init];

// 默認(rèn)為0

config.preferences.minimumFontSize=10;

// 默認(rèn)認(rèn)為YES

config.preferences.javaScriptEnabled=YES;

// 在iOS上默認(rèn)為NO谋作,表示不能自動(dòng)通過窗口打開

config.preferences.javaScriptCanOpenWindowsAutomatically=NO;

配置web內(nèi)容處理池

其實(shí)我們沒有必要去創(chuàng)建它遵蚜,因?yàn)樗緵]有屬性和方法:

// web內(nèi)容處理池吭净,由于沒有屬性可以設(shè)置肴甸,也沒有方法可以調(diào)用原在,不用手動(dòng)創(chuàng)建

config.processPool=[[WKProcessPoolalloc]init];

配置Js與Web內(nèi)容交互

WKUserContentController是用于給JS注入對(duì)象的,注入對(duì)象后秽浇,JS端就可以使用:

window.webkit.messageHandlers..postMessage()

來調(diào)用發(fā)送數(shù)據(jù)給iOS端柬焕,比如:

window.webkit.messageHandlers.AppModel.postMessage({body:'傳數(shù)據(jù)'});

AppModel就是我們要注入的名稱击喂,注入以后懂昂,就可以在JS端調(diào)用了没宾,傳數(shù)據(jù)統(tǒng)一通過body傳循衰,可以是多種類型,只支持NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull類型伐蒋。

下面我們配置給JS的main frame注入AppModel名稱迁酸,對(duì)于JS端可就是對(duì)象了:

// 通過JS與webview內(nèi)容交互

config.userContentController=[[WKUserContentControlleralloc]init];

// 注入JS對(duì)象名稱AppModel奸鬓,當(dāng)JS通過AppModel來調(diào)用時(shí)串远,

// 我們可以在WKScriptMessageHandler代理中接收到

[config.userContentControlleraddScriptMessageHandler:selfname:@"AppModel"];

當(dāng)JS通過AppModel發(fā)送數(shù)據(jù)到iOS端時(shí)伸但,會(huì)在代理中收到:

#pragma mark - WKScriptMessageHandler

-(void)userContentController:(WKUserContentController*)userContentController

didReceiveScriptMessage:(WKScriptMessage*)message{

if([message.nameisEqualToString:@"AppModel"]){

// 打印所傳過來的參數(shù)留搔,只支持NSNumber, NSString, NSDate, NSArray,

// NSDictionary, and NSNull類型

NSLog(@"%@",message.body);

}

}

所有JS調(diào)用iOS的部分函喉,都只可以在此處使用哦管呵。當(dāng)然我們也可以注入多個(gè)名稱(JS對(duì)象)捐下,用于區(qū)分功能坷襟。

創(chuàng)建WKWebView

通過唯一的默認(rèn)構(gòu)造器來創(chuàng)建對(duì)象:

self.webView=[[WKWebViewalloc]initWithFrame:self.view.bounds

configuration:config];

[self.viewaddSubview:self.webView];

加載H5頁(yè)面

NSURL*path=[[NSBundlemainBundle]URLForResource:@"test"withExtension:@"html"];

[self.webViewloadRequest:[NSURLRequestrequestWithURL:path]];

配置代理

如果需要處理web導(dǎo)航條上的代理處理婴程,比如鏈接是否可以跳轉(zhuǎn)或者如何跳轉(zhuǎn)档叔,需要設(shè)置代理衙四;而如果需要與在JS調(diào)用alert传蹈、confirm惦界、prompt函數(shù)時(shí)表锻,通過JS原生來處理瞬逊,而不是調(diào)用JS的alert仪或、confirm范删、prompt函數(shù)旨巷,那么需要設(shè)置UIDelegate,在得到響應(yīng)后可以將結(jié)果反饋到JS端:

// 導(dǎo)航代理

self.webView.navigationDelegate=self;

// 與webview UI交互代理

self.webView.UIDelegate=self;

添加對(duì)WKWebView屬性的監(jiān)聽

WKWebView有好多個(gè)支持KVO的屬性若锁,這里只是監(jiān)聽loading又固、title仰冠、estimatedProgress屬性洋只,分別用于判斷是否正在加載、獲取頁(yè)面標(biāo)題舷礼、當(dāng)前頁(yè)面載入進(jìn)度:

// 添加KVO監(jiān)聽

[self.webViewaddObserver:self

forKeyPath:@"loading"

options:NSKeyValueObservingOptionNew

context:nil];

[self.webViewaddObserver:self

forKeyPath:@"title"

options:NSKeyValueObservingOptionNew

context:nil];

[self.webViewaddObserver:self

forKeyPath:@"estimatedProgress"

options:NSKeyValueObservingOptionNew

context:nil];

然后我們就可以實(shí)現(xiàn)KVO處理方法妻献,在loading完成時(shí)育拨,可以注入一些JS到web中熬丧。這里只是簡(jiǎn)單地執(zhí)行一段web中的JS函數(shù):

#pragma mark - KVO

-(void)observeValueForKeyPath:(NSString*)keyPath

ofObject:(id)object

change:(NSDictionary*)change

context:(void*)context{

if([keyPathisEqualToString:@"loading"]){

NSLog(@"loading");

}elseif([keyPathisEqualToString:@"title"]){

self.title=self.webView.title;

}elseif([keyPathisEqualToString:@"estimatedProgress"]){

NSLog(@"progress: %f",self.webView.estimatedProgress);

self.progressView.progress=self.webView.estimatedProgress;

}

// 加載完成

if(!self.webView.loading){

// 手動(dòng)調(diào)用JS代碼

// 每次頁(yè)面完成都彈出來,大家可以在測(cè)試時(shí)再打開

NSString*js=@"callJsAlert()";

[self.webViewevaluateJavaScript:jscompletionHandler:^(id_Nullableresponse,NSError*_Nullableerror){

NSLog(@"response: %@ error: %@",response,error);

NSLog(@"call js alert by native");

}];

[UIViewanimateWithDuration:0.5animations:^{

self.progressView.alpha=0;

}];

}

}

WKUIDelegate

與JS原生的alert怀挠、confirm析蝴、prompt交互,將彈出來的實(shí)際上是我們?cè)拇翱诼塘埽皇荍S的闷畸。在得到數(shù)據(jù)后,由原生傳回到JS:

#pragma mark - WKUIDelegate

-(void)webViewDidClose:(WKWebView*)webView{

NSLog(@"%s",__FUNCTION__);

}

// 在JS端調(diào)用alert函數(shù)時(shí)吞滞,會(huì)觸發(fā)此代理方法佑菩。

// JS端調(diào)用alert時(shí)所傳的數(shù)據(jù)可以通過message拿到

// 在原生得到結(jié)果后盾沫,需要回調(diào)JS,是通過completionHandler回調(diào)

-(void)webView:(WKWebView*)webViewrunJavaScriptAlertPanelWithMessage:(NSString*)messageinitiatedByFrame:(WKFrameInfo*)framecompletionHandler:(void(^)(void))completionHandler{

NSLog(@"%s",__FUNCTION__);

UIAlertController*alert=[UIAlertControlleralertControllerWithTitle:@"alert"message:@"JS調(diào)用alert"preferredStyle:UIAlertControllerStyleAlert];

[alertaddAction:[UIAlertActionactionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*_Nonnullaction){

completionHandler();

}]];

[selfpresentViewController:alertanimated:YEScompletion:NULL];

NSLog(@"%@",message);

}

// JS端調(diào)用confirm函數(shù)時(shí),會(huì)觸發(fā)此方法

// 通過message可以拿到JS端所傳的數(shù)據(jù)

// 在iOS端顯示原生alert得到Y(jié)ES/NO后

// 通過completionHandler回調(diào)給JS端

-(void)webView:(WKWebView*)webViewrunJavaScriptConfirmPanelWithMessage:(NSString*)messageinitiatedByFrame:(WKFrameInfo*)framecompletionHandler:(void(^)(BOOLresult))completionHandler{

NSLog(@"%s",__FUNCTION__);

UIAlertController*alert=[UIAlertControlleralertControllerWithTitle:@"confirm"message:@"JS調(diào)用confirm"preferredStyle:UIAlertControllerStyleAlert];

[alertaddAction:[UIAlertActionactionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*_Nonnullaction){

completionHandler(YES);

}]];

[alertaddAction:[UIAlertActionactionWithTitle:@"取消"style:UIAlertActionStyleCancelhandler:^(UIAlertAction*_Nonnullaction){

completionHandler(NO);

}]];

[selfpresentViewController:alertanimated:YEScompletion:NULL];

NSLog(@"%@",message);

}

// JS端調(diào)用prompt函數(shù)時(shí),會(huì)觸發(fā)此方法

// 要求輸入一段文本

// 在原生輸入得到文本內(nèi)容后,通過completionHandler回調(diào)給JS

-(void)webView:(WKWebView*)webViewrunJavaScriptTextInputPanelWithPrompt:(NSString*)promptdefaultText:(nullableNSString*)defaultTextinitiatedByFrame:(WKFrameInfo*)framecompletionHandler:(void(^)(NSString*__nullableresult))completionHandler{

NSLog(@"%s",__FUNCTION__);

NSLog(@"%@",prompt);

UIAlertController*alert=[UIAlertControlleralertControllerWithTitle:@"textinput"message:@"JS調(diào)用輸入框"preferredStyle:UIAlertControllerStyleAlert];

[alertaddTextFieldWithConfigurationHandler:^(UITextField*_NonnulltextField){

textField.textColor=[UIColorredColor];

}];

[alertaddAction:[UIAlertActionactionWithTitle:@"確定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*_Nonnullaction){

completionHandler([[alert.textFieldslastObject]text]);

}]];

[selfpresentViewController:alertanimated:YEScompletion:NULL];

}

WKNavigationDelegate

如果需要處理web導(dǎo)航操作,比如鏈接跳轉(zhuǎn)、接收響應(yīng)、在導(dǎo)航開始、成功畏浆、失敗等時(shí)要做些處理蝎毡,就可以通過實(shí)現(xiàn)相關(guān)的代理方法:

#pragma mark - WKNavigationDelegate

// 請(qǐng)求開始前挑胸,會(huì)先調(diào)用此代理方法

// 與UIWebView的

// - (BOOL)webView:(UIWebView *)webView

// shouldStartLoadWithRequest:(NSURLRequest *)request

// navigationType:(UIWebViewNavigationType)navigationType;

// 類型,在請(qǐng)求先判斷能不能跳轉(zhuǎn)(請(qǐng)求)

-(void)webView:(WKWebView*)webViewdecidePolicyForNavigationAction:(WKNavigationAction*)navigationActiondecisionHandler:(void(^)(WKNavigationActionPolicy))decisionHandler{

NSString*hostname=navigationAction.request.URL.host.lowercaseString;

if(navigationAction.navigationType==WKNavigationTypeLinkActivated

&&![hostnamecontainsString:@".baidu.com"]){

// 對(duì)于跨域,需要手動(dòng)跳轉(zhuǎn)

[[UIApplicationsharedApplication]openURL:navigationAction.request.URL];

// 不允許web內(nèi)跳轉(zhuǎn)

decisionHandler(WKNavigationActionPolicyCancel);

}else{

self.progressView.alpha=1.0;

decisionHandler(WKNavigationActionPolicyAllow);

}

NSLog(@"%s",__FUNCTION__);

}

// 在響應(yīng)完成時(shí)喘先,會(huì)回調(diào)此方法

// 如果設(shè)置為不允許響應(yīng),web內(nèi)容就不會(huì)傳過來

-(void)webView:(WKWebView*)webViewdecidePolicyForNavigationResponse:(WKNavigationResponse*)navigationResponsedecisionHandler:(void(^)(WKNavigationResponsePolicy))decisionHandler{

decisionHandler(WKNavigationResponsePolicyAllow);

NSLog(@"%s",__FUNCTION__);

}

// 開始導(dǎo)航跳轉(zhuǎn)時(shí)會(huì)回調(diào)

-(void)webView:(WKWebView*)webViewdidStartProvisionalNavigation:(null_unspecifiedWKNavigation*)navigation{

NSLog(@"%s",__FUNCTION__);

}

// 接收到重定向時(shí)會(huì)回調(diào)

-(void)webView:(WKWebView*)webViewdidReceiveServerRedirectForProvisionalNavigation:(null_unspecifiedWKNavigation*)navigation{

NSLog(@"%s",__FUNCTION__);

}

// 導(dǎo)航失敗時(shí)會(huì)回調(diào)

-(void)webView:(WKWebView*)webViewdidFailProvisionalNavigation:(null_unspecifiedWKNavigation*)navigationwithError:(NSError*)error{

NSLog(@"%s",__FUNCTION__);

}

// 頁(yè)面內(nèi)容到達(dá)main frame時(shí)回調(diào)

-(void)webView:(WKWebView*)webViewdidCommitNavigation:(null_unspecifiedWKNavigation*)navigation{

NSLog(@"%s",__FUNCTION__);

}

// 導(dǎo)航完成時(shí),會(huì)回調(diào)(也就是頁(yè)面載入完成了)

-(void)webView:(WKWebView*)webViewdidFinishNavigation:(null_unspecifiedWKNavigation*)navigation{

NSLog(@"%s",__FUNCTION__);

}

// 導(dǎo)航失敗時(shí)會(huì)回調(diào)

-(void)webView:(WKWebView*)webViewdidFailNavigation:(null_unspecifiedWKNavigation*)navigationwithError:(NSError*)error{

}

// 對(duì)于HTTPS的都會(huì)觸發(fā)此代理,如果不要求驗(yàn)證庄呈,傳默認(rèn)就行

// 如果需要證書驗(yàn)證文兑,與使用AFN進(jìn)行HTTPS證書驗(yàn)證是一樣的

-(void)webView:(WKWebView*)webViewdidReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challengecompletionHandler:(void(^)(NSURLSessionAuthChallengeDispositiondisposition,NSURLCredential*__nullablecredential))completionHandler{

NSLog(@"%s",__FUNCTION__);

completionHandler(NSURLSessionAuthChallengePerformDefaultHandling,nil);

}

// 9.0才能使用籍铁,web內(nèi)容處理中斷時(shí)會(huì)觸發(fā)

-(void)webViewWebContentProcessDidTerminate:(WKWebView*)webView{

NSLog(@"%s",__FUNCTION__);

}

JS端代碼

iOSandJs

*{

font-size:40px;

}

Testhowtouseobjective-ccalljs

Clickmehere:JumptoBaidu

functioncallJsAlert(){

alert('Objective-C call js to show alert');

window.webkit.messageHandlers.AppModel.postMessage({body:'call js alert in js'});

}

functioncallJsConfirm(){

if(confirm('confirm','Objective-C call js to show confirm')){

document.getElementById('jsParamFuncSpan').innerHTML

='true';

}else{

document.getElementById('jsParamFuncSpan').innerHTML

='false';

}

// AppModel是我們所注入的對(duì)象

window.webkit.messageHandlers.AppModel.postMessage({body:'call js confirm in js'});

}

functioncallJsInput(){

varresponse=prompt('Hello','Please input your name:');

document.getElementById('jsParamFuncSpan').innerHTML=response;

// AppModel是我們所注入的對(duì)象

window.webkit.messageHandlers.AppModel.postMessage({body:response});

}

停下休息的時(shí)候不要忘記別人在奔跑!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末炸站,一起剝皮案震驚了整個(gè)濱河市咒唆,隨后出現(xiàn)的幾起案子误债,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笆制,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡奕删,警方通過查閱死者的電腦和手機(jī)谨设,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸥诽,“玉大人地回,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵沟优,是天一觀的道長(zhǎng)锨用。 經(jīng)常有香客問我棵帽,道長(zhǎng),這世上最難降的妖魔是什么星掰? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任镰绎,我火速辦了婚禮,結(jié)果婚禮上沸停,老公的妹妹穿的比我還像新娘。我一直安慰自己镜硕,他們只是感情好晚顷,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布庞瘸。 她就那樣靜靜地躺著,像睡著了一般看幼。 火紅的嫁衣襯著肌膚如雪搬卒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天叉袍,我揣著相機(jī)與錄音转唉,去河邊找鬼款侵。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的娜氏。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起练湿,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吊圾,沒想到半個(gè)月后达椰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡街夭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年砰碴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躏筏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片板丽。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出埃碱,到底是詐尸還是另有隱情猖辫,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布砚殿,位于F島的核電站啃憎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏似炎。R本人自食惡果不足惜辛萍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望羡藐。 院中可真熱鬧贩毕,春花似錦、人聲如沸仆嗦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瘩扼。三九已至谆甜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間集绰,已是汗流浹背规辱。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留栽燕,地道東北人按摘。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像纫谅,于是被迫代替她去往敵國(guó)和親炫贤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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

  • 前言 上一篇專門講解了WKWebView相關(guān)的所有類付秕、代理的所有API兰珍。前篇文章地址:http://blog.cs...
    iwolfox閱讀 1,108評(píng)論 1 1
  • 通過本篇文章,至少可以學(xué)習(xí)到: OC如何給JS注入對(duì)象及JS如何給IOS發(fā)送數(shù)據(jù) JS調(diào)用alert询吴、confir...
    一個(gè)叫小強(qiáng)的程序猿閱讀 1,154評(píng)論 2 0
  • 場(chǎng)景:使用Wi-Fi連接的內(nèi)網(wǎng)web 服務(wù) 構(gòu)思&準(zhǔn)備 需要有雙網(wǎng)卡的電腦或服務(wù)器一臺(tái) 連接資源寶發(fā)射的Wi-Fi...
    cielu閱讀 1,615評(píng)論 0 2
  • 古人曰:“見字如見人掠河。”而我想說猛计,見字如聞其心唠摹。我不知道別人怎么樣,但我知道我必須心非常非常地靜時(shí)奉瘤,我的字才能看勾拉。...
    無心悠悠然閱讀 644評(píng)論 6 1
  • 1煮甥、有一次聽高三復(fù)習(xí)課,聽旁邊一男生嘀咕藕赞,啊成肘,劉蘭芝和焦仲卿結(jié)婚了? 2斧蜕、高一双霍,我問課文中為什么詳寫劉蘭芝在辭別婆...
    最憐天上月q閱讀 740評(píng)論 0 1