結識hybrid體驗這一年

在這之前雖然看過一些博客介紹 hybrid,但是始終沒有具體應用場景,想象的就是我現在做好了一個網站,然後 native 直接在 webview 中打開我的網站,類似瀏覽器中打開網站一樣,頭部添加一個類似瀏覽器的返回按鈕,如果只是考慮到安卓或許這一步都沒必要。

以下是以一個面描述了一個點的整個過程。

檢索

  • 硬件交互
    • 通訊協議
    • 遠程操作
  • 問題分析
    • websocket 心跳重連問題
    • 緩存方案
    • 圖片資源渲染問題
    • 系統字體大小修改影響網頁字體大小
    • 多小程序掃同一個碼的需求
  • 如何進階

認真接觸 hybrid 是在入職後的第一個項目,項目是基於 Hybrid/webapp at gh-pages · yexiaochai/Hybrid · GitHub 其中視圖部分在原項目基礎上引入了 vue ,目錄結構等都是和之前項目一致,頁面和組件可以直接使用 vue 語法,hybrid 協議有些許變化。

沒有 webpack 項目的啓動依賴 Charles map local 預覽項目,mock 工具當時使用的是 easy-mock 中間跨域的解決方案是 Charles map remote

硬件交互

我們常見的智能零售或者說其他的智能硬件的交互屏,一般是一個類似 樹莓派 的板子,然後裝載系統。可以是 win,android,也可以是 ios。開發需要 native 初始化一個 webview,然後定義一些通用協議,加載一個頁面似乎就完活了。

通訊協議

開發過程中我們需要 native 賦予我們一些能力,我們需要約定一下通訊協議的格式,其中參數 tagname:協議名稱;param:協議參數;callback:協議回掉(native處理成功以後可能需要返回一些參數信息)
格式如下:

{
    tagname: '', // 
    param: {},
    callback() {}
}

遠程操作

例如用戶掃碼購買了一瓶飲料,我想在零售屏上切換一個歡迎使用的頁面,這個時候需要在 用戶-零售屏 上建立關係,這中間可能需要一個服務端。用戶一開始和服務端建立聯繫,正常的下單購買,購買成功後,服務端推送一條消息給零售機,告訴他有用戶買了瓶飲料,你現在給他推一個飲料出來。

用戶 -> 掃碼 -> 購買 -> 服務 -> 出貨

用戶掃描機器上的二維碼,這個行爲會觸發一個與當前售賣機綁定的操作,綁定成功後服務可以推送一個消息給零售屏,零售屏接收到消息後會切換到歡迎界面,後續的交互包括支付成功,出貨成功這些消息如果要表示到零售屏上都是同樣的道理。用戶與服務,服務與零售屏他們時如何通訊的呢?

用戶與服務之間是數據請求,服務與零售之間爲了通訊保持,建立的是 websocket 連接,零售機內部是 hybrid ,native 調用硬件能力。

問題分析

開發過程中遇見過一些問題,應該是 hybrid 應用開發也會遇到這些問題,相對而言這些問題對比一個成熟的 hybrid 方案要解決的問題要輕很多。

websocket 心跳重連問題

這個問題是消息推送相關。websocket 初始化會後,頁面都是按照如下處理業務

    const ws = new WebSocket('url');
    ws.addEventListener('error', e => {
        // 去維護頁面
    })

    ws.addEventListener('message', event => {
        // 按消息內容處理事件邏輯
    })

    ws.addEventListener('open', event => {
        // 定時發送消息 4min NAT
    })

    ws.addEventListener('close', event => {
        // 去維護頁面
  })

    ws.addEventListener('disconnect', event => {
        // 去維護頁面
    })
  • 單頁應用容器內維持狀態,組件內展示業務狀態。遠程操作時提到的服務與零售屏之間的通訊是 websocket ,零售屏中通過監聽 message 來調用對應的方法處理相應的邏輯。有指定的故障頁面,故障會跳轉到故障頁面,故障有:機器斷網(native捕捉處理),請求超時,服務端主動更新斷開,運維維護斷開等等情況,如果是 websocket 斷開會定時刷新頁面重新連接,如果是 websocket 沒有斷開,數據請求超時等,定時再次請求,如果請求成功切換頁面。

這裏有另外一個問題,零售屏頁面更新的問題,之前是進入維護頁面會定時刷新頁面,這樣如果頁面更新下次刷新肯定可以更新到新的頁面,現在更改成只有斷開 websocket 纔會刷新,這個斷開操作可能會干擾到用戶操作。
對於 app 來說有一個用戶重啓 app 的概念,我們也可以加一個這個功能,機器會斷電,斷電後可以更新或者線下運維人員可以在運維的時候重啓一下。
還有一種方案就是服務向最近10分鐘無狀態的機器推送消息,機器收到消息後強制刷新頁面。

  • 定時發送業務心跳消息。在這之前沒有定時去發送消息,會出現一種情況是受其他原因被關閉了,websocket 並不會監聽到關閉或斷開或錯誤,這樣就不會去重新連接,這時用戶的操作零售屏是收不到任何消息的。服務推送消息是正常推送會提示已經斷開。 Pings have an opcode of 0x9, and pongs have an opcode of 0xA 心跳的發送都是底層協議來做的,但是會涉及到一個問題就是NAT超時鏈路會被斷開,這個時候如果業務沒有數據傳遞,客戶端不會重新建立連接,如果零售屏沒有消息發送就不能出發關閉時間,如果零售機就失聯了,按照Android微信智能心跳方案設置了一個業務心跳,維持長鏈接的活動,這樣以來不會觸發用戶掃碼無響應機器失聯的情況。
    服務可以根據掃碼加推送消息日誌來判斷有沒有具體失聯,如果失聯可以調整業務心跳的觸發時間。

緩存方案

一開始 Native 認爲緩存問題很難處理,直接就在配置中沒有使用緩存,每次頁面加載都會直接重新從線上加載資源(LOAD_CACHE_ONLY),我的每一個狀態頁面切換也都會耗費資源流量,首頁加了一個視頻啊,1G的流量卡如何是好?網絡不好的情況下如何是好?
搜索發現 android 在 webview 中可以有幾種形式設置緩存

// 緩存模式如下:
// LOAD_CACHE_ONLY: 不使用網絡,只讀取本地緩存數據
// LOAD_DEFAULT: (默認)根據cache-control決定是否從網絡上取數據。
// LOAD_NO_CACHE: 不使用緩存,只從網絡獲取數據.
// LOAD_CACHE_ELSE_NETWORK: 只要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。

通過 nginx 配置 http 的緩存協議頭,可以使用 LOAD_DEFAULT ,通過緩存協議來控制。頁面的發佈每一次都會根據內容以 hash 的名字命名編譯文件,每次發佈都能保證修改後的文件會重新從走線上資源拉取。

  • meta標籤,瀏覽器在請求文檔資源時會在請求頭上攜帶 content 信息,可以處理緩存問題,但是對於非瀏覽器緩存的情況下這種形式就失效了
  • meta 標籤是走的 http 協議頭來傳遞,直接設置 http 協議頭不是也可以解決問題嗎
    • 強緩存
      • Expires HTTP/1.0 指緩存過期的時間,超過了這個時間點就代表資源過期
      • Cache-Control HTTP/1.1 指定一個時間長度,在這個時間段內緩存是有效的,單位是s
    • 協商緩存
  • 本地資源緩存,可能我們有時需要更新 app 資源包的形式來更新一些資源,是直接使用 file:// 的形式來讀取資源好一些呢?還是直接走 http:// 的形式好一些呢?很明顯是後者,如果緩存有,強緩存直接用本地。協商緩存或者緩存沒有 native 有直接攔截請求做響應,如果沒有,直接走線上請求。
    編譯項目以後,項目靜態資源可以按需打包到 app 中隨 app 的更新升級做升級。

圖片資源渲染問題

