iOS WKWebView 如何使用

apple官方文檔https://developer.apple.com/documentation/webkit

WKWebView 是蘋果在iOS 8中引入的新組件父叙,目的是提供一個(gè)現(xiàn)代的支持最新Webkit功能的網(wǎng)頁(yè)瀏覽控件趾唱,擺脫過(guò)去 UIWebView的老蜻懦、舊、笨悠咱,特別是內(nèi)存占用量巨大的問(wèn)題析既。它使用與Safari中一樣的Nitro JavaScript引擎谆奥,大大提高了頁(yè)面js執(zhí)行速度。

相比于UIWebView的優(yōu)勢(shì):?

在性能空骚、穩(wěn)定性擂仍、占用內(nèi)存方面有很大提升逢渔;?

允許JavaScript的Nitro庫(kù)加載并使用(UIWebView中限制)?

增加加載進(jìn)度屬性:estimatedProgress肃廓,不用在自己寫假進(jìn)度條了?支持了更多的HTML的屬性

具體分析WKWebView的優(yōu)劣勢(shì)

內(nèi)存占用是UIWebView的1/4~1/3

頁(yè)面加載速度有提升诲泌,有的文章說(shuō)它的加載速度比UIWebView提升了一倍左右。

更為細(xì)致地拆分了 UIWebViewDelegate 中的方法

自帶進(jìn)度條哀蘑。不需要像UIWebView一樣自己做假進(jìn)度條(通過(guò)NJKWebViewProgress和雙層代理技術(shù)實(shí)現(xiàn))绘迁,技術(shù)復(fù)雜度和代碼量,根貼近實(shí)際加載進(jìn)度優(yōu)化好的多棠赛。

允許JavaScript的Nitro庫(kù)加載并使用(UIWebView中限制)

可以和js直接互調(diào)函數(shù)睛约,不像UIWebView需要第三方庫(kù)WebViewJavascriptBridge來(lái)協(xié)助處理和js的交互哲身。

不支持頁(yè)面緩存,需要自己注入cookie,而UIWebView是自動(dòng)注入cookie膀值。

無(wú)法發(fā)送POST參數(shù)問(wèn)題

基本參數(shù)解釋:

WKWebView:網(wǎng)頁(yè)的渲染與展示沧踏,通過(guò)WKWebViewConfiguration可以進(jìn)行自定義配置巾钉。

WKWebViewConfiguration:這個(gè)類專門用來(lái)配置WKWebView。

WKPreference:這個(gè)類用來(lái)進(jìn)行相關(guān)webView設(shè)置潦匈。

WKProcessPool:這個(gè)類用來(lái)配置進(jìn)程池赚导,與網(wǎng)頁(yè)視圖的資源共享有關(guān)吼旧。

WKUserContentController:這個(gè)類主要用來(lái)做native與JavaScript的交互管理。

WKUserScript:用于進(jìn)行JavaScript注入掂为。

WKScriptMessageHandler:這個(gè)類專門用來(lái)處理JavaScript調(diào)用native的方法员串。

WKNavigationDelegate:網(wǎng)頁(yè)跳轉(zhuǎn)間的導(dǎo)航管理協(xié)議寸齐,這個(gè)協(xié)議可以監(jiān)聽(tīng)網(wǎng)頁(yè)的活動(dòng)抄谐。

WKNavigationAction:網(wǎng)頁(yè)某個(gè)活動(dòng)的示例化對(duì)象斯稳。

WKUIDelegate:用于交互處理JavaScript中的一些彈出框迹恐。

WKBackForwardList:堆棧管理的網(wǎng)頁(yè)列表殴边。

WKBackForwardListItem:每個(gè)網(wǎng)頁(yè)節(jié)點(diǎn)對(duì)象。

1.加載網(wǎng)頁(yè)

WKWebViewConfiguration *webConfiguration = [WKWebViewConfiguration new];

???WKWebView *webView=[[WKWebView alloc]initWithFrame:CGRectZero configuration:webConfiguration];

????[self.view addSubview:self.webView];

????[webView mas_makeConstraints:^(MASConstraintMaker *make) {

????????make.top.offset(self.zxNavigationbarHeight);

????????make.left.right.offset(0);

????????make.bottom.offset(0);

????}];

????NSURL *url = [NSURL URLWithString:self.strUrl];

????NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];

????[webView loadRequest:request];

2.進(jìn)度條和標(biāo)題

????_progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, self.zxNavigationbarHeight,?????????????????????????????????????????????????????self.view.frame.size.width, 2)];

????_progressView.tintColor = [UIColor blueColor];

????_progressView.trackTintColor = [UIColor clearColor];

????[self.view addSubview:_progressView];

//添加監(jiān)測(cè)網(wǎng)頁(yè)加載進(jìn)度的觀察者

