近段時間來,關(guān)于移動客戶端方面的動態(tài)化解決方案有了不少。之前的JSPatch,滴滴的解決方法:DynamicCocoa绊诲,微信iOS開發(fā)團(tuán)隊(duì)的解決方案:OCS。而今天需要說道的是React Native褪贵。
1. 背景
首先簡單介紹下滴滴和微信的解決方案掂之。
-
1.1 DynamicCocoa
DynamicCocoa 可以讓現(xiàn)有的 Objective-C 代碼轉(zhuǎn)換生成中間*代碼(JS),下發(fā)后動態(tài)執(zhí)行脆丁,相比其他動態(tài)化方案世舰,優(yōu)勢在于:- 使用原生技術(shù)棧:使用者完全不用接觸到 JS 或任何中間代碼,保持原生的 Objective-C 開發(fā)偎快、調(diào)試方式不變
- 無需重寫已有代碼:已有 native 模塊能很方便的變成動態(tài)化插件
- 語法支持完備性高:支持絕大多數(shù)日常開發(fā)中用到的語法冯乘,不用擔(dān)心這不支持那不支持
- 支持 HotPatch:改完 bug 后直接從源碼打出 patch,一站式解決動態(tài)化和熱修復(fù)需
最重要DynamicCocoa有一下特點(diǎn):
- 完整的 Class 定義:interface晒夹、category、class extension姊氓、method丐怯、property,最重要的是支持完備的 ivar 定義翔横,保持和 native 完全一致的實(shí)例內(nèi)存結(jié)構(gòu)
- ARC:可以正確處理 strong读跷、weak、unsafe_unretained 等對象的引用計數(shù)禾唁,對象的 ivar 也可以正確的釋放
- C 函數(shù):支持 C 函數(shù)的定義與 C 函數(shù)的調(diào)用效览、內(nèi)聯(lián)函數(shù)的調(diào)用
- 可變參數(shù):支持 C 與 OC 的可變參數(shù)方法的調(diào)用无切,如 NSLog
- struct:支持任意結(jié)構(gòu)體的使用,無需額外處理
- block:支持創(chuàng)建和調(diào)用任意參數(shù)類型的 block
- 其他 OC 特性:如 @selector丐枉、@protocol哆键、@encode、for..in 等
- 其他 C 特性:支持使用宏瘦锹、static 變量籍嘹、全局變量,取地址等
-
1.2 OCS
OCS是全新設(shè)計的iOS動態(tài)化方案弯院。我們定義了一套精確描述OC語義的字節(jié)碼指令集(OCScript)辱士,開發(fā)了一套全自動編譯器(OCSCompiler),實(shí)現(xiàn)了一個高性能的虛擬機(jī)(OCSVM)以及一個可以跟底層無縫對接的橋接器(OCSBridge)听绳。我們首先使用OCS編譯器把OC源碼轉(zhuǎn)化成OCS字節(jié)碼颂碘,然后通過OCS橋接器實(shí)現(xiàn)OCS虛擬機(jī)與Native運(yùn)行時的互聯(lián),最后使用OCS虛擬機(jī)對OCS字節(jié)碼進(jìn)行解釋運(yùn)算椅挣,并驅(qū)動Native運(yùn)行時完成邏輯的執(zhí)行凭涂,以此達(dá)到Native代碼動態(tài)化的效果。OCS被用于iOS APP安裝包減包贴妻、功能插件化切油、HotPatch等方方面面動態(tài)化需求。- OCS有哪些與眾不同之處
- 語義與OC保持嚴(yán)格一致
OCS字節(jié)碼指令集語義與OC/的語義保持嚴(yán)格一一對應(yīng)關(guān)系名惩,支持的數(shù)據(jù)類型也完全等同澎胡,運(yùn)行過程無需進(jìn)行任何轉(zhuǎn)換,因此效率非常高娩鹉。 - 自動化工具支持
OCS擁有完善的自動化工具鏈攻谁,OCS編譯器支持絕大多數(shù)OC/C語法的轉(zhuǎn)化,包括C方法弯予、任意自定義結(jié)構(gòu)體戚宦、任意自定義block。對于少數(shù)不支持的的語法锈嫩,可以準(zhǔn)確報錯受楼,引導(dǎo)用戶進(jìn)行規(guī)避,避免產(chǎn)生未定義行為呼寸。OCS編譯器還可以準(zhǔn)確識別OC/C代碼的內(nèi)存管理語義艳汽,可以正確生成內(nèi)存管理相關(guān)的代碼。特別對于ARC來說对雪,可以準(zhǔn)確生成Retain河狐、Release代碼,正確插入到生成代碼中去。 - 原生OC內(nèi)存管理機(jī)制
OCS虛擬機(jī)完全支持Native的內(nèi)存管理機(jī)制馋艺,可以在正確的時機(jī)執(zhí)行正確的內(nèi)存釋放邏輯栅干,絕無延遲操作,徹底杜絕了Crash和爆內(nèi)存風(fēng)險的引入捐祠。 - 搶占式多線程
OCS虛擬機(jī)支持Native的搶占式多線程線程管理支持碱鳞,完全支持Pthread、 GCD雏赦、 NSOperationqueue劫笙、 NSThread等各種線程模型,完全避免了額外引入Crash星岗、卡頓與死鎖風(fēng)險填大。 - 高性能匯編ABI
OCS橋接器根據(jù)過程調(diào)用約定實(shí)現(xiàn)自定義OCSABI,使得虛擬機(jī)與Native底層實(shí)現(xiàn)直接通信俏橘,保證Native代碼動態(tài)化引入額外性能損耗最小化允华,使得OCS動態(tài)化不僅普遍適用于普通邏輯轉(zhuǎn)化,對于對性能要求苛刻的有復(fù)雜排版的滑動列表寥掐,OCS也有極佳的表現(xiàn)靴寂,動態(tài)化后掉幀率增長量幾乎可以忽略不計
- 語義與OC保持嚴(yán)格一致
- OCS有哪些與眾不同之處
ps:OCS完整介紹
-
1.3 ReactNative
React Native 讓開發(fā)者使用 JavaScript 和 React 編寫應(yīng)用,利用相同的核心代碼就可以創(chuàng)建 Web召耘,iOS 和 Android 平臺的原生應(yīng)用百炬。React Native 的宗旨是,學(xué)習(xí)一次污它,高效編寫跨平臺原生應(yīng)用剖踊。- React Native有什么優(yōu)點(diǎn)
提供了原生的控件支持
使用 React Native 你可以使用原生的控件,入在iOS平臺我們可以使用UITabBar控件衫贬,在Android平臺我們可以使用Drawer控件德澈。這樣,就讓我們的App從使用上和視覺上擁有像原生App一樣的體驗(yàn)固惯。而且使用起來也非常簡單梆造。-
異步執(zhí)行
所有的JavaScript邏輯與原生的代碼邏輯都是在異步中執(zhí)行的。原生的代碼邏輯當(dāng)然也可以添加自己的額外的線程葬毫。
這個特性意味著镇辉,我們可以將圖片解碼過程的線程從主線程中抽離出來,在后臺線程將其保存在磁盤中供常,在不影響UI的情況下計算調(diào)整布局等等摊聋。所以,這些讓React Native開發(fā)出來的App都是較為的流暢栈暇。
這個之間的通信過程也是有序列化來完成的,這個就讓我們可以使用Chrome Developer Tools 來完成JavaScript邏輯的調(diào)試箍镜,當(dāng)然我們也能夠在模擬器和物理設(shè)備上調(diào)試源祈。 觸屏處理 React Native實(shí)現(xiàn)了高性能的圖層點(diǎn)擊與接觸處理煎源。
Flexbox的布局樣式 使布局將變得更簡單,這就使我們?yōu)槭裁匆獙⒕W(wǎng)頁的布局模式切換到React Native的Flexbox布局模式香缺。Flexbox讓UI布局變得簡單手销,入使用margin和padding的嵌套模式。當(dāng)然图张,React Native 同樣也支持網(wǎng)頁原生的一些屬性布局模式锋拖,如FontWeight之類的。這些聲明的布局和樣式祸轮,都會存在內(nèi)聯(lián)的機(jī)制將其優(yōu)化兽埃。
Polyfills機(jī)制 React Native也支持我們使用第三方的JavaScript庫,來方便我們的開發(fā)适袜。支持npm中的成千上萬的模塊柄错。
基于React JS 擁有React JS的優(yōu)良特性。
- React Native有什么優(yōu)點(diǎn)
2. 抉擇
通過上面的簡單介紹苦酱,可以看出DynamicCocoa和OCS都還是很厲害的售貌。對于iOS開發(fā)人員,可以不需要去花費(fèi)過多的時間來學(xué)習(xí)其他語言疫萤,使用原生的Object-C也可以基本完成動態(tài)化颂跨。然后在實(shí)際開發(fā)中,以及實(shí)際的項(xiàng)目中扯饶,功能不僅僅是在iOS平臺上面恒削,同時在Android中也需要。這個時候就比較尷尬了帝际。但是ReactNative卻不一樣蔓同,他是跨平臺的,可以同時支持iOS和Android蹲诀,同時可以達(dá)到原生的效果(雖然和其他兩個的性能上還是有些差距)斑粱,而且現(xiàn)在的手機(jī)性能都在不斷提升,利弊權(quán)衡下脯爪,個人覺得ReactNative相對是更優(yōu)選擇则北。
3. ReactNative應(yīng)用
這里主要相對于現(xiàn)有工程
- 3.1 在現(xiàn)有工程中添加ReactNative
條件: - 1、CocoaPods
- 2痕慢、Node.js
步驟:
- 1尚揣、工程根目錄下創(chuàng)建ReactComponent
- 2、在ReactComponent目錄中創(chuàng)建JS文件(例如:index.ios.js)掖举,并初始化
npm init
- 3快骗、通過CocoaPods安裝ReactNative庫
def react_native
# 取決于你的工程如何組織,你的node_modules文件夾可能會在別的地方。
# 請將:path后面的內(nèi)容修改為正確的路徑(一定要確保正確~~)方篮。
pod 'React', :path => ‘./ReactComponent/node_modules/react-native', :subspecs => [
'Core',
'ART',
'RCTActionSheet',
'RCTAdSupport',
'RCTGeolocation',
'RCTImage',
'RCTNetwork',
'RCTPushNotification',
'RCTSettings',
'RCTText',
'RCTVibration',
'RCTWebSocket',
'RCTLinkingIOS',
]
end
- 4名秀、執(zhí)行CocoaPods
pod install
- 5、添加原生代碼
NSString * strUrl = @"http://127.0.0.1:8081/index.ios.bundle?platform=ios&dev=true";
NSURL * jsCodeLocation = [NSURL URLWithString:strUrl];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"AwesomeProject"
initialProperties:nil
launchOptions:nil];
self.view = rootView;
- 6藕溅、運(yùn)行react
npm start
- 7匕得、運(yùn)行原生應(yīng)用(Run)
4. ReactNative發(fā)布
在技術(shù)上來講當(dāng)然可以把react程序放在服務(wù)器上,但是加載速度就比較慢巾表,在用戶體驗(yàn)上當(dāng)然也會減分不少汁掠。因此可以通過打離線包(jsbundle)的方式,通過服務(wù)端控制來實(shí)現(xiàn)程序的動態(tài)化(類似JSPatch發(fā)布機(jī)制)。
- ReactNative離線打包
我們用‘react-native bundle’命令把JS代碼打包成一個bundle文件集币。然后客戶端直接訪問這個bundle文件即可考阱。
命令說明
react-native bundle
Options:
命令 | 枚舉 | 解釋 |
---|---|---|
--entry-file | index.ios.js | 入口文件 |
--platform | "ios"/"android" | 平臺 |
--transformer | /packager/transformer.js | transformer |
--dev | false /true | 調(diào)試開關(guān) |
--prepack | false/true | |
--bridge-config | ||
--bundle-output | 路徑 | bundle包目標(biāo)路徑 |
--assets-dest | 資源文件路徑 | 資源文件路徑 |
- 修改原生代碼
NSURL * jsCodeLocation = [[NSBundle mainBundle ] URLForResource:@"main" withExtension:@"jsbundle"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"AwesomeProject" initialProperties:nil launchOptions:nil];
self.view = rootView;