寫這篇文章的原因是公司有一個H5的項目,有這樣的一個需求:要求移動端這邊做圖片緩存,因為我們公司的這個項目是一個商城類的,所以里面會有很多的展示性的圖片,由此導致的問題就是頁面加載速度極慢,所以公司要求我們移動端將展示的圖片保存在本地,目的就是為了第二次啟動App的時候可以提升加載速度咖祭。所以為了解決該問題济欢,我們需要攔截所有的URL請求并使用SDWebImage做圖片緩存告希,在成功解決了該問題之后忽舟,又發(fā)現App莫名的出現閃退诡右,多方查找原因后我們得出的結論是:由于展示性的圖片過多(一個商品頁面我數了一下展示了78張商品圖片并且前端的同志還沒有做分頁緩存功能),在內存激增之后UIWebView自身極其容易發(fā)生內存泄漏所幸我們最低適配iOS8可以使用WKWebView介却,最終成功解決了閃退問題柱搜。
首先我們來看看怎樣在H5的項目中使用SDWebImage做圖片緩存。
我們需要攔截所有的URL請求涨岁,使用的不是UIWebView(最開始都是使用的UIWebView之后才是WKWebView)的代理方法shouldStartLoadWithRequest(該方法是處理H5和OC的交互使用的)拐袜,而是繼承NSURLProtocol,自己子類化并且實現其中的代理方法梢薪,可以攔截到所有的URL請求,我們在canInitWithRequest方法中去處理帶有jpg尝哆,jpeg秉撇,png后綴名的URL(具體操作請點擊連接:http://www.reibang.com/p/0244e431fb3c,如果好用的話不要忘記點贊哦!)琐馆,然后在startLoading方法中處理攔截到的URL請求规阀,其中的思路就是:先看本地是否緩存有攔截的圖片URL對應的本地圖片,如果有那么使用本地圖片替換否則下載該鏈接對應的圖片到本地瘦麸。還有要提的一點是:如果使用WKWebView谁撼,子類化NSURLProtocol是攔截不到URL請求的,如果想要攔截滋饲,請參考:github.com/LiuShuoyu/HybirdWKWebVIew(有用不忘點贊@鞯)
到此,第一個問題解決:H5項目中利用SDWebImage做圖片緩存屠缭,對于第二個問題:UIWebView引起的內存泄漏箍鼓,我們的解決方案是:將UIWebView換成WKWebView。
簡答介紹一下WKWebView:
蘋果在iOS8中加入的用來替代UIWebView的控件呵曹。比UIWebView加載塊一倍的控件款咖,內存方面卻比它少一半,但是相對的緩存處理方面會稍微差一點奄喂。優(yōu)缺點如下:
優(yōu)點:
將瀏覽器內核渲染進程提取出 App铐殃,由系統(tǒng)進行統(tǒng)一管理,這減少了相當一部分的性能損失跨新。
js 可以直接使用已經事先注入 js runtime 的 js 接口給 Native 層傳值背稼,不必再通過苦逼的 iframe 制造頁面刷新再解析自定義協議的奇怪方式。
支持高達 60 fps 的滾動刷新率玻蝌,內置了手勢探測蟹肘。
缺點:
MK對緩存和Cookie操作沒有UIWebView那么方便。(調用的API沒有那么顯著的用途俯树。)
MK從iOS8才開始支持帘腹,也就是說在我們同時對iOS7支持的情況下,如果為了減少代碼量及適配等方面因素许饿,一樣會選擇UIWebView阳欲。
簡單地對比一下UIWebView和WKWebView的幾個代理方法:
1. 準備加載頁面
UIWebViewDelegate - webView:shouldStartLoadWithRequest:navigationType
WKNavigationDelegate: -webView:didStartProvisionalNavigation:
2. 內容開始加載
UIWebViewDelegate: -webViewDidStartLoad:
WKNavigationDelegate: -webView:didCommitNavigation:
3. 頁面加載完成
UIWebViewDelegate: -webViewDidFinishLoad:
WKNavigationDelegate: -webView:didFinishNavigation:
4. 頁面加載失敗
UIWebViewDelegate: -webView:didFailLoadWithError:
WKNavigationDelegate: -webView:didFailNavigation:withError:
WKNavigationDelegate: -webView:didFailProvisionalNavigation:withError:
再來講講WKWebView中需要的必備技能:原生和JS的交互
原生調用JavaScript的代碼:
需要在頁面加載完成之后,就是在- webView:didFinishNavigation:代理方法里面
[webView evaluateJavaScript:@"showAlert('奏是一個彈框')"completionHandler:^(iditem, NSError * _Nullable error) {
? ? ? ? ? ?// Block中處理是否通過了或者執(zhí)行JS錯誤的代碼
}];
JS調用原生:
千萬記茁省:JS調用本地的方法需要和前段的伙伴配合球化,需要前段的伙伴在JS的方法中調用:
window.webkit.messageHandlers.appsend.postMessage("就是一個消息啊");
這個NativeMethod是和App中要統(tǒng)一的,配置方法也很簡單
我們需要了解userContentController類瓦糟,該屬性幫助我們做原生和H5 的交互筒愚。我在實際操作中遇到這樣的一個問題:我點擊H5頁面中撥打電話的按鈕沒有響應,原因就是我們沒有統(tǒng)一好規(guī)則菩浙,前段在JS代碼中加上:window.webkit.messageHandlers.appsend.postMessage("就是一個消息啊")巢掺,而我則是配置我們約定的標識:[userContentControlleraddScriptMessageHandler:selfname:@"appsend"];然后在代理方法中通過標識拿到前段傳過來的參數調用原生方法進行打電話
- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message{
? ? ? ? ? ?if([message.nameisEqualToString: @"appsend"]) {
? ? ? ? ? ? ? ? NSString*phone = [@"tel://" ?stringByAppendingString:message.body];
? ? ? ? ? ? ? [[UIApplicationsharedApplication] ?openURL:[NSURLURLWithString:phone]];
}
其實明白了其中的原理句伶,WKWebView的使用還是比較簡單的,關于WKWebView更多的操作請看以下的參考文章:
http://www.reibang.com/p/403853b63537(記得幫忙點贊B降怼)
最后考余,說一些技術外的話吧,對于上面出現的幾個問題真的把我和我同事整的心累的不行轧苫,我們一致認為這個H5項目的優(yōu)化前端的同志才是應該出大力楚堤,但是沒法啊,由于各種原因最后反正就是我們移動端的小伙伴去優(yōu)化含懊,這幾個問題困擾了我們很久身冬,希望遇到相關問題小伙伴讀了該文章后能夠對大家有所幫助。還有必須要提的是:問題能夠解決還是首先要感謝網上那些熱心分享技術的小伙伴們绢要,所以大家在看了文章中幾個鏈接涉及的文章吏恭,如果你覺得有用請不忘點贊,感謝大家重罪!