????[self.webView addObserver:self

???????????????????forKeyPath:NSStringFromSelector(@selector(estimatedProgress))

??????????????????????options:0

??????????????????????context:nil];

????[self.webView addObserver:self

???????????????????forKeyPath:@"title"

??????????????????????options:NSKeyValueObservingOptionNew

??????????????????????context:nil];

//kvo 監(jiān)聽(tīng)進(jìn)度和標(biāo)題 必須實(shí)現(xiàn)此方法

-(void)observeValueForKeyPath:(NSString *)keyPath

?????????????????????ofObject:(id)object

???????????????????????change:(NSDictionary<NSKeyValueChangeKey,id> *)change

??????????????????????context:(void *)context{


????if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))]

????????&& object == _webView) {


????????DDLog(@"網(wǎng)頁(yè)加載進(jìn)度 = %f",_webView.estimatedProgress);

????????self.progressView.progress = _webView.estimatedProgress;

????????if (_webView.estimatedProgress >= 1.0f) {

????????????dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

????????????????self.progressView.progress = 0;

????????????});

????????}


????}else if([keyPath isEqualToString:@"title"]

?????????????&& object == _webView){

????????self.navigationItem.title = _webView.title;

????}else{

????????[super observeValueForKeyPath:keyPath

?????????????????????????????ofObject:object

???????????????????????????????change:change

??????????????????????????????context:context];

????}

}

- (void)dealloc{

????//移除觀察者

????[_webView removeObserver:self

??????????????????forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];

????[_webView removeObserver:self

??????????????????forKeyPath:NSStringFromSelector(@selector(title))];

}

3.刷新、上一頁(yè)拳氢、下一頁(yè)

- (void)goBackAction:(id)sender{

????if ([self.webView canGoBack]) {

????????[self.webView goBack];

????}

}

- (void)refreshAction:(id)sender{

????[self.webView reload];

}

-(void)goNextAction:(id)sender{

????if ([self.webView canGoForward]) {

????????[self.webView goForward];

????}

}

4.OC調(diào)用JS

//OC調(diào)用JS

- (void)ocToJs{

????//changeColor()是JS方法名馋评,completionHandler是異步回調(diào)block

????NSString *jsString = [NSString stringWithFormat:@"changeColor('%@')", @"Js顏色參數(shù)"];

????[_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {

????????DDLog(@"改變HTML的背景色");

????}];


????//改變字體大小 調(diào)用原生JS方法

????NSString *jsFont = [NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", arc4random()%99 + 100];

????[_webView evaluateJavaScript:jsFont completionHandler:nil];


????NSString * path =??[[NSBundle mainBundle] pathForResource:@"girl" ofType:@"png"];

????NSString *jsPicture = [NSString stringWithFormat:@"changePicture('%@','%@')", @"pictureId",path];

????[_webView evaluateJavaScript:jsPicture completionHandler:^(id _Nullable data, NSError * _Nullable error) {

????????DDLog(@"切換本地頭像");

????}];


}

//OC調(diào)用JS改變背景色

????function changeColor(parameter)

????{

????????document.body.style.backgroundColor = randomColor();

????}

5.JS調(diào)用OC

//方式一.WKNavigationDelegate通過(guò)即將跳轉(zhuǎn)的url攔截

// 根據(jù)WebView對(duì)于即將跳轉(zhuǎn)的HTTP請(qǐng)求頭信息和相關(guān)信息來(lái)決定是否跳轉(zhuǎn)

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


????NSString * urlStr = navigationAction.request.URL.absoluteString;

????NSLog(@"發(fā)送跳轉(zhuǎn)請(qǐng)求:%@",urlStr);

????//自己定義的協(xié)議頭

????NSString *htmlHeadString = @"github://";

????if([urlStr hasPrefix:htmlHeadString]){

????????UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"通過(guò)截取URL調(diào)用OC" message:@"你想前往我的Github主頁(yè)?" preferredStyle:UIAlertControllerStyleAlert];

????????[alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {


????????}])];

????????[alertController addAction:([UIAlertAction actionWithTitle:@"打開(kāi)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

????????????NSURL * url = [NSURL URLWithString:[urlStr stringByReplacingOccurrencesOfString:@"github://callName_?" withString:@""]];

????????????[[UIApplication sharedApplication] openURL:url];


????????}])];

????????[self presentViewController:alertController animated:YES completion:nil];


????????decisionHandler(WKNavigationActionPolicyCancel);


????}else{

????????decisionHandler(WKNavigationActionPolicyAllow);

????}

}

//方式二.WKScriptMessageHandler注冊(cè)相應(yīng)交互事件

//自定義的WKScriptMessageHandler 是為了解決內(nèi)存不釋放的問(wèn)題

????????WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];

