一、React Native原理及流程介紹
(一)枉氮、RN前端調(diào)用native整體流程示损;
??js調(diào)native簡(jiǎn)單流程:
??js先根據(jù)moduleName和methodName朗和,查詢本地remoteModuleTable,remoteMethodTable谊娇,得出moduleIndex肺孤,methodIndex索引。再調(diào)用native暴露給js的nativeFlushQueueImmediate方法济欢,執(zhí)行調(diào)用native的邏輯赠堵。
a、native端映射表數(shù)據(jù)結(jié)構(gòu)
??native在啟動(dòng)時(shí)法褥,將初始化由RCT_EXPORT_MODULE指定的模塊茫叭,并加載RCT_EXPORT_METHOD指定的方法到RCTNativeModule中,上圖中module1半等、module2等都是RCTNativeModule類揍愁。并利用JavaScriptCore提供的JSContextRef傳遞remoteModuleTable,remoteMethodTable給到rn前端;
b杀饵、rn前端映射表數(shù)據(jù)結(jié)構(gòu)
??rn前端的remoteModuleTable數(shù)據(jù):
??rn前端的remoteMethodTable數(shù)據(jù):
c莽囤、native與rn前端互調(diào)的例子
??一個(gè)native調(diào)js,同時(shí)js又調(diào)用了native的例子:
(二)切距、native調(diào)用RN前端流程朽缎;
??與前者流程不一致的是,js和Native之間并未協(xié)商一個(gè)通用的js module名及module對(duì)應(yīng)的方法Table谜悟,React Native目前在native端是直接硬編碼话肖,寫死通知rn前端的模塊名及方法名,這要求開(kāi)發(fā)者按照統(tǒng)一的寫法規(guī)范及接口文檔去調(diào)用js赌躺。
??native調(diào)用js:
??底層仍然以JavaScriptCore作為中介狼牺,實(shí)現(xiàn)native對(duì)js的調(diào)用;
Value Object::callAsFunction(JSObjectRef thisObj, int nArgs, const JSValueRef args[]) const {
JSValueRef exn;
JSValueRef result = JSC_JSObjectCallAsFunction(m_context, m_obj, thisObj, nArgs, args, &exn);
if (!result) {
throw JSException(m_context, exn, "Exception calling object as function");
}
return Value(m_context, result);
}
(三)通訊原理總結(jié)礼患;
??React Native主要依賴對(duì)JavaScriptCore的深度應(yīng)用是钥,來(lái)實(shí)現(xiàn)js對(duì)native的調(diào)用掠归,通過(guò)暴露指定的類和接口來(lái)避免觸范apple的上架規(guī)定,避免像JSPatch一樣無(wú)限制的調(diào)用native代碼悄泥。rn js層實(shí)現(xiàn)dom tree和render tree的構(gòu)建虏冻,但是繪制交由了native層處理。
??實(shí)現(xiàn)方案具有創(chuàng)新性弹囚,但還不能完全滿足大型業(yè)務(wù)的開(kāi)發(fā)需求厨相,要對(duì)原有框架作些改進(jìn)和修復(fù)才能在項(xiàng)目中落地。較適合簡(jiǎn)單鸥鹉、有熱更新需要蛮穿、界面元素不太復(fù)雜的業(yè)務(wù)。希望以RN代替native開(kāi)發(fā)還為時(shí)尚早毁渗,除非有機(jī)構(gòu)或個(gè)人React Native對(duì)安卓和iOS提高兼容性践磅,和React Native底層趨于穩(wěn)定。
??但是線程之間切換存在開(kāi)銷灸异,頻繁通訊將導(dǎo)致業(yè)務(wù)流程復(fù)雜府适,需要通過(guò)callback來(lái)實(shí)現(xiàn)。同時(shí)線程切換肺樟,一般會(huì)有10-30毫秒的耗時(shí)檐春,對(duì)于即時(shí)要求嚴(yán)格的場(chǎng)景,應(yīng)盡量避免頻繁需要js與native間的通訊么伯;
二疟暖、充電樁RNBridge層、及RN前端實(shí)現(xiàn)介紹蹦狂;
??為了方便RN業(yè)務(wù)順利開(kāi)展誓篱,有必要對(duì)app原有功能進(jìn)行封裝,如"網(wǎng)絡(luò)凯楔、數(shù)據(jù)庫(kù)窜骄、藍(lán)牙、動(dòng)畫"等摆屯,React Native原生支持不太好或不夠完善的部分邻遏,進(jìn)行補(bǔ)充或修復(fù)。
??RN前端項(xiàng)目結(jié)構(gòu)圖:
??項(xiàng)目中主要是針對(duì)RN的動(dòng)畫實(shí)現(xiàn)機(jī)制有做一些修改虐骑,RN的動(dòng)畫是依賴于js線程和主線程間的通訊准验,但是js線程切換到主線程的時(shí)間不是一致的,時(shí)快時(shí)慢廷没,這樣會(huì)導(dǎo)致主線程更新動(dòng)畫的幀間隔不一致糊饱,如果js線程卡頓,那么主線程的動(dòng)畫也相應(yīng)卡頓颠黎。
??針對(duì)以上問(wèn)題另锋,想到了用native的方式實(shí)現(xiàn)動(dòng)畫滞项,依賴于js端傳來(lái)的表達(dá)式,聲明『動(dòng)畫類型夭坪、動(dòng)畫時(shí)長(zhǎng)文判、時(shí)間循環(huán)次數(shù)』等,RN前端只是給native發(fā)送了動(dòng)畫指令及參數(shù)室梅,動(dòng)畫過(guò)程完全由native操作戏仓。從而最大限度實(shí)現(xiàn)較好的性能。
三亡鼠、安卓效果演示及簡(jiǎn)單介紹赏殃;
四、開(kāi)發(fā)過(guò)程遇到的問(wèn)題及坑點(diǎn)拆宛;
相關(guān)的經(jīng)驗(yàn)總結(jié)備忘:
安卓經(jīng)驗(yàn)總結(jié):
a.用react-native run-android時(shí)嗓奢,提示local.properties,的ndk目錄浑厚、sdk目錄未設(shè)置,打開(kāi)設(shè)置根盒;
b.不能下載https://jcenter.bintray.com/com/google/auto/value/auto-value/1.5.2/auto-value-1.5.2.jar钳幅,可以將ss代理設(shè)置成全局代理⊙字停或者不走shadowsocks客戶端敢艰,直接由as配置ip、port册赛、password钠导、帳戶。
c.默認(rèn)rn demo加載的是本地assets的bundle森瘪,則輸入以下命令:
1)mkdir android/app/src/main/assets
2)react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
d.搖晃vivo牡属,輸入ip:port,之后扼睬,要重啟npm服務(wù)逮栅,才可以在線打bundle包;
e.提示在本地ip的環(huán)境下窗宇,加載locolhost的請(qǐng)求措伐,被跨域攔截,安裝chrome跨域工具军俊;
f.cd Awesome
react-native run-android
i.compile project(':android-jsc')
compile 'org.webkit:android-jsc:r174650'
g.單例莫名被析構(gòu)侥加,原因是當(dāng)前rn js代碼有問(wèn)題,會(huì)強(qiáng)制析構(gòu)ReactActivity及相關(guān)聯(lián)的單例類粪躬。原因未知担败。
開(kāi)發(fā)過(guò)程中常見(jiàn)的問(wèn)題總結(jié):
a.Super expression must either be null or a function, not undefined
component的首字母沒(méi)有為大寫
b.https://github.com/facebook/react-native/issues/14314
Packager can not find entry file index.ios.js in any of the roots... #14314
watchman watch-del-all
rm -rf node_modules && npm install
npm start -- --reset-cache
c.no bundle url
一般是shadowsocks開(kāi)了全局代理導(dǎo)致昔穴。
d.Unable to resolve module `AccessibilityInfo`
重啟電腦,并且npm start --reset-cache
e.Error: Cannot find module '/Users/liuyihao/beehome/node_modules/react-native/local-cli/cli.js'
at Function.Module._resolveFilename (module.js:485:15)
at Function.Module._load (module.js:437:25)
at Function.Module.runMain (module.js:605:10)
at startup (bootstrap_node.js:158:16)
at bootstrap_node.js:575:3
npm ERR! code ELIFECYCLE
npm ERR! errno 1
提示npm ERR! code ELIFECYCLE
rm -rf node_modules && rm ./package-lock.json && npm install
f.
如果出現(xiàn)修改了的代碼不生效氢架,或者出現(xiàn)"Module `*` does not exist in the Haste module map"傻咖、<br>"Unable to resolve module `AccessibilityInfo`",可以嘗試重啟清除npm緩存;
Reset Metro Bundler cache: `rm -rf /tmp/metro-bundler-cache-*` or `npm start -- --reset-cache`.
h.
render方法的括號(hào)一定要在return后面岖研,不可以換行卿操,否則將crash.
return ()