rn版本:0.55
原生和rn混編
TouchableWithoutFeedback系列組件內(nèi)部包含的Text設(shè)置lineHeight時忧吟,在某些安卓手機上可能導致文本顯示出現(xiàn)被切割現(xiàn)象
安卓的部分組件如Text無法撐開父視圖的寬高
安卓和ios的Text組件文本內(nèi)置間隙差異很大
Dimensions.get('window’)獲取的屏幕寬高芦拿,在某些安卓機型上面有問題,例如沒有考慮頂部狀態(tài)欄和底部按鍵欄目捺宗,需要原生另外寫方法判斷
對Animated.View等動畫組件,設(shè)置transform的scale為0在某些安卓手機上無法完全隱藏,可以配合設(shè)置opacity為0實現(xiàn)效果
rn執(zhí)行的代碼中涉及到原生代碼有改動,則該rn包不能下發(fā)給舊的app版本笔咽,需要做版本控制
rn頁面實現(xiàn)類似viewwillappera的代理方法
前提是所有的rn頁面的跳轉(zhuǎn)是由原生控制,rn僅僅是顯示作用毡惜。跳轉(zhuǎn)到rn頁面代碼如下
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:properties];
RNViewController *vc = [[HCZRNViewController alloc] init];
[vc.view addSubview:rootView];
[nav pushViewController:vc animated:YES];
RNViewController就是一個普通的UIViewController拓轻,在內(nèi)部的viewWillAppear中發(fā)出通知斯撮,通過RCTEventEmitter將事件傳遞給RN頁面(RN頁面需要監(jiān)聽該事件才行)
rn拆包
拆分給common和業(yè)務(wù)包经伙,common只包含公共的基礎(chǔ)組件,為各個業(yè)務(wù)模塊共用勿锅,可以采用內(nèi)置方案帕膜,程序啟動時的Bridge就先加載該模塊。
業(yè)務(wù)包為各個業(yè)務(wù)模塊所獨立溢十,打包時會根據(jù)內(nèi)部依賴將該業(yè)務(wù)模塊所依賴的組件全部導出垮刹,內(nèi)部會包含commom模塊的內(nèi)容,需要過濾掉张弛,減少體積荒典。
--manifest-output命令就是獲取各個組件的特征id值,通過對比id值實現(xiàn)過濾
下面是某個業(yè)務(wù)模塊拆包的腳本文件吞鸭,shell語言編寫
#輸入ios和android
read -p "輸入platform: " -r platform
resultDir=./dist
bundlerBin=./node_modules/metro-bundler-cli/bin/metro-bundler-cli.js
bundlerCmd="$bundlerBin bundle --platform $platform --dev false"
#清空結(jié)果目錄
if [ -e "$resultDir" ]; then
rm -r $resultDir/*
else
mkdir $resultDir
fi
#打包common組件寺董,目的是獲取common的特征值。 --manifest-output獲取common組件的特征id值base.manifest.json文件
$bundlerCmd --entry-file ./base.js --bundle-output $resultDir/base.jsbundle --manifest-output $resultDir/base.manifest.json --use-stable-id true
#打包業(yè)務(wù)組件 --exclude為過濾命令刻剥,根據(jù)base.manifest.json文件遮咖,過濾掉業(yè)務(wù)組件中所包含的common組件
$bundlerCmd --entry-file pax_index.js --bundle-output $resultDir/pax.jsbundle --manifest-output $resultDir/business.manifest.json --assets-dest $resultDir --exclude $resultDir/base.manifest.json --use-stable-id true
#壓縮到目標文件,該文件用來給APP下載熱更新造虏,并且替換APP本地文件
cd $resultDir
if [[ "$platform" = "ios" ]]; then
cp ../switch.json switch.json
zip -r paxIos.zip pax.jsbundle assets switch.json
fi
else
cp ../switch.json ./switch.json
zip -r paxAndroid.zip pax.jsbundle drawable-mdpi switch.jsonfi
程序運行時需要將common和業(yè)務(wù)模塊合并御吞,可以采用算法將jsbudle合并在執(zhí)行麦箍,也可以采用更簡單的方式,Bridge創(chuàng)建時先加載common內(nèi)容陶珠,當進入具體的某個業(yè)務(wù)模塊時挟裂,動態(tài)加載業(yè)務(wù)模塊jsbudle。動態(tài)加載方法是enqueueApplicationScript揍诽,參考尾部鏈接
自建熱更新
rn具有內(nèi)置包以及存儲在沙盒cache中的網(wǎng)絡(luò)下載包话瞧。優(yōu)先使用cache中的熱文件,若cache中沒有需要的文件寝姿,則將內(nèi)置包拷貝到cache中交排。
每次打開app時從服務(wù)器拉取所有模塊的配置表,該接口需要傳的參數(shù)是一個數(shù)組饵筑,內(nèi)部表明各個模塊的當前版本號埃篓,服務(wù)器拿著版本號做對比判斷哪些模塊需要更新「剩客戶端對需要更新的模塊一一下載架专,然后覆蓋到cache中。若某個模塊需要回滾玄帕,則客戶端會刪除該模塊在cache中的文件部脚。
原理:http://www.reibang.com/p/203b91a77174
RN內(nèi)置包無效問題:
因為每次都是從cache目錄讀取js文件,所以即使APP更新后裤纹,其內(nèi)置的js包也是無效的委刘,也即APP更新后首次打開APP還是看到以前舊的RN頁面,只有等線上的RN下載完畢鹰椒,更新cache目錄下的js包锡移,打開APP才能看到最新的RN版本。
此外還有一個隱藏的bug漆际,如新版本RN包中新增一個頁面A淆珊,需要在新版本APP中直接跳到A頁面,那么首次更新APP時從原生跳轉(zhuǎn)到A頁面時會crash奸汇,因為此時APP加載的還是cache目錄下舊的js包施符,并沒有A頁面,只有等線上js包下載完成覆蓋cache才會正常
解決:存儲當前內(nèi)置的各個模塊js文件的md5值擂找,一旦發(fā)現(xiàn)APP有更新戳吝,則讀取最新的內(nèi)置js文件md5,跟上次保存的做對比婴洼。若發(fā)現(xiàn)不一樣骨坑,則說明有更新內(nèi)置包,拷貝內(nèi)置包到cache目錄中覆蓋該模塊,使內(nèi)置js包即使更新欢唾。
RN實現(xiàn)圓環(huán)漸變色
畫出同一中心點兩段圓弧且警,例如100半徑和98半徑的,然后將其path封閉相連礁遣,則得到一個寬度為2的弧形矩形斑芜,利用Shape的fill可以填充系統(tǒng)的漸變色LinearGradient而實現(xiàn)圓環(huán)漸變色。但是漸變色不支持安卓
因為ART中的LinearGradient在安卓上無效祟霍,漸變色可使用三方框架杏头,使用react-native-linear-gradient原生渲染,則可如下實現(xiàn)沸呐。同一個中點畫一個帶漸變色的100圓餅醇王,和一個純色的98的圓餅,則得到一個寬度為2的漸變色圓環(huán)崭添。這種圓環(huán)只能從一側(cè)漸變色到另外一側(cè)寓娩,若想優(yōu)化可以采用多個漸變色圓餅拼裝,實現(xiàn)隨著圓弧的漸變色呼渣。
再得到的漸變色圓環(huán)上面棘伴,采用ART.Shape覆蓋住一段均勻顏色的圓弧,比如180度圓弧屁置,則得到了進度為50%的漸變色圓弧焊夸。
Shape的d屬性path繪制舉例如下:
// move: 100,100, 最初的定位點// arc: -20,20, 弧線的終點,是相對上面的100蓝角,100的相對偏移點// arc:100阱穗,0,true帅容,100是這段圓弧的半徑颇象,0沒發(fā)現(xiàn)有什么用伍伤,別設(shè)置太大太小即可并徘。true控制圓弧的方向let path = new Path().moveTo(100,100).arc(-20,20,100,0,true);
背景: 原生控制器,RN(0.5版)頁面作為視圖扰魂,視圖只有一個ScrollView麦乞,內(nèi)部多個Text撐開使ScrollView能上下滑動的頁面。
現(xiàn)象:某些安卓手機push進該頁面時經(jīng)常出現(xiàn)無法滑動現(xiàn)象劝评,但是用手機連上電腦wifi調(diào)試則一切正常姐直,打包后異常。
代碼本身肯定沒有問題蒋畜,在ios手機和多款安卓上均運行正常声畏,發(fā)現(xiàn)有vivo7.1,錘子8.1有上述異常
猜測代碼某些格式在這種手機上不支持,多方修改代碼插龄,打包愿棋,測試,發(fā)現(xiàn)當ScrollView內(nèi)部只用兩個Text包裹大量文字時正常均牢,一旦超過4個Text包裹這些文字則容易出現(xiàn)異常糠雨,不是代碼問題,猜測是RN的一個bug
原因猜測(瞎猜):push時主線程在做動畫徘跪,同時js線程讀取js代碼提交到主線程做渲染甘邀,若ScrollView內(nèi)部有大量Text文本,因渲染文本很耗費資源垮庐,此時主線程任務(wù)量太大導致某些異常出現(xiàn)松邪,如Text文本高度計算延后,導致ScrollView沒有被撐開無法滑動哨查。手機連上電腦調(diào)試時测摔,因為是debug模式,js線程執(zhí)行緩慢解恰,當js內(nèi)容提交給主線程渲染時push動畫已完成锋八,正常。
解決:使用定時器將頁面渲染延后執(zhí)行,具體就是
componentDidMount() { setTimeout(() => { this.setState({ flag: true }) },100)}
render() { if (!this.state.flag) return null; return <ScrollView>}
flatlist優(yōu)化:
1护盈、getItemLayout設(shè)置挟纱,避免渲染cell時計算單元行高度
2、cell使用PureComponent腐宋,避免每次刷新所有cell都刷新了紊服,局部刷新使用shouldComponentUpdate調(diào)節(jié)
3、keyExtractor胸竞,F(xiàn)latList的原理是往一個ScrollView依次存放所有的cell組件作為子組件欺嗤,兄弟組件之間需要使用一個唯一的key來標記自身,應(yīng)該唯一卫枝,若使用索引作為keyExtractor煎饼,要保證cell不會動態(tài)刪除,移動等校赤,否則keyExtractor會重復吆玖,性能降低
RN原理:
http://szuwest.github.io/react-nativekuang-jia-yuan-ma-xue-xi-iosxia.html
http://blog.cnbang.net/tech/2698/
RN幀動畫
采用定時器不斷循環(huán)setState更改Image的source實現(xiàn)幀動畫,安卓上面會出現(xiàn)圖片閃爍現(xiàn)象马篮。目測是圖片刷新時安卓會先清空圖片內(nèi)容沾乘,再加載圖片并將新的圖片渲染出來,這中間存在一個間隔時間浑测,期間圖片內(nèi)容為空翅阵,導致圖片先白一下(圖片背景色)再出現(xiàn)圖片內(nèi)容的閃爍現(xiàn)象
通過測試,發(fā)現(xiàn)當幀動畫的圖片數(shù)量較少,圖片尺寸較小時掷匠,閃爍現(xiàn)象只會循環(huán)一輪读慎,下一輪幀動畫時就會正常。推測是因為圖片較少時槐雾,第一輪幀動畫將所有的圖片緩存在內(nèi)存中夭委,后續(xù)圖片直接從內(nèi)存加載速度很快從而沒有出現(xiàn)閃爍現(xiàn)象。圖片較多時幀動畫會一直閃爍募强。
解決:
1株灸、使用GIF,缺陷:gif較大時擎值,如2M慌烧,則首次初始化gif時會出現(xiàn)明顯卡頓,因為gif初始化解壓消耗大量線程資源
2鸠儿、在目標Image后面再放一張Image屹蚊,該Image也使用setState同步實現(xiàn)幀動畫,但是圖片的索引-1进每,這樣汹粤,當前面那個Image刷新時看到的是后面那個Image,也就是上一幀的圖片田晚,閃爍消除嘱兼。為保險起見,背景采用首幀圖片贤徒,這樣即使閃爍也肉眼難辨
幀動畫時存在大量setState操作芹壕,性能不佳,采用setNativeProps會好很多接奈。