電子佛典 App 新支援離線瀏覽


2022/06/02 星期四端午節前夕,搭電車回家的路上,我在想我開發的 CBETA 電子佛典 app 還能支援什麼新功能、作什麼改善?這款 app 之前已支援離線瀏覽,但僅限於整合 Electron app 的版本,若單純用 PWA, 只能用連線版資料庫。因此我就在想有沒有辦法克服此問題。

這問題的影響面涉及 iOS, Android 平台不支援 Electron app (特別是 App Store 禁止此類 app 上架),因此我的 app 在這兩平台缺乏對離線瀏覽資料庫的支援。這兩個平台的用戶數是主流,因此這是一個值得解決的問題。

起初研究此問題,要先探討可行性,例如現有的系統、程式能不能達成需求,例如經文資料檔要存哪、目標功能能不能用 JavaScript 完成、需要多少時間能做得出來?如果不可能,就不必繼續了😭探討完可行性,就是整理有哪些工要做。

以這次的問題來說,經文資料檔有幾 GB,在 PWA 環境得試著用 IndexedDB 才可能儲存,而實際測試發現不同平台有不同限制。例如在 iOS 把 PWA 新增至桌面後,會限制 IndexedDB 最大空間 1 GB😭、在 Android 讀取 1 GB 多檔案會出現錯誤😭 iOS 的問題,我後來想到經文原檔中排除用不到的檔案,再壓縮後由 3 GB 變為 600+ MB,能塞進 IndexedDB!所以我設計 PWA 讀入原壓縮檔會解壓縮、濾掉用不到的檔,並把文字檔重新壓縮存入 IndexedDB、圖檔就不再壓縮浪費時間。至於為什麼不把單一的 600+ MB 壓縮檔直接寫進 IndexedDB,是因為這會造成要使用檔案時要把整個檔讀出、載入記憶體,很耗硬體資源。至於 Android 的問題,只好將刪檔過的經文壓縮檔放上 GitHub 提供下載 (要使用 git lfs)。

再來經文原始檔是 XML,要轉出網頁版的 HTML。我的舊版離線程式是使用 XSLT 作轉檔。幸運的,PWA 環境都有現成 XML, XSLT 的程式可用,我只要改寫舊版程式就可以了。在改寫過程有卡關,就是起初的改寫,會造成經文無法正常顯示。經檢查 HTML 的原始碼,發現在一系列的 XML 轉 HTML 檔處理中,出現許多空內容 span 標籤。這些標籤若不處理,會在轉 ePub 檔,再用 iframe 顯示後,出現文件結構變異。總之後來的解法就是用程式先把這些空內容標籤移除。

但在寫移除的程式碼又發現”有些空標籤刪不掉”!?後來查網路才知道是刪法有誤:我們知道 HTML 文件的結構是一樹狀結構 (DOM tree),一個節點可有多個子節點,子節點也可以有它們的子節點。要刪掉空內容標籤,可以用遞迴的寫法對每個節點的子節點先處理,再處理自身節點。所以當處理某個節點的子節點時,可用一迴圈遞迴下去。若遇到子節點是 span 標籤,就檢查是否有內容,若無則刪除。但此作法問題在於當某子節點被刪除,它的索引位置會被下一個子節點取代!而迴圈索引不知道這件事。以子結點索引編號 0, 1, 2 來說,若由 0 開始索引,子結點 0 被刪,剩餘子結點就會往前移。然後迴圈接著索引 1,實際卻跳過子結點 1,索引到子節點 2!後來查網路,有人提出一個解決辦法 – 反向索引。也就是由最後一個子結點往前開始索引,如此一來發生刪除子結點時,不會對待處理的子結點索引造成影響!👍

還有一個問題,除了經文文字的部分,還有圖片的部分。這些圖片在 HTML 檔中是以 URL 網址指向圖片資源。問題是我要如何讓網頁瀏覽器將它們指向 IndexedDB 中的圖檔?本來找到一個很漂亮的解法,就是使用 service worker 攔截 URL 請求,改至 IndexedDB 讀檔,再回傳給瀏覽器。程式面,現有的workbox-routing 就可達成。可惜我忘了一件事,Chrome 的 iframe 對 service worker 支援似乎有問題,總之我試了很久都試不出來。後來才決定用效能較差的方法:把圖片轉 base64 嵌入網頁。這方法終於成功了,幸好 CBETA 經文的圖檔都不大、每卷經文圖也不多,程式實際運行沒有明顯很慢。

雖然在研發過程很燒腦、要面對許多未知問題,好在最終成品效能還不錯、也學到不少東西🙂


Leave a Reply