WKWebview的使用詳解 以及WKWebview存在的坑點(diǎn)

雖然WKWebView是在Apple的WWDC 2014隨iOS 8和OS X 10.10出來(lái)的,是為了解決UIWebView加載速度慢谒所、占用內(nèi)存大的問(wèn)題沛申。但是由于之前還要適配iOS7庶弃,所以就沒有使用“鹪欤現(xiàn)在項(xiàng)目都適配iOS 8以上了忽肛,所以就開始使用WKWebView了烂斋,但是發(fā)現(xiàn)在使用的時(shí)候有好多坑屹逛,希望這篇文章能帶大家繞過(guò)坑,更好的使用WKWebView帘瞭。
這篇文章主要介紹了以下問(wèn)題淑掌,方便小伙伴們查閱:

  1. WKWebView的基本介紹和使用
  2. WKWebView和JavaScript的交互
  3. WKWebView 默認(rèn)不彈出js的alert問(wèn)題
  4. WKWebView 默認(rèn)是不能識(shí)別電話號(hào)碼
  5. WKWebView 攔截js通過(guò)window.open() 打開的窗口
  6. WKWebView解決文字顯示太小問(wèn)題

下面開始說(shuō)第一個(gè)問(wèn)題** WKWebView**基本使用

1.創(chuàng)建 跟UIWebview 一樣

// 創(chuàng)建WKWebView
    WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    // 設(shè)置訪問(wèn)的URL
    NSURL *url = [NSURL URLWithString:@"http://www.reibang.com"];
    // 根據(jù)URL創(chuàng)建請(qǐng)求
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // WKWebView加載請(qǐng)求
    [webView loadRequest:request];
    // 將WKWebView添加到視圖
    [self.view addSubview:webView];

UIWebView和WKWebView的代理方法做一個(gè)對(duì)比
1.準(zhǔn)備加載頁(yè)面

UIWebViewDelegate: - webView:shouldStartLoadWithRequest:navigationType
 WKNavigationDelegate: - webView:didStartProvisionalNavigation:

2.內(nèi)容開始加載

UIWebViewDelegate: - webViewDidStartLoad:
 WKNavigationDelegate: - webView:didCommitNavigation:

3.頁(yè)面加載完成

UIWebViewDelegate: - webViewDidFinishLoad:
 WKNavigationDelegate: - webView:didFinishNavigation:

4.頁(yè)面加載失敗

UIWebViewDelegate: - webView:didFailLoadWithError:
 WKNavigationDelegate: - webView:didFailNavigation:withError:
 WKNavigationDelegate: - webView:didFailProvisionalNavigation:withError:

可以看到很簡(jiǎn)單,和UIWebView并沒有多少差別蝶念,然而性能就刷刷刷的提上去了抛腕,是不是很爽呢?如果你只是簡(jiǎn)單的集成個(gè)Web頁(yè)到App媒殉,這些已經(jīng)夠了担敌。不過(guò)很多時(shí)候并沒有那么簡(jiǎn)單,還需要處理各種東西适袜,那么接著往后看柄错。

接下來(lái)我們開始說(shuō)第二個(gè)問(wèn)題 WKWebView和JavaScript的交互

WKWebView和JavaScript的交互主要涉及到兩個(gè)方面,一個(gè)是OC調(diào)用JavaScript ,另一個(gè)是 JavaScript 調(diào)用OC的方法,

在WebKit框架中,有WKWebView可以替換UIKit的UIWebView和AppKit的WebView苦酱,而且提供了在兩個(gè)平臺(tái)可以一致使用的接口售貌。WebKit框架使得開發(fā)者可以在原生App中使用Nitro來(lái)提高網(wǎng)頁(yè)的性能和表現(xiàn),Nitro就是Safari的JavaScript引擎,WKWebView不支持JavaScriptCore的方式但提供message handler的方式為JavaScript與Native通信疫萤。(這個(gè)引自天狐博客颂跨,更多的與UIWebView或者WKWebView的交互方法可以在這里看到)。

1. OC調(diào)用JavaScript

OC調(diào)用JavaScrippt是相對(duì)來(lái)說(shuō)比較簡(jiǎn)單的
只需要在調(diào)用的地方添加下面一句代碼即可

//showAlert()是js里面的方法,這樣就可以實(shí)現(xiàn)調(diào)用js方法
[self.webView evaluateJavaScript:@"showAlert('傳參')" completionHandler:^(id item, NSError * _Nullable error) {
        // Block中處理是否通過(guò)了或者執(zhí)行JS錯(cuò)誤的代碼
    }];

2. JavaScript 調(diào)用OC的方法,相對(duì)來(lái)說(shuō)復(fù)雜一點(diǎn)

