WKWebView使用過程中遇到的坑

前言

在以前,一直以為Hybrid App開發(fā)是一種略顯簡單的事肛跌,不會使用太多能發(fā)揮移動端原生本身優(yōu)勢的復(fù)雜API艺配,后來在新公司的工作(半混合式開發(fā))過程中,發(fā)現(xiàn)混合式開發(fā)也是很多坑... 或者說WKWebView好多坑...

以下所說的內(nèi)容衍慎,參考鏈接上基本上都有转唉,本文的敘述方式主要是結(jié)合自己的經(jīng)歷(自己踩過的總結(jié)總是那么的深刻...[捂臉])
應(yīng)該在開始混合開發(fā)之前就看下這篇文章的,結(jié)果真的是等自己踩坑踩了一遍稳捆,總結(jié)之后赠法,發(fā)現(xiàn)這篇文章上都有....[大哭]
參考鏈接2: http://www.reibang.com/p/86d99192df68

目錄

  1. 加載URL的 encode問題
  2. loadRequest造成的body數(shù)據(jù)丟失
  3. 使用WKUserContentController造成的內(nèi)存泄漏問題
  4. WKWebView的白屏問題(拍照引起)
  5. NSURLProtocol(做網(wǎng)頁緩存)
  6. WKWebView的截屏問題(做意見反饋)
  7. window.alert()引起的crash問題(暫時沒遇到)
  8. WKWebView攔截協(xié)議
  9. User-Agent修改
  10. UI細(xì)節(jié)問題
    . wkwebview中 h5絕對布局不生效
    . iOS 12中WKWebView中表單 鍵盤彈起自動上移,導(dǎo)致的兼容問題
    . WKWebview會下移20
    . 頁面滾動速率
    . 視頻自動播放
    . goBack API問題
    · didFinishNavigation遲遲不調(diào)用
  11. iOS 11系統(tǒng)上乔夯,WKWebView內(nèi)H5標(biāo)簽不可點擊砖织,Native不受影響

1. 加載URL的 encode問題

在數(shù)據(jù)網(wǎng)絡(luò)請求或其他情況下,需要把URL中的一些特殊字符轉(zhuǎn)換成UTF-8編碼末荐,比如:中文侧纯。解決無法加載的問題

編碼:

iOS 9以前
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding
ios9后對其方法進行了修改
stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLQueryAllowedCharacterSet]

解碼

iOS 9以前
stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding
iOS 9以后
stringByRemovingPercentEncoding

總結(jié):混合開發(fā)中,最好將所有的URL的編解碼問題都交給前端或者后端來做甲脏,畢竟移動端發(fā)版太笨重了眶熬,最起碼保證iOS與Android兩端的處理一致,否則前端同學(xué)做處理就太麻煩了

2. loadRequest造成的body數(shù)據(jù)丟失

在 WKWebView 上通過 loadRequest 發(fā)起的 post 請求 body 數(shù)據(jù)會丟失:

//同樣是由于進程間通信性能問題块请,HTTPBody字段被丟棄[request setHTTPMethod:@"POST"];
[request setHTTPBody:[@"bodyData" dataUsingEncoding:NSUTF8StringEncoding]];
[wkwebview loadRequest: request];

解決方案:見參考鏈接娜氏,目前暫無使用場景

3. 使用WKUserContentController造成的內(nèi)存泄漏問題

  self -> webView -> WKWebViewConfiguration -> WKUserContentController -> self (addScriptMessageHandler)

__weak typeof(self) copy_self = self;
addScriptMessageHandler: copy_self  //不能解決問題

解決方案:
  單獨創(chuàng)建一個類實現(xiàn)`WKScriptMessageHandler`協(xié)議,然后在該類中再創(chuàng)建一個協(xié)議墩新,由self來實現(xiàn)協(xié)議
  即: `self -> webView -> WKWebViewConfiguration -> WKUserContentController -> weak delegate obj --delegate--> self `

