實現思路
我的最終方案主要參考了豆瓣的rexxar和廣為大家使用的WebViewJavascriptBridge,之前也對后者有一點點研究。
源碼實現
代碼暫時沒有考慮開源性,結合了部分公司的業務和個性化配置,不做提供了。
WKWebView一直有很多坑,而且蘋果也沒有要解決的意思。在性能和需求兩者中,一定要權衡利弊,謹慎使用。
創建一個WKWebView,會配置一些基本信息,主要是WKWebViewConfiguration
,其中比較關鍵的一個是userContentController
,它可以用于注入javascript
腳本、處理native
和web
交互(本文后續都簡稱交互)等。
1)為什么要注入javascript
?
其實直接用WKWebView也能完成交互。客戶端直接調用evaluateJavaScript: completionHandler:
方法,web端先在userContentController
中調用addScriptMessageHandler
方法注冊xxx
事件,然后就可以用window.webkit.messageHandlers.xxx.postMessage(JSON.stringify(json))
方法調用客戶端的方法了。(注意:xxx是要一一對應的)
當然,更好的推薦是使用WebViewJavascriptBridge
,我們只要處理好注冊的事情就可以方便使用了,網上的教程也很多。
2)為什么不基于WebViewJavascriptBridge
實現一個Hybrid容器?
最主要的目的:為了web端能用一份代碼實現與Android和iOS端的交互。(本文只是一種思路)
3)實現思路是什么?
- a.使用WKWebView提供的交互方法,而不是用攔截URL Scheme的方式
- b.將多個注冊事件統一為一個事件
第一點主要還是要結合Android端和iOS端的方案選擇。我們的Android端不使用攔截方式,所以我選擇了WKWebView的方法。
第二點是為了避免后期維護頻繁的添加新的事件。假如這個H5容器是一個開源庫,隨著業務擴展擴展,交互的事件越來越多。我們可以選擇把webView
交付出去,讓用戶自身實現configuration
的配置,注冊新的事件;也可以選擇提供API,讓用戶注冊新事件。但是,感覺這樣都不夠方便。
能否讓用戶只是單純的實現自己的業務方法,而不要考慮注冊的事情?
最終,采用的辦法是:只注冊一個事件,兩端的開發只需要商定交互的方法名,中間的事情都交給H5容器去做。具體的實現是:
- a.假設注冊了一個
InteractiveEvent
- b.web端統一調用
window.webkit.messageHandlers.InteractiveEvent.postMessage(msg)
方法,參數msg中包含了需要調用方法的函數名、數據、回調等 - c.客戶端拿到函數名,用
NSMethodSignature
提供的API生成最終的函數簽名 - d.客戶端用一個哈希表存放了這些函數以及他們對應的組件功能,如果匹配上了則調用響應的功能。
小結
第一版做的比較簡單,基本是照葫蘆畫瓢,大部分的時間都用在填WKWebView
的坑了,還好前人總結的非常全面。不過,新東西采坑是件好事,收獲很多。