這地方需要兩個(gè)配置,一個(gè)是OC代碼的配置,另一個(gè)是JS代碼的配置,下面先說(shuō)一下OC代碼的配置,細(xì)心的小伙伴可能已經(jīng)發(fā)現(xiàn)了扯饶,創(chuàng)建WKWebView的時(shí)候恒削,除了有- initWithFrame:方法外池颈,還有一個(gè)高端的方法:- initWithFrame:configuration:方法。
#######OC代碼的配置
1.配置 WKWebView

// 創(chuàng)建配置
      WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
      // 創(chuàng)建UserContentController(提供JavaScript向webView發(fā)送消息的方法)
      WKUserContentController* userContent = [[WKUserContentController alloc] init];
      // 添加消息處理钓丰,注意:self指代的對(duì)象需要遵守WKScriptMessageHandler協(xié)議躯砰,結(jié)束時(shí)需要移除
//NativeMethod 這個(gè)方法一會(huì)要與JS里面的方法寫的一樣
      [userContent addScriptMessageHandler:self name:@"NativeMethod"];
      // 將UserConttentController設(shè)置到配置文件
      config.userContentController = userContent;
      // 高端的自定義配置創(chuàng)建WKWebView
      WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:config];
      // 設(shè)置訪問(wèn)的URL
      NSURL *url = [NSURL URLWithString:@"http://www.reibang.com"];
      // 根據(jù)URL創(chuàng)建請(qǐng)求
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      // WKWebView加載請(qǐng)求
      [webView loadRequest:request];
      // 將WKWebView添加到視圖
      [self.view addSubview:webView];

2.實(shí)現(xiàn)協(xié)議方法

好了,現(xiàn)在萬(wàn)事俱備携丁,只欠東風(fēng)了琢歇。東風(fēng)是什么呢,就是該在哪兒處理梦鉴±蠲#可以看到WKScriptMessageHandler的協(xié)議里面只有一個(gè)方法,就是:

 - userContentController:didReceiveScriptMessage:

相信聰明的你已經(jīng)猜到了肥橙。是的魄宏,就是在這個(gè)代理方法里面操作:如果JavaScript執(zhí)行已經(jīng)寫好的:window.webkit.messageHandlers.NativeMethod.postMessage("就是一個(gè)消息啊");這行代碼,這個(gè)代理方法就會(huì)走存筏,并且會(huì)有個(gè)WKScriptMessage的對(duì)象宠互,這個(gè)WKScriptMessage對(duì)象有個(gè)name屬性,拿到之后你會(huì)發(fā)現(xiàn)方篮,就是我們注冊(cè)的NativeMethod這個(gè)字符串名秀,這時(shí)候你就可以手動(dòng)調(diào)用Native的方法了。如果有多個(gè)方法需要調(diào)用的話怎么辦藕溅,看到JavaScript中postMessage()方法有一個(gè)參數(shù)了沒有匕得,可以根據(jù)這里的參數(shù)來(lái)區(qū)分調(diào)用原生App的哪個(gè)方法。

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
          // 判斷是否是調(diào)用原生的
          if ([@"NativeMethod" isEqualToString:message.name]) {
              // 判斷message的內(nèi)容巾表,然后做相應(yīng)的操作
              if ([@"close" isEqualToString:message.body]) {

              }
          }
      }

2.JavaScript的配置

JavaScript調(diào)用Native的方法就需要前端和Native的小伙伴們配合了汁掠,需要前端的小伙伴在JS的方法中調(diào)用:

window.webkit.messageHandlers.方法名.postMessage(參數(shù))

注意:

參數(shù)沒有時(shí)傳 (null) 這里是個(gè)坑點(diǎn)

第一:實(shí)現(xiàn)以上代碼的時(shí)候不要忘記實(shí)現(xiàn)** WKScriptMessageHandler**協(xié)議
第二:上面將當(dāng)前ViewController設(shè)置為MessageHandler之后需要在當(dāng)前ViewController銷毀前將其移除(dealloc方法),否則會(huì)造成內(nèi)存泄漏集币。

//頁(yè)面進(jìn)入時(shí)創(chuàng)建
 -(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:JS_goPageSelectClass];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:JS_goClasscardList];
}

//頁(yè)面消失是移除
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:JS_goPageSelectClass];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:JS_goClasscardList];
}

js區(qū)分Android和iOS的方法

           var u = navigator.userAgent;
            var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android終端
            var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //iOS終端

                if(isAndroid){
                    window.Android.alipayOrder();
                }
                if(isiOS){
                    window.webkit.messageHandlers.alipayOrder.postMessage(r);
                }

第三個(gè)問(wèn)題 WKWebview 默認(rèn)是不彈出js的alert 要想可以彈出alert 需要手動(dòng)的設(shè)置代理實(shí)現(xiàn)

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