示例代碼:
 1.創(chuàng)建一個新類WeakScriptMessageDelegate

  #import <Foundation/Foundation.h>
  #import <WebKit/WebKit.h>
  @interface WeakScriptMessageDelegate : NSObject
    @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

  2.在我們使用WKWebView的控制器中引入我們創(chuàng)建的那個類贸弥,將注入js對象的代碼改為:
  [config.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:scriptMessage];

  3.在delloc方法中通過下面的方式移除注入的js對象
  [self.config.userContentController removeScriptMessageHandlerForName:scriptMessage];
  上面三步就可以解決控制器不能被釋放的問題了

4. WKWebView的白屏問題(拍照引起)

WKWebView 自詡擁有更快的加載速度,更低的內(nèi)存占用抖棘,但實際上 WKWebView 是一個多進程組件茂腥,Network Loading 以及 UI Rendering 在其它進程中執(zhí)行狸涌。
換WKWebView加載網(wǎng)頁后,App 進程內(nèi)存消耗反而大幅下降最岗,但是仔細(xì)觀察會發(fā)現(xiàn)帕胆,Other Process 的內(nèi)存占用會增加。在一些用 webGL 渲染的復(fù)雜頁面般渡,使用 WKWebView 總體的內(nèi)存占用(App Process Memory + Other Process Memory)不見得比 UIWebView 少很多懒豹。

在 UIWebView 上當(dāng)內(nèi)存占用太大的時候,App Process 會 crash驯用;
而在 WKWebView 上當(dāng)總體的內(nèi)存占用比較大的時候脸秽,WebContent Process 會 crash,從而出現(xiàn)白屏現(xiàn)象

# 解決方案:
  1. 借助 iOS 9以后 WKNavigtionDelegate 新增了一個回調(diào)函數(shù):
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));

當(dāng) WKWebView 總體內(nèi)存占用過大蝴乔,頁面即將白屏的時候记餐,系統(tǒng)會調(diào)用上面的回調(diào)函數(shù),我們在該函數(shù)里執(zhí)行[webView reload](這個時候 webView.URL 取值尚不為 nil)解決白屏問題薇正。在一些高內(nèi)存消耗的頁面可能會頻繁刷新當(dāng)前頁面片酝,H5側(cè)也要做相應(yīng)的適配操作。

  1. 檢測 webView.title 是否為空
    并不是所有H5頁面白屏的時候都會調(diào)用上面的回調(diào)函數(shù)挖腰,比如雕沿,最近遇到在一個高內(nèi)存消耗的意見反饋H5頁面上 present 系統(tǒng)相機,拍照完畢后返回原來頁面的時候出現(xiàn)白屏現(xiàn)象(拍照過程消耗了大量內(nèi)存猴仑,導(dǎo)致內(nèi)存緊張审轮,WebContent Process 被系統(tǒng)掛起),但上面的回調(diào)函數(shù)并沒有被調(diào)用辽俗。在WKWebView白屏的時候疾渣,另一種現(xiàn)象是 webView.titile 會被置空, 因此,可以在 viewWillAppear 的時候檢測 webView.title 是否為空來 reload 頁面榆苞。

注意:可能有的前端頁面確實沒寫title標(biāo)簽稳衬,在前端移動端開發(fā)中是可能會有這種場景的,會造成頁面反復(fù)刷新

綜合以上兩種方法可以解決絕大多數(shù)的白屏問題坐漏。

5. NSURLProtocol(做網(wǎng)頁緩存)

WKWebView中NSURLProtocol的使用以及對H5的緩存,這是利用NSURLProtocol做網(wǎng)頁緩存以及帶來的隱患碧信。

6. WKWebView的截屏問題(做意見反饋)

WKWebView 下通過 -[CALayer renderInContext:]實現(xiàn)截屏的方式失效赊琳,需要通過以下方式實現(xiàn)截屏功能:

