ios WaxPatch熱更新原理


以下是引用他人文章內容:

  • 為什么需要 WaxPatch
    很多情況下,已經在 AppStore 上線的應用需要緊急缺陷修復,此時便需要使用某些技術手段,使應用程序能夠動態下載補丁,進行缺陷修復。
  • 什么是 WaxPatch
    迄今為止,腳本語言中運行速度最快的是 Lua。Lua 語言由巴西里約熱內盧天主教大學的 Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo 於 1993 年開發的。其最初的設計目的是提供一個方便嵌入到應用程序中得腳本語言。Lua 語言完全使用 ANSI C 實現,其設計精巧,代碼優美。Lua 的解釋器總共在 200k 大小,而且運行速度大約是 C 語言的 1/5,語法比較簡單,即使不是專業的編程人員也容易掌握。
    2003 年,隨着暴雪的大型在線網絡游戲 《魔獸世界》的發布,Lua 逐漸被人們所知(《魔獸世界》的插件系統就是使用 Lua 開發), Lua 逐漸在游戲界流行起來。現在國內幾乎大部分游戲策划都使用 Lua 語言來進行數值或者關卡的設計。

    《魔獸世界》內的Lua編輯器

由於 Lua 編程簡單,運行速度快,在 iOS 上, 一個支持使用 Lua 語言編寫 iOS 應用的項目 Wax 誕生了。Wax 項目允許用戶使用 Lua 語言調動蘋果 iOS SDK 的功能,進行應用程序的開發。

Wax Patch 項目是由 Wax 項目衍生而來,Wax patch 不僅僅允許用戶使用 Lua 調用 iOS SDK 和應用程序內部的 API, 而且使用了 Objective-C runtime 的 class_replaceMethod 調用替換應用程序內部由 Objective-C 編寫的類方法,從而達到功能微調或者缺陷修復的目的。

Wax/WaxPatch 主要特點:

● 所有 Objective-C 調用接口構建在 Objective-C runtime 之上,所以其調用 Objective-C 的 API 方式非常方便,不像調用 C/C++ 哪樣,必須先為 Lua 編寫調用接口(有些技術可以幫助 Lua 調用 C/C++ 編寫的動態庫而不必事先編寫調用接口, 但是在 iOS 上不能調用應用程序自己編寫的 API)。

● 對於 Objective-C 和 Lua 之間的數據類型轉換進行了封裝,使得開發者不必關心 Lua 和 Objective-C 的數據類型轉換,方便開發。
WaxPatch 工作原理
Objectvie-C 語言的特性和實現機制決定了任何其他腳本語言對其進行調用都很方便。主要原因在於 Objective-C runtime 提供了對於 類/對象 等 OC 類型的反射和自省機制。
相關的 API 如下:

typedefstruct objc_class *Class;
structobjc_object "【"Class isa OBJC_ISA_AVAILABILITY;"】";
typedefstruct objc_object *id;
typedefstruct objc_selector *SEL;
typedefid (*IMP)(id, SEL, ...);
SELsel_getUid(const char *str);
constchar *object_getClassName(id obj);
Classobjc_getClass(const char *name);
Methodclass_getInstanceMethod(Class cls, SEL name);
Methodclass_getClassMethod(Class cls, SEL name);
IMPclass_getMethodImplementation(Class cls, SEL name);
IMPclass_replaceMethod(Class cls, SEL name, IMP imp, const char *types);

藉由以上 API,則可以通過字符串來動態調用 Objective-C 的類和對象的方法。

Wax/WaxPatch 調用 Objective-C 並不是簡單得對 Objective-C runtime 的 API 進行 1 對 1 得封裝,而是把所有的 Objective-C 的對象\類\函數\等抽象成一個 WaxInstance,對 WaxInstance 進行操作。而 WaxPatch 則對 WaxInstance 的元表的 __newindex 屬性進行改寫,調用 class_replaceMethod 方法改寫父類的函數實現,使用 forwardInvocation 機制把針對父類的調用方法轉發到 Lua 改寫的類方法里面。
動態補丁流程
我們在一些項目中使用 WaxPatch 來實現熱更新機制,主要的流程如下所示。

