iOS 遠端代碼下發: 使用 JS 設計 Patch

iOS 遠端代碼下發,有什麼設計思路 ?

通常你們都用 JSPatch?前端

用別人的,總很差。老王造了個輪子,我來描述一下。git

老王 Patch, 挺先進的。JavaScript 代碼, 採用 WebPack 打包。也參考了 JSPatch ,

怎麼設計這個 Patch?github

從原理上


Patch 主要是 幹什麼的呢?
通常大公司的 App 在運行的過程中,業務線很是複雜,可能會出現一些問題。後端

這個時候,打補丁比較好

能夠遠端下發一個文件,開發的 App 經過 加載 這個文件,
實行 這個 代碼 補丁。app

這個樣子,就能夠經過遠端, 把這個代碼, 在開發的 app 運行當中,給執行過來,

OC 能夠的,由於是動態語言,有 runtime ,因此才能搞這個 patch。函數

OC 有本身的消息轉發流程。 Runtime 有 objc_msgSend_objc_msgForward
Runtime 有這兩個方法,
這兩個函數特性,讓全部的函數調用都會走這兩個方法。優化

這樣就能夠幹一些 patch 的事情。

另一點, 在 App 中植入了這個 patch ,他所使用的語言,可以被 eval 。

eval, 判斷代碼語句能夠執行

這樣 app 中有一個 context, 能夠執行用於 patch 的語言。lua


本文中的 iOS 補丁方案直接運用 這個 JavaScriptCore,
就是使用 JavaScriptCore 提供的 JSContext.
能讓 JavaScript 語言 和 Objective-C 之間,有一個接口。而後就能夠 JavaScript 與 Objective-C 相互調用了。
( 蘋果本身實現的 )設計

JSPatch 用到了 FFI,這個庫老王 Patch 也使用了 FFI .

FFI, Foreign Function Interface ,就是把一個語言暴露出來的接口,能讓其餘語言來調用。
Java 的 JNI 標準,與 FFI 比較類似。
FFI ,首先聽從 Coding Convention ,就是定義遵照一些調用的協議和規定。
爲何要有 FFI 呢?指針

舉個 🌰:

咱們執行一個函數調用,首先開闢一個棧幀,這個棧幀傳遞一些什麼樣的參數?參數的類型是什麼?參數 的個數,是多少?包括這個函數裏面,執行的一些動做是什麼?
FFI 就把遵照的一些調用的協議和規定定義出來。


老王 Patch 庫的這個自定義 FFI , 就是把想作的 patch 語言, 對接 Objective-C 的執行環境。
須要往裏面傳遞的命令,把這個東西,給規定出來。

這個樣子, 在執行這個 Patch 的過程當中,就能夠按照這個命令,去發相應的消息,讓相應的 context ,執行須要 patch 的代碼。

FFI 就到這裏了。 開啓預編譯。

使用 JSPatch 的過程中,老王發現,用的很是的不順手,
爲何他不順手呢?
老王覺得,JSPatch 把 JavaScript 硬生轉換成至關於 Objective-C 這種風格的,補丁代碼。
其間,還作了不少的語言處理,包括 Bang 說的源函數的處理。
包括 C 語言函數,相似 Ruby 的 Method Mission .
至於其餘, 老王覺得, JSPatch 都是在後端進行的。

JavaScript 的 逼真度

要增強Patch, 自己具備的語言的一個平滑性,就是寫 JavaScript , 就使用 JavaScript 的寫法

引出了預編譯的過程:

把 JavaScriptContext 的註冊接口,抽象出三個層,

define, 定義

define, 往 Objective-C 發消息。 不須要參數返回, 能夠用 define .
須要定義的,確定都本身定義的。
抽象出這一層,就能夠了。

evaluate

須要一個返回值的時候,使用
去執行一些什麼任務

Callback

老王感受蘋果封裝的 JavaScriptContext,可能有一些問題。
好比說, 傳遞的一些函數對象,開發者封裝了兩層。那就可能獲取不到這個對象了。
這個時候, 須要 Callback 方式,在那個執行環境當中,獲取前端的 function 內容。
用 JavaScriptCore 相關的一種回調方式,來取到在當前 JavaScriptContext 環境 當中的一個 function 值。

還有就是指令類型

這個 patch ,是幹什麼的? 對所使用的內容, 有哪些指令?

  • Patch 就是 執行 一些 Method 函數 的 一些 hook,
  • 會修改 一些 property 的值了。
  • 會 作一些 block 方面的改動了。
  • 訪問 父類 super
  • 咱們 能夠 新增 函數,method_create

經過 這些指令,咱們能夠實現, 想要 patch 到的一些功能

還有關鍵字轉換:這個經過預處理來實現。要完成對一些關鍵字的處理。

對於 Objective-C 中的 self 關鍵字, 一般用來表明當前對象的指針。
還須要改 super 關鍵字, 爲 oc_super. 由於 super 在 ECMAScript 6 裏面, 也是關鍵字了,須要迴避掉。
original, 是 Patch 中特有的。調用以前的函數,即打補丁以前的這個函數的調用。

一些優化,舉個 🌰: JS 寫 高階函數

對 JavaScript 高階函數作一個平滑處理,不然可能寫起來,很是費勁。

a.request( 

function(a:id,b:Int):double{},
callback:(string,string) => int,
(num1:string, num2:double) => { return num1 + num2; } 

);

request 方法, 有三個參數。三個 function 類型的參數。第一個 function 函數,接收兩個參數。第二個參數 callback, 是咱們在函數調用上下文中取到的。第三個參數是, ECMAScript 6 中使用的箭頭函數。
最好呢,對這個進行一些支持。
這些操做,是經過預處理的方式,
編譯成,可以對接 OC 的 Block 指令的。

而後,才能 正常 完成工做。

JSPatch 是很好的參考,

你們都仿照 JSPatch,在 JavaScriptContext 中註冊一大堆本身要進行 patch 的函數。
想要用到什麼,就去補充什麼。
通常都是徹底借鑑 Bang 的一些想法。

最好呢? 要把 JSPatch 的這麼一些想法,背後的東西,給抽象出來。

缺點,沒使用挺好用的 JSExport 協議, JSVirtualMachine

Github 官方 repo 連接:https://github.com/wangyunico...

個人民間 repo , https://github.com/BoxDengJZ/...

相關文章
相關標籤/搜索