@implementation UIView (ImageSnapshot) 
- (UIImage*)imageSnapshot { 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size,YES,self.contentScaleFactor); 
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES]; 
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return newImage; 
} 
@end

然而這種方式依然解決不了 webGL 頁面的截屏問題,Safari 以及 Chrome 這兩個全量切換到 WKWebView 的瀏覽器也存在同樣的問題:對webGL 頁面的截屏結(jié)果不是空白就是純黑圖片砰碴。

7. window.alert()引起的crash問題(暫時沒遇到)

8. WKWebView攔截協(xié)議

WKWebView內(nèi)默認(rèn)不允許iTunes躏筏、weixin等協(xié)議跳轉(zhuǎn)
UIWebView打開ituns.apple.com、跳轉(zhuǎn)到appStore,呈枉、撥打電話,趁尼、喚起郵箱等一系列操作UIWebView 自己處理不了會自動交給UIApplication 來處理埃碱。

WKWebView上述事件WKWebView 不會自動交給UIApplication 來處理,除此之外,js端通過window.open() 打開新的網(wǎng)頁的動作也被禁掉了

9. User-Agent修改

不要擅自修改webView的User-Agent,務(wù)必要跟前端反復(fù)確認(rèn)酥泞,是否有用UA來做一些設(shè)備區(qū)分砚殿,進而做一些系統(tǒng)、機型適配問題芝囤。

10. UI細(xì)節(jié)問題

