本文的讀者需要有一定的 Hybrid 基礎,相關的概念已經有很多優秀的文章進行過講解,這裡不再贅述。本文的重點在於如何基於 Hybrid 框架,在移動端(不限於具體平臺)完成一個 wap 頁面的完整下載。這個頁面會包含豐富的媒體資源,包括圖片、音訊、視訊等。下載完成之後,我們在離線時依然能夠流暢閱讀該頁面的完整內容。
場景分析
在移動端使用 wap 頁面展示內容有非常多的應用場景,比如常見的新聞資訊閱讀、簡書或掘金的文章展示。客戶端提供 webview 容器,配套一系列前端與客戶端互動的能力,前端使用模板批量生成不同的內容後下發,發揮著前端極高靈活性的同時又可以享受到客戶端原生的許多能力。
前面說的場景,使用者很少有快取的需求。不過對於某些產品中使用者可能會反覆檢視的內容,提供頁面的下載以供離線檢視就很有必要了。wap 頁面不僅可以展示文字,還經常出現圖片,有的頁面中還會包含音訊甚至視訊,該採用什麼方式完成下載,需要根據不同的場景具體分析。
方案選擇
一般而言,提供了下載功能的 wap 頁面,它將展示的內容形式必然是有限制的。如果任何一個頁面丟過來都要求快取,我們很難保證離線情況下的展示效果。
利用 NSURLProtocol 實現快取
對於簡單的頁面,比如它只包含文字和圖片,那麼不依賴 Hybrid 也可以實現。NSURLProtocol 就是一個可選方案,並且它的覆蓋範圍可以更廣。使用 NSURLProtocol 對網路請求進行過濾,如果是特定的 html、css、js 等請求和圖片請求,就在本地快取資料中進行查詢,命中快取則使用本地資料包裝成網路請求的響應資料進行回傳,否則才執行對應的網路請求。這樣即使在網路可用的情況下,也會優先使用本地快取資料,不僅可以完成頁面的離線展示,還有效地加快了網路可用時頁面的載入速度。自然想到,這也是很多 wap 頁面加速方案會採用的方式。
基於 Hybrid 的 wap 頁面
而對於包含了音訊、視訊等內容的 wap 頁面,出於使用者體驗等目的,客戶端往往會將這些資源的展示進行接管。比如頁面中包含音樂時,使用者進行點選會發現是客戶端的播放器在進行播放,這便是 Hybrid 應用的例子。它的一個常見實現方案是:客戶端為前端提供了播放音訊的介面,對於 wap 頁面中的所有音訊,放棄前端的原生寫法,採用客戶端提供的介面。而客戶端中這個介面的實現,自然是調起客戶端音訊播放器,播放對應的音訊,這個過程中又會涉及到是否成功的回撥、客戶端播放器和 wap 頁中播放狀態的同步等諸多問題,不過這不是本文關注的重點。本文討論的需要完整下載的 wap 頁面的場景,就是基於這種方案。
具體實現
頁面的展示方案
通過上面的例子可以看到,基於 Hybrid 方案展示的 wap 頁面,不僅需要客戶端提供面向前端呼叫的各種能力,也需要前端在編寫程式碼時進行相應的呼叫。兩端相互配合,完成高度定製化的 wap 頁面。對於上面的例子,客戶端提供出來圖片、音訊、視訊的介面,這樣 wap 頁面中對應內容的互動,便都交由客戶端的原生實現。而客戶端介面的實現,自然就是首先在本地快取資料中進行查詢,若該資料已下載,則使用本地資料,否則進行對應的網路獲取,以此相容有網和離線的情況。
交由客戶端接管的好處,除了上述離線快取的應用,還有一點是能夠讓 webview 中的內容也可以享受到客戶端原生的處理方式。比如圖片介面的客戶端實現,就可以交由專案中使用的網路圖片非同步載入工具(SDWebImage 或 YYWebImage 等),這樣 webview 中的圖片載入和原生場景下的圖片載入可以共享快取資料,原生場景載入過的圖片,在 webview 中展示時便無需重複網路獲取,反過來也如此。基於區域性性原理,這樣可以在一定程度上達到圖片載入加速的效果(減少了重複網路請求)。
進一步優化
事實上,在高度定製的 wap 頁面場景下,我們對於 webview 中可能出現的頁面型別會進行嚴格控制。可以通過內容的控制,避免 wap 頁中出現外部頁面的跳轉,也可以通過 webview 的對應代理方法,禁掉我們不希望出現的跳轉型別,或者同時使用,雙重保護來確保當前 webview 容器中只會出現我們定製過的內容。既然 wap 頁的型別是有限的,自然想到,同型別頁面大都由前端採用模板生成,頁面所使用的 html、css、js 的資源很可能是同一份,或者是有限的幾份,把它們直接隨客戶端打包在本地也就變得可行。載入對應的 url 時,直接 load 本地的資源。
對於 webview 中的網路請求,其實也可以交由客戶端接管,比如在你所採用的 Hybrid 框架中,為前端註冊一個發起網路請求的介面。wap 頁中的所有網路請求,都通過這個介面來傳送。這樣客戶端可以做的事情就非常多了,舉個例子,NSURLProtocol 無法攔截 WKWebview 發起的網路請求,採用 Hybrid 方式交由客戶端來傳送,便可以實現對應的攔截。
基於上面的方案,我們的 wap 頁的完整展示流程是這樣:客戶端在 webview 中載入某個 url,判斷符合規則,load 本地的模板 html,該頁面的內部實現是通過客戶端提供的網路請求介面,發起獲取具體頁面內容的網路請求,獲得填充的資料從而完成展示。
下載時如何確定具體需要下載的資源
客戶端如何確定某個具體 wap 頁中會包含的資源,我們沒有找到很高效的辦法。所幸這種場景下的頁面多是內部生產、高度定製的,這也就為後端提供資源統計提供了可能(頁面資料本來就是後端生產的~),所以我們採用了後端提供對應介面支援的方案,根據 wap 頁的 id,可以獲取該頁面包含的具體資源。執行使用者的下載行為時,使用對應頁面 id 呼叫資源統計介面,獲得該頁面包含的資源。這其中包括 JSON 格式的頁面填充資料,也包括媒體檔案的 url。對於 JSON 資料,可以採用簡單的快取框架進行快取(YYCache 等),圖片採用場景的圖片快取框架,音訊、視訊等可以處理成常規的檔案下載任務。
結語
- 本文並沒有關注具體的 Hybrid 框架如何實現,重點在於提供一個基於 Hybrid 可以實現的具體業務場景。
- 文中所述的方案,是公司內部場景下剝離了業務的技術實現闡述。會有不盡合理的地方,歡迎討論。