????????//這個(gè)類主要用來(lái)做native與JavaScript的交互管理

????????WKUserContentController * wkUController = [[WKUserContentController alloc] init];

????????//注冊(cè)一個(gè)name為jsToOcNoPrams的js方法 設(shè)置處理接收J(rèn)S方法的對(duì)象

????????[wkUController addScriptMessageHandler:weakScriptMessageDelegate??name:@"jsToOcNoPrams"];

????????[wkUController addScriptMessageHandler:weakScriptMessageDelegate??name:@"jsToOcWithPrams"];


????????config.userContentController = wkUController;

- (void)dealloc{

????//移除注冊(cè)的js方法

????[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcNoPrams"];

????[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcWithPrams"];

}

//被自定義的WKScriptMessageHandler在回調(diào)方法里通過(guò)代理回調(diào)回來(lái),繞了一圈就是為了解決內(nèi)存不釋放的問(wèn)題

//通過(guò)接收J(rèn)S傳出消息的name進(jìn)行捕捉的回調(diào)方法

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

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

????//用message.body獲得JS傳出的參數(shù)體

????NSDictionary * parameter = message.body;

????//JS調(diào)用OC

????if([message.name isEqualToString:@"jsToOcNoPrams"]){

????????UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js調(diào)用到了oc" message:@"不帶參數(shù)" preferredStyle:UIAlertControllerStyleAlert];

????????[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

????????}])];

????????[self presentViewController:alertController animated:YES completion:nil];


????}else if([message.name isEqualToString:@"jsToOcWithPrams"]){

????????UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js調(diào)用到了oc" message:parameter[@"params"] preferredStyle:UIAlertControllerStyleAlert];

????????[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

????????}])];

????????[self presentViewController:alertController animated:YES completion:nil];

????}

}

function jsToOcFunction1()

????{

???????window.webkit.messageHandlers.jsToOcNoPrams.postMessage({});

????}


????function jsToOcFunction2()

????{

????????window.webkit.messageHandlers.jsToOcWithPrams.postMessage({"params":"我是參數(shù)"});

????}

//方式三.WKUIDelegate捕獲系統(tǒng)交互

/**

*??web界面中有彈出警告框時(shí)調(diào)用

*

*??@param webView??????????實(shí)現(xiàn)該代理的webview

*??@param message??????????警告框中的內(nèi)容

*??@param completionHandler 警告框消失調(diào)用

*/

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

????UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"HTML的彈出框" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];

????[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

????????completionHandler();

????}])];

????[self presentViewController:alertController animated:YES completion:nil];

}

// 確認(rèn)框

//JavaScript調(diào)用confirm方法后回調(diào)的方法 confirm是js中的確定框,需要在block中把用戶選擇的情況傳遞進(jìn)去

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

????UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];

????[alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

????????completionHandler(NO);

????}])];

????[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

????????completionHandler(YES);

????}])];

????[self presentViewController:alertController animated:YES completion:nil];

}

// 輸入框

//JavaScript調(diào)用prompt方法后回調(diào)的方法 prompt是js中的輸入框 需要在block中把用戶輸入的信息傳入

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

????UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];

????[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {

????????textField.text = defaultText;

????}];

????[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

????????completionHandler(alertController.textFields[0].text?:@"");

????}])];

????[self presentViewController:alertController animated:YES completion:nil];

}

// 頁(yè)面是彈出窗口 _blank 處理

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

????if (!navigationAction.targetFrame.isMainFrame) {

????????[webView loadRequest:navigationAction.request];

????}

????return nil;

}

function showAlert()

????{

????????alert("被OC截獲到了");

????}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渺绒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌采缚,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篡帕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡镰烧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門茉唉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)度陆,“玉大人,你說(shuō)我怎么就攤上這事懂傀±校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵犀斋,是天一觀的道長(zhǎng)闪水。 經(jīng)常有香客問(wèn)我,道長(zhǎng)球榆,這世上最難降的妖魔是什么禁筏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮每强,結(jié)果婚禮上州刽,老公的妹妹穿的比我還像新娘。我一直安慰自己穗椅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布门坷。 她就那樣靜靜地躺著,像睡著了一般默蚌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绸吸,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天惯裕,我揣著相機(jī)與錄音,去河邊找鬼撑刺。 笑死握玛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挠铲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼安聘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瓢棒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起脯宿,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤连霉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后窟感,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肌括,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年谍夭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了紧索。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菜谣。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖尾膊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情待笑,我是刑警寧澤抓谴,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站仰泻,受9級(jí)特大地震影響滩届,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帜消,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一券犁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粘衬,春花似錦、人聲如沸稚新。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至轴术,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逗栽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工彼宠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凭峡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓摧冀,卻偏偏與公主長(zhǎng)得像霉涨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子楼镐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355