# 1. wkwebview中 h5絕對布局不生效
_baseWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; (ios 11之后)`

然后:前端需要在meta標(biāo)簽中增加 **iPhoneX**的適配**---**適配方案**viewport-fit**:**cover**
# 2. iOS 12中WKWebView中表單 鍵盤彈起自動上移似炎,導(dǎo)致的兼容問題

WKWebView會自動監(jiān)聽鍵盤彈出,并做上下移動處理(效果如同IQKeyboardManage這些庫)悯姊,但是在iOS12中會有一些問題羡藐,鍵盤收起后,控件不恢復(fù)原狀悯许,或者部分控件消失等不兼容問題
解決方案:

if(kSystemVersion < 12.0) {
    if (@available(iOS 11.0, *)) {
        _webview.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    } 
}
if (@available(iOS 12.0, *)) {
     _webview.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
}
# 3. WKWebview會下移20

解決方案:

VC.automaticallyAdjustsScrollViewInsets = NO;  //iOS11以及以后失效
需要使用_webview.scrollView.contentInsetAdjustmentBehavior
# 順帶解釋一下以下兩個屬性

關(guān)于extendedLayoutIncludesOpaqueBarsautomaticallyAdjustsScrollViewInsets

  • 這兩個屬性屬于UIViewController
  • 默認(rèn)情況下extendedLayoutIncludesOpaqueBars = false 擴展布局不包含導(dǎo)航欄
  • 默認(rèn)情況下automaticallyAdjustsScrollViewInsets = true 自動計算滾動視圖的內(nèi)容邊距
  • 但是,當(dāng) 導(dǎo)航欄 是 不透明時,而tabBar為透明的時候,為了正確顯示tableView的全部內(nèi)容,需要重新設(shè)置這兩個屬性的值,然后設(shè)置contentInset(參考代碼).

在iOS11 中, UIViewController的automaticallyAdjustsScrollViewInsets屬性已經(jīng)不再使用,我們需要使用UIScrollView的 contentInsetAdjustmentBehavior屬性來替代它.

UIScrollViewContentInsetAdjustmentBehavior 是一個枚舉類型,值有以下幾種:

  • automatic 和scrollableAxes一樣,scrollView會自動計算和適應(yīng)頂部和底部的內(nèi)邊距并且在scrollView 不可滾動時,也會設(shè)置內(nèi)邊距.
  • scrollableAxes 自動計算內(nèi)邊距.
  • never不計算內(nèi)邊距
  • always 根據(jù)safeAreaInsets 計算內(nèi)邊距一般我們肯定需要設(shè)置為 never仆嗦,我們自己來控制間距,但是在iOS 12的webView中先壕,就會出現(xiàn)開始所說的問題欧啤,需要設(shè)置為automatic才能解決

調(diào)整WKWebView布局方式,避免調(diào)整webView.scrollView.contentInset启上。實際上邢隧,即便在 UIWebView 上也不建議直接調(diào)整webView.scrollView.contentInset的值.

# 4. 頁面滾動速率

WKWebView 需要通過 scrollView delegate 調(diào)整滾動速率:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
 scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}
# 5. 視頻自動播放

WKWebView 需要通過WKWebViewConfiguration.mediaPlaybackRequiresUserAction設(shè)置是否允許自動播放,但一定要在 WKWebView 初始化之前設(shè)置冈在,在 WKWebView 初始化之后設(shè)置無效倒慧。

# 6. goBack API問題

WKWebView 上調(diào)用 -[WKWebView goBack], 回退到上一個頁面后不會觸發(fā)window.onload()函數(shù)、不會執(zhí)行JS包券。

# 7. didFinishNavigation遲遲不調(diào)用

明明看起來頁面加載完全纫谅,卻不調(diào)用(一般只發(fā)生在第一次進入該頁面)。
解決方法:經(jīng)過自定義NSURLProtocol溅固,攔截所有的H5加載資源付秕,并在didCompleteWithError中打印資源的加載情況,發(fā)現(xiàn)有圖片資源侍郭,域名有問題
Error Domain=NSURLErrorDomain Code=-1003 "未能找到使用指定主機名的服務(wù)器询吴。
DNS解析失敗導(dǎo)致系統(tǒng)認(rèn)定H5一直沒加載完成,第二次再進入亮元,系統(tǒng)緩存了DNS解析的映射記錄猛计,所以很快就認(rèn)定資源錯誤,調(diào)用了didFinish方法爆捞。

11. iOS 11系統(tǒng)上奉瘤,WKWebView內(nèi)H5標(biāo)簽不可點擊,Native不受影響

在頻繁的切換頁面煮甥、刷新WKWebView的情況下盗温,會出現(xiàn)WKWebView卡死藕赞,所有的H5標(biāo)簽不可點擊,Native的UI不受影響卖局,TabBarVC的幾個子控制器最為嚴(yán)重斧蜕,有時候切換、刷新四五次左右吼驶,就會出現(xiàn)這種情況惩激。

更新:結(jié)論:在viewWillAppear方法中調(diào)用了evaluateJavaScript: completionHandler:方法,將該方法的調(diào)用移到viewDidAppear方法中即可蟹演。

下面是探索的一些步驟风钻,也走了一些彎路,可繞過

分別從內(nèi)存酒请、視圖骡技、網(wǎng)絡(luò)請求幾個方面入手,按照以下步驟定位問題:
1.對APP進行內(nèi)存泄漏檢測羞反,優(yōu)化了幾處代碼布朦。毫無用處
2.WKWebView單獨進程內(nèi)存問題?因為有一些二級頁面按照問題出現(xiàn)流程復(fù)現(xiàn)了N多次昼窗,都沒有出現(xiàn)是趴,所以暫時先排除
3.網(wǎng)速問題。發(fā)現(xiàn)網(wǎng)速差時澄惊,確實很容易復(fù)現(xiàn)唆途,網(wǎng)速好的時候,試了好幾次沒復(fù)現(xiàn)掸驱!做了一些網(wǎng)絡(luò)優(yōu)化肛搬,比如及時cancel掉一些不需要的請求,沒有效果毕贼。
4.視圖加載温赔、更新問題。**猜測依據(jù):一級頁面更容易復(fù)現(xiàn)鬼癣,且比二級頁面多了一個Tabbar的視圖陶贼。
結(jié)論:結(jié)合第3、4扣溺,猜測是網(wǎng)絡(luò)過慢時骇窍,tabbar出現(xiàn)、隱藏锥余,及WKWebView刷新、加載痢掠、渲染HTML驱犹,幾種情況結(jié)合導(dǎo)致的WKWebView布局混亂嘲恍。
最后解決方法:包含WKWebView的一級頁面,`viewDidAppear`時重新設(shè)置了一下WKWebView的約束雄驹。(設(shè)置UIScrollViewContentInsetAdjustmentAutomatic = YES佃牛,沒有效果)
效果:大大改善了,但卻沒有根治問題医舆。加了個保底方案俘侠,下拉刷新時,銷毀舊WKWebView蔬将,創(chuàng)建新的爷速,并loadRequest。(因為這些情況下iOS 11上出現(xiàn)的霞怀,且沒有更低版本的測試機復(fù)現(xiàn)惫东,所以暫時把修改限制在了iOS 11及以下的系統(tǒng))

最后:有個最省事的方案,針對這些頁面毙石,將WKWebView替換成UIWebView廉沮。 可行,但逃避問題徐矩,不太可取滞时,而且UIWebView、WKWebView各有一些特性滤灯,另一個不支持坪稽,比如WKWebView支持html,滾動時實時回調(diào)力喷,而UIWebView只支持滾動停止時回調(diào)刽漂。且蘋果已經(jīng)不太支持UIWebView。還是早點擁抱WKWebView吧弟孟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贝咙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拂募,更是在濱河造成了極大的恐慌庭猩,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陈症,死亡現(xiàn)場離奇詭異蔼水,居然都是意外死亡,警方通過查閱死者的電腦和手機录肯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門趴腋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事优炬“渚” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵蠢护,是天一觀的道長雅宾。 經(jīng)常有香客問我,道長葵硕,這世上最難降的妖魔是什么眉抬? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮懈凹,結(jié)果婚禮上蜀变,老公的妹妹穿的比我還像新娘。我一直安慰自己蘸劈,他們只是感情好昏苏,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著威沫,像睡著了一般贤惯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上棒掠,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天孵构,我揣著相機與錄音,去河邊找鬼烟很。 笑死颈墅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼祟偷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毒坛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤林说,失蹤者是張志新(化名)和其女友劉穎煎殷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腿箩,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡豪直,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了珠移。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弓乙。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡末融,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唆貌,到底是詐尸還是另有隱情滑潘,我是刑警寧澤垢乙,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布锨咙,位于F島的核電站,受9級特大地震影響追逮,放射性物質(zhì)發(fā)生泄漏酪刀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一钮孵、第九天 我趴在偏房一處隱蔽的房頂上張望骂倘。 院中可真熱鬧,春花似錦巴席、人聲如沸历涝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荧库。三九已至,卻和暖如春赵刑,著一層夾襖步出監(jiān)牢的瞬間分衫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工般此, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蚪战,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓铐懊,卻偏偏與公主長得像邀桑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子科乎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 導(dǎo)語 WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件壁畸,用以替代 UIKit...
    Jecky丶閱讀 8,341評論 2 22
  • 1、WKWebView 白屏問題WKWebView 自詡擁有更快的加載速度喜喂,更低的內(nèi)存占用瓤摧,但實際上 WKWebV...
    iosRn閱讀 2,093評論 1 10
  • 1、WKWebView 白屏問題WKWebView 自詡擁有更快的加載速度玉吁,更低的內(nèi)存占用照弥,但實際上 WKWebV...
    無名感恩閱讀 2,133評論 0 3
  • 轉(zhuǎn)載:http://www.cnblogs.com/NSong/p/6489802.html 導(dǎo)語 WKWebVi...
    李小威閱讀 4,849評論 8 9
  • WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件,用以替代 UIKit 中笨...
    Aiana閱讀 4,557評論 1 8