1. 補丁包發布流程

2 客戶端請求補丁流程

3 客戶端使用補丁流程

整個流程遵循以下原則:

● 簡單有效,避免復雜邏輯。整個補丁包是所有補丁的全量包而不是增量包。

● 安全性要有保證。發布版的補丁包是需要經過加密的,避免被惡意篡改。

● 正確性。在打補丁的過程中,一旦出現錯誤,則立刻退出補丁流程,避免對原應用程序的流程產生致命的損壞。

4 全量補丁包格式
├── 20150701_01
│ ├──LoadPatchViewController.lua
│ └──init.lua
├── 20150703_01
│ ├──LTMoviePlayerViewController.lua
│ ├──LTPlayControlCenterView.lua
│ └──init.lua
├── LuaPatchManager.lua
└── letv_hotpatch_mapping.lua

① letvPatchManager.lua :補丁管理和執行文件,通過對客戶端版本號和 letv_hotpatch_mapping.ua 文件判斷補丁是否應該用於客戶端。
② letv_hotpatch_mapping.lua:補丁索引文件,記錄補丁適用於那個客戶端版本。
③ 20150701_01:補丁包分包,為了方便補丁包管理,對單個補丁文件進行分組。
④ 20150701_01/init.lua:補丁分組執行文件。
⑤ 20150701_01/xxxx.lua:功能性的補丁。
整個方案主要由以下部分組成:

● 補丁包管理器:集成在客戶端內部,使用 Objective-C 編寫,負責從服務器下載補丁包,並解壓到客戶端的沙盒中。

● 補丁包:見上文。

● 補丁打包器:負責把所有明文補丁進行加密,並打包成 zip 格式供客戶端下載。
改進WaxPatch
block 調用和實現
WaxPatch 對於 Objective-C 的 block 支持不夠完備,雖然有一些 WaxPatch 的衍生版本增加了一些 block 的支持,但是並不能令我們滿意,尤其是 block 的參數支持上。對此。我們自己增加了 WaxPatch 對 block 的支持,做到了對 block 的可變參數的支持。

安全性解決方案
由於 WaxPatch 可以做到對所有 Objective-C 的 API 修改(包括系統的和客戶端內部的)。所以理論上來說,一個非法的 lua 補丁可以修改客戶端所有的流程和功能,以致於對最終用戶的信息造成傷害。

為了保證客戶端功能和流程的安全性,在發布的補丁包中,所有的 Lua 補丁源碼都由秘鑰進行加密。在客戶端方面,我們針對 Lua 的解釋器進行修改,使用公鑰進行解密和驗證碼,避免非法的 Lua 補丁文件被執行。
其他解決方案與結論
與 WaxPatch 方案相同的另外一個方案是 JSPatch。JSPatch 使用系統內置的 Javascript 解釋器來動態 Javascript 代碼,達到與 WaxPatch 同樣的目的。其原理與 WaxPatch 基本相同。

經過調查,JSPatch 與 WaxPatch 相比,有一些固有的缺點無法解決:

① 在 iOS6.0 系統上,Apple 並沒有開放 JavascriptCore 引擎,需要自己內置 JS 引擎,增加客戶端的體積。

② 由於 JSPatch 使用系統的 JavascriptCore 引擎,我們無法去驗證 Javascript 補丁的合法性和有效性,對客戶端帶來了很大的安全隱患。

以上原因決定使用 WaxPatch 的方案而不是 JSPatch 的方案。

軟件開發的正途應該是:以加強代碼質量和嚴格的測試來控制客戶端質量。雖然 WaxPatch 可以做到對線上應用程序的缺陷進行快速修復,但是這種手段永遠只能作為最后的一個防線,而不能過於依賴它。

附上開源項目

https://raw.github.com/mmin18/Create-a-More-Flexible-App/master/Wax
https://github.com/mmin18/WaxPatch

https://github.com/piaojin/iOS-WaxPatch


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM