react-native-update@4.0版本 具體熱更新的機制

熱更新原理

  • react-native 的程序其實是原生的模塊+JS和圖片資源模塊,熱更新,就是更新其中的js和圖片資源。react

  • 安卓程序把它名字命名爲zip解壓後能夠清楚的看到其中的bundle文件和資源文件ios

熱更新的方法

熱更新又分爲全量更新和增量更新。算法

  • 全量更新是直接去服務器抓取你上傳的ppk文件,下載下來,直接覆蓋本地的ppk文件。json

  • 增量更新是使用了bsdiff算法,用來比對二者bundle之間的區別,而後只修改不同的地方。react-native

啓動程序的時候,會發一個請求給服務器,詢問我需不須要更新api

URL: http://update.reactnative.cn/api/checkUpdate/${key}
抓包也好,看源碼也好,結論就是使用的是這個請求帶上本身熱更新json的key值,用來匹配你的app服務器

{
    "upToDate": true,
    "ok": 1
}

這個是服務器返回給個人值,若是是已是最新的版本了,就會返回upToDate給我。app

{
    "expired": true,
    "downloadUrl":'xxx',
    "ok": 1
}

若是是須要硬版本更新了,就會返回一個expired的給我,順便給我一個downloadUrl(隨便寫的,具體可能不是這個名字,懶的再去刪版本看了)的參數,固然這個參數是我在他家官網配置的,就是我新版本的下載地址。iphone

這個時候,若是是須要熱更新了,根據當前版本react-native-update@4.xxx的大量數據試驗狀況來看,返回格式無非就兩種,雖然源碼裏有第三種async

{
    "update": true,
    "hash": "FppJ-yU8-_bvYJe5Sg5_opUp_eFH",
    "name": "0.2.1",
    "description": "test",
    "metaInfo": "0.2.1",
    "updateUrl": "http://update-packages.reactnative.cn/FppJ-yU8-_bvYJe5Sg5_opUp_eFH?e=1483510148&token=made75kGFhOozkiRfa7LK_E1xG1pLOnhW8fhbnev:t2YXoxZZXQImvvyHH1hdrnNNRmQ=",
    "pdiffUrl": "http://update-packages.reactnative.cn/lpKbEZnU6_T-mvwZGfzIQby489Bm-FppJ-yU8-_bvYJe5Sg5_opUp_eFH.pdiff?e=1483510148&token=made75kGFhOozkiRfa7LK_E1xG1pLOnhW8fhbnev:YBI4sdIEr30wa1DHV4xnMUlI1bU=",
    "ok": 1
}

update爲true表明我須要熱更新,其中有個參數叫updateUrl,這個參數提供的地址就是全量更新的地址,會把我整個bundle都下載下來。
還有一個參數叫pdiffUrl,這個就是增量更新,我會去下載一個pdiff文件,而後你檢測會發現,在安卓狀況下,你的cpu已經跑起來了,後臺程序數據漲起來了,可是流量沒動,由於走的是內部計算,測試了一下發如今不一樣的手機上表現也不同。
酷派A8930:120S
ViVioX7:90S
小米5:75S。
iphone全系手機1S-5S之間。(目測不是一我的寫的代碼,或者是安卓讀寫的線程出了某些問題,僅僅是猜想)
以上時間都是單單是計算時間,由於下載增量更新那幾十K也就1S的事情。

關於服務器是否返回pdiffUrl的狀況我仍是不能推算出官方的原理,由於一樣的一個包,有的時候它會返回pdiffUrl,有的時候卻只有updateUrl,不過好在無論什麼狀況下,都有updateUrl,那麼咱們就能夠利用這個點,把沒必要要的等待給改掉。
好比我流量不少,我不想讓個人安卓機器等待100S,又不想後臺靜默更新,那就直接改源碼,好在源碼找的很快,修改更是容易。

export async function downloadUpdate(options) {
  if (!options.update) {
    return;
  }

  if (options.diffUrl) {
    await HotUpdate.downloadPatchFromPpk({
      updateUrl: options.diffUrl,
      hashName: options.hash,
      originHashName: currentVersion,
    });
  } else if (options.pdiffUrl) {
    await HotUpdate.downloadPatchFromPackage({
      updateUrl: options.pdiffUrl,
      hashName: options.hash,
    });
  } else {
    await HotUpdate.downloadUpdate({
      updateUrl: options.updateUrl,
      hashName: options.hash,
    });
    
  }
  return options.hash;
}

這個就是它判斷是否走增量更新的代碼,其中diffUrl我歷來沒見到過,因此不動邏輯,因此很簡單,把增量和全量調換個順序就OK了

export async function downloadUpdate(options) {
  if (!options.update) {
    return;
  }

  if (options.diffUrl) {
    await HotUpdate.downloadPatchFromPpk({
      updateUrl: options.diffUrl,
      hashName: options.hash,
      originHashName: currentVersion,
    });
  } else if (options.updateUrl) {
    await HotUpdate.downloadUpdate({
      updateUrl: options.updateUrl,
      hashName: options.hash,
    });
  } else {
    await HotUpdate.downloadPatchFromPackage({
      updateUrl: options.pdiffUrl,
      hashName: options.hash,
    });
  }
  return options.hash;
}

搞定,親測後發現,安卓在即便服務器給了我pdiffUrl的狀況下,我依然也會去選擇全量更新,恩,也就費個3M流量,可是你們都是無線網,因此20S之內,這個熱更新確定就行了,就不須要等待那麼久了。

問題

  • 我發現這個index.js文件裏沒有區分Ios和安卓,因此若是我想讓ios走原來的邏輯還須要判斷一下,因此後續會測試下好很差用。

  • 用上了bsdiff算法後,切記切記,你的下載地址的ipa包也好,apk包也好,必定必定要和update.reactnative.cn上的包保持徹底一致。不然一旦第一次走的是增量更新,那麼恭喜你,無限重啓。
    爲何會出現這樣的問題,個人猜想是:

(update.cn上的包是7號,給用戶下載地址上的包是8號,8號的程序內容比7號僅僅是多了幾個文案修改。這個時候,我推送一個熱更新上去,名字叫10號。那麼它的計算方式原本是10號減去7號的 = 3,而後拿着這個3去加7 = 10,更新成功。可是你手裏的包倒是8,他仍是拿10-7=3,3+8 卻=11!=10.boom爆炸。11!=10,無限熱更新。卻永遠都對不上。因此無限重啓)括號內容僅僅是猜想,沒有和官方溝通。

相關文章
相關標籤/搜索