零售屏的二維碼信息時動態更新的,有一個很詭異的bug是二維碼偶爾會出現緩存的問題。瀏覽器渲染機制以及vue內部運行機制,沒有深入沒有發言權,後續如何提升這也是一些方向。
爲了解決圖片的緩存的問題,請求的時候我們都會在圖片的地址上帶上時間戳。詭異的問題描述如下(以下數據都是通過日誌記錄所得):

1. 生成:11:20:34 130281
2. 生成:11:20:50 399538
3. 生成:11:35:09 123391
4. 使用:11:35:15 123391
5. 生成:11:35:30 117602
6. 使用:11:35:37 399538
7. 使用:11:35:44 399538
8. 使用:11:38:29 399538
9. 使用:11:38:42 399538

11:20:50生成一個二維碼,11:35:09生成一個二維碼並正常使用,說明渲染爭取,11:35:30服務日誌記錄最新生成的碼上的信息和用戶上傳上來的信息不一致,如果說請求還沒響應,圖片應該是上一次的正常使用時的情況,不會出現上上次的二維碼。代碼邏輯時按也許需求去續改src。

<img src="" />

能力有限沒能找到問題所在,解決方案不能沒有啊,刷新時等待圖片加載成功後再插入整個圖片元素。不是單純的更新一個屬性,而是整個元素。

系統字體大小修改影響網頁字體大小

實際零售屏都是一個標準,這個需求是一個相對而言的僞需求,建立在不會有人去修改系統配置的情況下,如果有要麼 native 控制,要麼頁面用相對尺寸,px 會按照設置的字體受影響。

多小程序掃同一個碼的需求

零售對應用戶,維護對應運營。運營有一些特殊的權限,不想影響到用戶,單獨需要做一個小程序,用戶端和運維端同時去掃描用戶端的小程序,運維端是拿不到任何小程序上的數據信息。
小程序也考慮到了兼容用戶之前的二維碼的情況,於是有了一個自定義二維碼的規則,按照自己的業務規則配置鏈接,然後生成二維碼,無論是微信掃一掃,用戶或者運維小程序內部掃一掃都可以拿到二維碼上的業務信息,同時爲了兼容之前的小程序碼的掃碼需要做一個掃碼收口處理。

如何進階

這個是我一直在思考的問題,一年前剛剛入職的時候給的目標是一年對比之前的兩年,現在看來一年不如一年,之前還能儘量保證按時學習新的知識點,唯一有出入的是現在可以學而實踐之。從某些方面來說這一年是沒有達到預期的。

沉澱

從入職到現在項目起起伏伏很多次,hybrid 技術方案也有 blade,blade-vue,blade-scripts,react-hybrid,rn(名字我按照自己的實際使用劃分),小程序也有使用原生小程序,wepy,mpvue,也從 javascript 也部分到 typescript ,如果只是把自己侷限在某一個語言或者某一個框架,這樣始終是瞭解如何使用這個框架,學習從文檔開始都可以上手。
Hybrid 從 blade 演進到現在已經是第四個版本了,基本的思想都是在繼續沿用,改進的只是技術方案。這也是我想到在實際工作中不能侷限某種語言或方案,能想辦法把當前工作用的技術方案沉澱下來,延續到以後的工作,不能每一次開局一把刀,裝備全靠撿,積累很重要。

基礎服務

在不斷升級過程中也暴露了一些問題,中間也說明了基礎服務的重要性,剛開始時是0,計劃的是半年內趨於穩定,後面加班的時候會越來越少,後面發現不加班能解決的問題就是換家工作,差別在於加班時你在做的是什麼?
如果是沒有沉澱的情況下你可能需要2天,沉澱後1天或者半天就能完成的工作,剩下的時間讓你加班你是不是可以繼續折騰了?但這些都需要建立在基礎服務完善的基礎之上,沒事的時候就完善通用組件,工具函數,基礎樣式類等,相應的服務端也需要配合演進,不斷打磨中才能更好的完善穩定。

上去就是幹!

其他問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章