協(xié)議方法
具體的實(shí)現(xiàn)方法是,我們采用源生的UIAlertController 來(lái)實(shí)現(xiàn)彈出框,獲取js里面的alert內(nèi)容顯示出來(lái)

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
        NSLog(@"點(diǎn)擊了取消按鈕==%@",message);
    }])];
    [alertController addAction:([UIAlertAction actionWithTitle:@"確認(rèn)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
        NSLog(@"點(diǎn)擊了確定按鈕==%@",message);
    }])];

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

}

問(wèn)題四 : WKWebview 默認(rèn)是不能識(shí)別電話號(hào)的,這里需要通過(guò)實(shí)現(xiàn)一個(gè)協(xié)議來(lái)實(shí)現(xiàn)撥打電話的功能

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

具體的代碼如下:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    NSURL *URL = navigationAction.request.URL;
    NSLog(@"獲取到URL========%@",URL);
    NSString *scheme = [URL scheme];
    UIApplication *app = [UIApplication sharedApplication];
    // 打電話
    if ([scheme isEqualToString:@"tel"]) {
        if ([app canOpenURL:URL]) {
            [app openURL:URL];
            // 一定要加上這句,否則會(huì)打開新頁(yè)面
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

注:對(duì)應(yīng)html代碼采用的是a標(biāo)簽

<a href="tel:18158711698">識(shí)別電話號(hào)碼18158711698,進(jìn)行撥打電話</a>

問(wèn)題五: WKWebView 默認(rèn)攔截open.window() 打開新的頁(yè)面

- (WKWebView )webView:(WKWebView )webView createWebViewWithConfiguration:(WKWebViewConfiguration )configuration forNavigationAction:(WKNavigationAction )navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
會(huì)攔截到window.open()事件.
只需要我們?cè)谠诜椒▋?nèi)進(jìn)行處理
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}

問(wèn)題六:WKWebView解決顯示字體太小的問(wèn)題

在使用WKWebView的時(shí)候考阱,常常會(huì)碰到顯示內(nèi)容比實(shí)際css設(shè)置的樣式不能正常顯示,內(nèi)容普遍的偏小鞠苟。其實(shí)導(dǎo)致這樣問(wèn)題的根源是少了HTML5的meta標(biāo)簽乞榨。解決的辦法可以在iOS端添加以下的內(nèi)容,當(dāng)然也可以讓后臺(tái)添加完整的HTML5的格式当娱。如果要在iOS端指定字體的大小也是可以的(不推薦在客戶端設(shè)置字體大谐约取)。

 NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";

 WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
[wkUController addUserScript:wkUScript];

WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
wkWebConfig.userContentController = wkUController;

_myWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0,CGRectGetMaxY(headerView.frame)+10, M_S.width,M_S.height - CGRectGetMaxY(headerView.frame) - 40) configuration:wkWebConfig];

客戶端設(shè)置字體大小eg:

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
    //修改字體大小 300%
    [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '200%'" completionHandler:nil];

    //    //修改字體顏色  #9098b8
    //    [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextFillColor= '#9098b8'" completionHandler:nil];

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跨细,一起剝皮案震驚了整個(gè)濱河市鹦倚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冀惭,老刑警劉巖震叙,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掀鹅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡媒楼,警方通過(guò)查閱死者的電腦和手機(jī)乐尊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匣砖,“玉大人科吭,你說(shuō)我怎么就攤上這事『秭辏” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵谣殊,是天一觀的道長(zhǎng)拂共。 經(jīng)常有香客問(wèn)我,道長(zhǎng)姻几,這世上最難降的妖魔是什么宜狐? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蛇捌,結(jié)果婚禮上抚恒,老公的妹妹穿的比我還像新娘。我一直安慰自己络拌,他們只是感情好俭驮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著春贸,像睡著了一般混萝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上萍恕,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天逸嘀,我揣著相機(jī)與錄音,去河邊找鬼允粤。 笑死崭倘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的类垫。 我是一名探鬼主播司光,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼阔挠!你這毒婦竟也來(lái)了飘庄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤购撼,失蹤者是張志新(化名)和其女友劉穎跪削,沒想到半個(gè)月后谴仙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碾盐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年晃跺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毫玖。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掀虎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出付枫,到底是詐尸還是另有隱情烹玉,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布阐滩,位于F島的核電站二打,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏掂榔。R本人自食惡果不足惜继效,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望装获。 院中可真熱鬧瑞信,春花似錦、人聲如沸穴豫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)绩郎。三九已至潘鲫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肋杖,已是汗流浹背溉仑。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留状植,地道東北人浊竟。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像津畸,于是被迫代替她去往敵國(guó)和親振定。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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