iOS13發(fā)布了,據(jù)說蘋果開始拒絕使用UIWebView的api應(yīng)用了旦部。
有點(diǎn)慌障涯,由于項(xiàng)目自17年開始就一直用的UIWebView厨内,但UIWebView性能實(shí)在是太差了,進(jìn)幾個(gè)網(wǎng)頁內(nèi)存就飆升茄袖,并且退出頁面VC銷毀了但內(nèi)存還無法降下來操软,首次加載網(wǎng)頁的時(shí)候還會(huì)卡那么一會(huì),只能弄個(gè)假進(jìn)度條宪祥。
雖然中途也一直尋思著升級(jí)到WKWebView聂薪,但奈何項(xiàng)目中業(yè)務(wù)眾多又是分布式的,和js交互的地方也很多蝗羊,而WKWebView和UIWebView的交互方法寫法又不一樣藏澳,前端得區(qū)分是Android還是iOS,所有有交互的地方全要改耀找,要前端配合改的話翔悠,估計(jì)人家也不樂意业崖。
然后就這么一直拖著拖著,直到現(xiàn)在木有辦法了蓄愁,項(xiàng)目這時(shí)候剛好微信支付廢掉了双炕,要升級(jí)發(fā)新版本,跟錢相關(guān)的又刻不容緩撮抓,但又怕這次發(fā)新版由于UIWebView的問題被打回來妇斤,得硬著頭皮上了,必須把這塊硬石頭給啃了丹拯。
說干就干
不要慌站超,一步一步來
先不管交互,先把UIWebView切換到WKWebView咽笼,看看只加載網(wǎng)頁有沒什么問題顷编,再把網(wǎng)頁加載完成之后的一些邏輯移植過來,再把進(jìn)度條加上剑刑,OK,很完美双肤,加載網(wǎng)頁柔順多了施掏,內(nèi)存也降下來了。
不要慌茅糜,接下來七芭,集中精力搞定js和原生的交互
使用UIWebView時(shí),js和原生交互是使用注冊(cè)模型類蔑赘,然后js再通過注冊(cè)的模型類調(diào)用和原生聲明好的交互方法狸驳。比如注冊(cè)的模型名稱為backJSAction
,交互方法為- (void)returnPage;
缩赛,那么js那邊調(diào)用原生的就是backJSAction.returnPage()
而使用WKWebView時(shí)耙箍,js調(diào)用原生方法就變成了window.webkit.messageHandlers.backJSAction.postMessage();
,蛋疼就是在這里酥馍,前端得把以前的交互方式辩昆,全部改成這種,而Android那邊卻還是用上面的交互方式旨袒,這就得區(qū)分是Android還是iOS了(話說前端怎么區(qū)分呢汁针?),就算改了砚尽,那舊版的APP就無法使用了施无,這無疑加大了工作量,并且代價(jià)有點(diǎn)高必孤。
怎么辦猾骡,怎么辦,有沒有一種優(yōu)雅的方式,在不牽動(dòng)前端和Android的情況下卓练,順利的將UIWebView切換到WKWebView隘蝎。
不要慌,開始網(wǎng)上找資料
方法一襟企、通過攔截url參數(shù)方式
需要iOS嘱么、Android、前端都改代碼顽悼,不算嚴(yán)格意義上的js交互曼振,而且交互方法無法返回值,直接pass蔚龙。
方法二冰评、使用第三方框架WebViewJavascriptBridge
此法也需要推翻重來,需要iOS木羹、Android甲雅、前端都改代碼,改動(dòng)成本大坑填,只能作為最后的補(bǔ)救方案抛人。
就這樣完了嗎?不脐瑰,肯定是我搜索的方式不對(duì)(我就納悶了妖枚,這應(yīng)該是很多人都會(huì)碰到的問題,為什么就找不到相關(guān)問題和解決辦法)
不要慌苍在,換個(gè)關(guān)鍵詞繼續(xù)找資料
終于绝页,我仿佛看到了曙光,看到一種截然不同的解決辦法
http://www.reibang.com/p/afc52a5a28db
方法三寂恬、通過注入js腳本的方式续誉,轉(zhuǎn)換js的方法調(diào)用
說白了就是將在js調(diào)用backJSAction.returnPage()
方法時(shí),將方法轉(zhuǎn)換成window.webkit.messageHandlers.backJSAction.postMessage()
掠剑,這樣就可以調(diào)到原生的交互方法了屈芜,頓時(shí)嘴角一揚(yáng)。
不要慌朴译,先寫個(gè)小demo測試一下
測試了一個(gè)無返回值井佑,無參數(shù)- (void)returnPage;
和有參數(shù)- (void)setPageTitle:(NSString *)title;
的方法,都很完美眠寿,能調(diào)用到躬翁,心情愉悅。
接著往下測試一個(gè)有返回值- (NSString *)getUserInfo;
盯拱,發(fā)現(xiàn)js無法接收到返回值盒发,原來是window.webkit.messageHandlers.xxx
是沒有返回值的例嘱,也就是WKWebView不支持返回值的交互方法,WTF?
就這樣涼涼了宁舰?心中頓時(shí)跑過一萬只草泥馬拼卵。冷靜片刻后......
不要慌,查查WKWebView怎么同步返回值蛮艰。
看到的都是通過JS端調(diào)用prompt函數(shù)時(shí)腋腮,觸發(fā)WKWebView的一個(gè)代理方法,在代理方法里原生可以同步返回值給js壤蚜。
http://www.reibang.com/p/5fc4c0c6fbdf
難道要前端把所有有返回值的方法調(diào)用即寡,全部換成prompt函數(shù)?那這樣還是要前端改代碼袜刷,并且區(qū)分iOS和Android聪富,這不是我的初衷,抓狂中.......
不行著蟹,頭有點(diǎn)痛墩蔓,休息一下
想啊想,想啊想萧豆,既然上面能將那么復(fù)雜的方法進(jìn)行轉(zhuǎn)化钢拧,那我是不是可以將js的方法也轉(zhuǎn)換成prompt函數(shù),APP再將返回值給prompt函數(shù)炕横,再將prompt接收到的值返回給原始的js方法,有思路了就是干
prompt函數(shù)可以攜帶兩個(gè)參數(shù)prompt和defaultText葡粒,就將原始js方法名當(dāng)做prompt參數(shù)份殿,傳遞到WKWebView的代理方法,APP就根據(jù)方法名來區(qū)分執(zhí)行不同邏輯
腳本中的寫法:
backJSAction.getUserInfo = function () {
var r = window.prompt("getUserInfo");
return r;
}
代理方法中寫法:
#pragma mark ------ WKUIDelegate Delegate -------
// 交互嗽交∏涑埃可輸入的文本。
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {
NSLog(@"%@---%@",prompt,defaultText);
NSString *result = @"";
if ([prompt isEqualToString:@"getUserInfo"]) {
result = [self getUserInfo];
}else if ([prompt isEqualToString:@"getStrSign"]) {
result = [self getStrSign];
}
completionHandler(result);//這里就是要返回給JS的返回值
}
寫完夫壁,測試拾枣,完全ojbk,js交互方法能接收APP返回的值盒让。長吁一口氣梅肤,貌似就這樣完美解決了?哈哈哈哈邑茄,我真特么機(jī)智姨蝴。
繼續(xù)往下測試,當(dāng)測試到這個(gè)交互方法時(shí)- (BOOL)isLogin;
肺缕,尼瑪左医,又特么出問題了授帕,代理方法的completionHandler()只能返回字符串類型,不能返回布爾值浮梢。WCCCCCCCCCCCCC跛十,開始懷疑人生了。
哪怕前面解決了99%的問題秕硝,這個(gè)問題不解決芥映,那就全白費(fèi)了。
好在天無絕人之路缝裤,經(jīng)過嘗試屏轰,返回空字符串,js那邊接收到的就是false憋飞,返回非空字符串時(shí)霎苗,js那邊接收到的就是true,即想返回NO和YES榛做,就分別completionHandler(@""),completionHandler(@"1")即可唁盏。
大功告成!六點(diǎn)了下班检眯,放國慶假了厘擂,有時(shí)間再補(bǔ)個(gè)demo
10月15日
demo已補(bǔ)上