本篇文章主要包括兩方面,如何從0開始把RN(react-native)項目整合進入現有Android項目,以及我們做的第一個RN的上線項目遇到的一些坑。 初次做RN項目,我們選擇做了一個邏輯相對簡單的轉轉app內部的幫助中心項目。整個項目有4個頁面用的RN,其他頁面走的是native提供的統跳協議, ...
本篇文章主要包括兩方面,如何從0開始把RN(react-native)項目整合進入現有Android項目,以及我們做的第一個RN的上線項目遇到的一些坑。
初次做RN項目,我們選擇做了一個邏輯相對簡單的轉轉app內部的幫助中心項目。整個項目有4個頁面用的RN,其他頁面走的是native提供的統跳協議,跳轉到對應的native頁面或者是H5頁面。
整合RN到android項目中
react-native cli提供的init指令,可以幫助我們創建一個RN的工程,但是很多場景下RN都是移植進入原生android或者iOS中。例如應該如何實現,在Android頁面,點擊一個按鈕進入RN頁面呢?
下麵是具體的實現過程。
1、新建一個Android項目
註意Minimum SDK選擇API23以上,一路next後finish。
2、添加JS
打開studio的Terminal視窗,輸入如下命令:
npm init
會讓你輸入一些初始化package.json 的配置信息,例如:
按照提示輸入就行了。
這一步完成之後,在項目的根目錄下就會生成package.json這個文件,下一步輸入:
npm install [email protected] - -save
npm install react-native@^0.44.0 - -save
註意,一定優先安裝react哦
大約一兩分鐘的樣子(如果卡到這裡了,看看安裝時是不是忘了配置鏡像),完成之後你的根目錄下會多了一個node_modules的文件夾,裡面存放了下載好的React 和React Native。這裡有童鞋可能會質疑為什麼不把react和react-native的依賴直接寫入package.json中,然後直接npm install,如果這麼做的化,npm run start啟動的時候會報如下的錯誤:
接下來把如下命令粘貼到package.json 文件下 scripts 標簽中
“start”: “node node_modules/react-native/local-cli/cli.js start”
下一步,在根目錄下創建index.android.js文件並把如下代碼粘貼到其中:
代碼很簡單,居中顯示一個HelloWorld。
3、項目配置(Android)
用android studio打開工程,修改android根目錄下Gradle Scripts的build.gradle(Module:app)文件添加如下內容,註意下麵appcompat-v7版本為25.2.0,而且我把dependencies中test相關的依賴移除掉了,避免不必要的bug。
在build.gradle(Project:***)中添加依賴
繼續下一步,在AndroidManifest.xml中添加網路訪問許可權
4、創建Activity
以下幾步不要安裝官網的去做,官網的步驟太麻煩,而且很久沒有更新了。
1.新建一個Activity,讓其繼承ReactActivity,並重寫getMainComponentName(),返回我們在index.android.js中註冊的HelloWorld這個組件。
別忘了把這個activity加入app/manifests/AndroidManifest.xml文件中
2.自定義一個Application,繼承ReactApplication ,編寫以下代碼:
記得在AndroidManifest.xml中引用
android:name=”.App”
3.在目錄res/layout中增加activity_main.xml文件,內容如下:
在MainActivity中通過按鈕啟動我們的ReactNativeActivity
4.app/src/main下新建assets文件夾
運行如下命令
react-native start
然後直接在android studio工程中,點擊上方工具欄的“run”按鈕,應該就可以了。
如果卡在了這一步:
沒關係,用資源管理器打開你工程的根目錄,在此目錄下重新運行一個命令行併在其中輸入如下命令
react-native bundle - -platform android - -dev false - -entry-file index.android.js - -bundle-output app/src/main/assets/index.android.bundle - -assets-dest app/src/main/res/
完成之後assets目錄下會生成以下兩個文件
確認一下react native service處於運行狀態,然後正常運行你的APP,點擊start,如果出現
恭喜你!你已經成功入坑,但是,實際項目中並不是這麼簡單!
項目實戰踩坑
1.技術棧
es6 + redux + react-redux + redux-thunk + react-navigation
2.項目心得
這個項目踩坑最多的地方還是在react-navigation的使用上:
1、同一頁面參數不同,多次回退始終進入同一個頁面:
比如詳情頁頁面a/cateId/xy,當傳入不同cateId參數“cd”跳轉到同一詳情頁a/cateId/cd的時候,頁面是正常改變的,但是回退的時候,第一次是回到a/cateId/cd,再次回退還是回到a/cateId/cd。不會觸發頁面render。
stackNavigator導航管理的頁面,在切換的時候,不是按照堆棧的push,pop形式,而是通過移動指針到對應的頁面,同時標記此頁面為激活狀態。
解決辦法是通過componentWillReceiveProps,shouldComponentUpdate以及componentDidUpdate,當nextProps中的params.cateId和當前的params.cateId不同的時候,觸發頁面的render。
2、實現手勢swipe向右滑動後退功能:
官方文檔介紹,react-navigation在根組件的navigationOptions設置中添加gesturesEnabled: true,就可以實現滑動切換切換頁面的需求,但是在真機上測試不生效。
通過讀源碼瞭解到,react-navigation內部是通過引入RN的PanResponder手勢識別系統來實現滑動的機制,只有在onMoveShouldSetPanResponder返回true的時候,才能執行接下來的手勢動作。具體執行方法如下:
因為上述代碼中的 GESTURE_RESPONSE_DISTANCE_HORIZONTAL 過小,導致始終return false,把這個值從20改到60就可以了。
3、實現頁面跳轉動畫效果
StackNavigator(RouteConfigs, StackNavigatorConfig);
在第二個參數StackNavigatorConfig的配置中,可以傳入mode: ‘card’,這個參數會在native端獲取預設的滑動效果,iOS端預設的是左右切換的效果,但是android端預設的是上下切換效果。為了實現統一的過場效果。
幸好react-navigation提供了一個transitionConfig介面,可以實現定製化滑屏效果。不知道該如何定製麽?沒有關係,源碼中已經在iOS端幫我們實現,稍微修改一下代碼就可以了。
FlatList問題:
1.ListHeaderComponent,ListFooterComponent
當FlatList有併列的組件的時候,會出現,其他併列的組件位置是固定的(類似於css中的position fixed),頁面只有FlatList區域是可以滾動的,為了實現這個頁面整體是可以滾動的,需要把FlatList上面的組件加入FlatList的ListHeaderComponent屬性中,同時把其下麵的組件加入到ListFooterComponent中。
2.通過利用getItemLayout,把高度提前設定好,可以較少一次RN計算高度的render。
圖片問題:
1.RN中的圖片有兩種來源:native內部圖片,cdn的圖片。
native內部圖片,直接可以通過require圖片名字取到,一定不要加.png等尾碼。
例如:
當然我們可以通過在打包的時候把通過相對路徑引入的內部圖片,
例如:
通過配置–asset-dest打包進入native原生目錄res中,這時候要註意,打出來的RN的bundle,只有放入android的assets文件夾下才能根據相對路徑取到這些存放在res目錄中的圖片。
cdn的圖片,只有指定圖片的寬高才能夠顯示出來。
與native交互的處理
-
NativeModules:native暴露出來的模塊,可以通過NativeModules對象取到。
-
有些場景需要native直接傳遞某些參數到RN端,iOS可以通過調用initWithBundleURL,在initialProperties參數傳參,android通過getLaunchOptions把參數寫入返回的bundle中。在RN工程的根文件(例如app.js),通過this.props.key(key是屬性名字)直接取到。
如果你喜歡我們的文章,關註我們的公眾號和我們互動吧。