TAT.tennylv React Native Android 踩坑之旅
In 未分類 on 2015年10月25日 by view: 32,140
39

前言

Facebook  在 2015.9.15 發布了 React Native for Android,把 JavaScript  開發技術擴展到了移動 Android 平臺?;?React 的 React Native  讓前端開發者使用 JavaScript  和 React  編寫應用,利用相同的核心代碼就可以創建  基于 Web,iOS  和 Android  平臺的原生應用。在 React Native for Android 出來之后,本人花了些時間從環境搭建到做出幾個 demo,從體驗來看都挺流暢,具體將此間遇到和問題和具體的新的體會,向大家分享一下。

 

原理簡介

 

1 React Native for Android 和 for IOS 的基本原理是一致的,通過 android 的 JavaScriptCore 來異步解析 js 代碼 (jsbundle 文件),然后根據引入的支持和配置,渲染成原生 native 組件。

復用 React 系統,也減少了一定學習和開發成本,更重要的是利用了 React 里面的分層和 diff 機制。js 層傳給 Native 層的是一個 diff 后的 json,然后由 Native 將這個數據映射成真正的布局視圖。

 

 

環境搭建

環境搭建的話,在網上也找到過很多教程,但是還是推薦還是去看官方文檔 https://facebook.github.io/react-native/docs/android-setup.html#content,在搭建的過程中可能會遇到一些問題。

 

1 在 React Native for Android 剛出來的時候,官方稱是不支持在 windows 系統上安裝的,只有在 mac 上才可以使用,但是最新版的 React Native for Android 已經支持在 windows 上使用,更新 React Native 的方法:下載最新版的 react-native-cli 即 npm install -g react-native-cli,并且保證 node 是最新版的即>4.0。

 

2 在執行 react-native init AwesomeProject 命令時,由于這個命令會去下載一些 node module 所以要根據自己的實際情況設置 npm 的代理和鏡像,本人就曾經因為這個問題搞了很久才成功,可以安裝 nrm(npm install -g nrm) 來便捷設置 npm 的代理和鏡像,其次是執行這個命令必須現在機器上裝有 git,并且設置好 git 的環境變量,另外這個命令需要等待一些時間,不要提前取消。

 

3 在調用 react-native run-android 的命令時,有時會報出找不到 android-sdk 環境變量的錯誤(自己確實已經正確設置環境變量)提示例如

的錯誤時,可以單獨在項目根目錄下,也就是 AwesomeProject/新建一個 local.propertites 文件,添加 sdk.dir=你的 android 的 sdk 目錄,然后在運行 react-native run-android。

 

4 在調用 react-native run-android 命令時,其實這個命令就是執行的兩部分操作一是是構建你的 android 項目并生成 apk,另外一個是打開 react-native 的 package 管理工具同時編譯你的 js 文件,其實可以在項目根目錄的 package.json 下找到

其實是執行了另外一條命令 node node_modules\react-native\packager\packager.js 來打開 package 的管理工具,有些可能沒打開一個新的命令行窗口,自己手動執行這條 node 命令也是可以的。在這條命令執行完之后,node 就會開啟一個服務,同時把 js 文件編譯成 jsbundle 文件,我們可以通過 http://localhost:8081/index.android.bundle?platform=android 來訪問到這個文件,可以簡單將這個文件理解成一個 html,android 就是通過解析這個 html 來達到渲染的目的,將該文件部署到 CDN 可供 android app 從網絡獲取,即可實現不用發版本讓 app 的 UI 隨時更新,并且可獲得接近 native 的體驗,這也是 react-native 最吸引開發者的亮點之一。

 

5 用 react native 命令生成的 android 項目是基于 gradle 構建和部署的 (不清楚 gradle 的可以 google),這個以前一些搞用 eclipse 來 android 開發的可能不太一樣,gradle 是用在 google 主推的一款 android 開發 IDE,android statio 里面默認的項目構建方式,所以我們的項目里會看到一些 build.gradle 的文件,這些都是配置文件。

 

6 我們在根據教程搭環境時會碰到需要安裝 android 模擬器的步驟,這個步驟會提示你安裝一個 HAXM 的東西可以看到這個安裝不是必須的,其實這個是一個 android 模擬器的加速程序,按了這個你的模擬器可能會跑的更快,但是在安裝這個程序時,會遇到的錯誤是由于 CPU 的虛擬化未開啟,需要重新開機在 bios 上設置一下,具體怎么設置,可以自行 google。

 

7 react-native android 在本地調試開發時,你只需要修改 js 文件,然后刷新你的項目,所以在創建 android 模擬器時要記得選擇帶有 android 鍵盤的模擬器,這樣才能在模擬器上刷新你的更改。

 

與現有的 android 項目集成

1 想要在現有的 android 項目里添加 react native 支持,你必須要先創建一個基于 gradle 的 android 項目,推薦使用 android studio 來創建項目,要記得創建的項目要高于 Android 4.1 (API 16)的 android 項目。

 

2 用 android studio 創建一個項目 并且能跑起來,這段教程可以直接去網上少,一般配置無誤的情況下,很容易跑出一個 android helloword 來,你只需要保持之前的 node package 服務開啟,程序依然會去尋找 http://localhost:8081/index.android.bundle?platform=android 這個文件的。只是你的 android 模擬器是通過 android studio 來管理了。


3 在按照 http://facebook.github.io/react-native/docs/embedded-app-android.html#content 配置你的結合項目時,還要注意在 AndroidManifest.xml 文件里面添加<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> 這樣才能開啟調試模式。

 

4 對于 android 項目來說,react native 的支持也是就在 Activity 里面創建了一個 ReactRootView,對這不是 webview,然后將 Activity 的其他事件生命周期等等都交給 react manager 來管理,所以對于 react native 的 android 頁面,就可以簡單理解成一個 activety 里面套一個 reactrootview 這個 view 去加載并 jsbundle 文件,渲染出原生 native 的 ui 組件。

 

遠程加載 jsbundle 文件

1 目前在 react android 的官方文檔里面,還沒有找到如何遠程加載 jsbundle 文件的地方,只能是事先把 jsbundle 文件放在 assets 目錄下面,一起打包成 apk,也就是 release apk 文件,可以參考 https://facebook.github.io/react-native/docs/signed-apk-android.html。

 

樣式和布局

1 react native 的代碼和 react 基本一樣,組件的生命周期,jsx 語法都支持,只是在使用 jsx 時要經常調用官方提供的組件。

2 react native 里面的樣式大部分是可以利用 css 語法來寫的,只有文檔里面有的屬性才能用,不是所有的 css 都可以在 react native 里面用的,采用 obj 的形式將 css 屬性橫杠后面的第一個字母大寫即可。

react 的寬高度不支持百分比,設置寬高度時不需要帶單位,在 react native 里面默認使用 pt 為單位,注意在給 image 設置大小時要根據 PixelRatio 設置合適的值。

4 使用 dimensions.get("window") 可以獲取到當前 viewport 的大小,這個值可能會根據屏幕橫豎來動態改變。

5 react native 里面沒有 float 的用法,是根據 flex 來布局,alignItems 和 justifyContent 分別決定子元素的布局,而 flexDirection 決定子元素的排列方式垂直還是水平,flex:number 決定子元素所占的比例,alignSelf 決定元素本事的布局,子 view 會默認根據父 view 來 absolute,這里有個技巧,如果想讓子 view 實現 100% 的效果可以設置 left:0 ,right :0, 同理 height 可以用 top:0,bottom:0。

6 使用 text 的 numberOfLines 可以實現文本截取省略號,即 css 的 text-overflow 屬性。

7 默認情況下如果元素超過了父元素,是不可以滾動的,必須在外部套一個<ScrollView> 才可以。

8 react native 里面沒有 z-index 的概念,是根據 jsx 語法里面定義組件的順序來實現的,后寫的組件會覆蓋在先寫的組件上。

 

總結

1 react native android 和 ios 相比,由于出現的還比較晚一些功能還沒有非常完善,所以一些文檔里面沒有寫的東西還需要自己摸索, 例如 android 上使用 borderTopLeftRadius 沒起作用。

2 react native android 在性能上要比 web 來的好很多,畢竟渲染出來的是原生的組件,尤其是在一些低端 android 機型上,但是跟真正的 native 相比還是要遜色一些,但是 react native 的優勢在于一套代碼可以跨平臺復用,而且可以通過更新遠端 JS,直接更新 app,并且對于前端工程師來說用 js 的語法寫 native 的組件也并沒有很難。

本人用 react native android 做出的 demo,大家可以體驗一下。http://7jpp2v.com1.z0.glb.clouddn.com/app-release.apk

 

不斷跟新中

 

參考資料:http://www.nihaoshijie.com.cn/index.php/archives/550

 

 

原創文章轉載請注明:

轉載自AlloyTeam:http://www.5418yb.com/2015/10/react-native-android-steps-on-tour/

  1. Dai Software 2019 年 1 月 3 日

    Hey, very nice site. I came across this on Google, and I am stoked that I did. I will definitely be coming back here more often. Wish I could add to the conversation and bring a bit more to the table, but am just taking in as much info as I can at the moment. Thanks for sharing.

    React Native Development Company

  2. 小菜鳥 2017 年 5 月 16 日

    啟動崩潰:
    E/AndroidRuntime( 9811): Process: com.example.tennylv.myfff, PID: 9811
    E/AndroidRuntime( 9811): java.lang.UnsatisfiedLinkError: could find DSO to load: libreactnativejni.so
    E/AndroidRuntime( 9811): at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:213)
    E/AndroidRuntime( 9811): at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:178)
    E/AndroidRuntime( 9811): at com.facebook.react.bridge.JSCJavaScriptExecutor.(JSCJavaScriptExecutor.java:19)
    E/AndroidRuntime( 9811): at com.facebook.react.ReactInstanceManager.createReactContextInBackground(ReactInstanceManager.java:246)
    E/AndroidRuntime( 9811): at com.facebook.react.ReactInstanceManager.attachMeasuredRootView(ReactInstanceManager.java:367)
    E/AndroidRuntime( 9811): at com.facebook.react.ReactRootView$1.run(ReactRootView.java:105)
    E/AndroidRuntime( 9811): at android.os.Handler.handleCallback(Handler.java:739)
    E/AndroidRuntime( 9811): at android.os.Handler.dispatchMessage(Handler.java:95)
    E/AndroidRuntime( 9811): at android.os.Looper.loop(Looper.java:135)
    E/AndroidRuntime( 9811): at android.app.ActivityThread.main(ActivityThread.java:5418)
    E/AndroidRuntime( 9811): at java.lang.reflect.Method.invoke(Native Method)
    E/AndroidRuntime( 9811): at java.lang.reflect.Method.invoke(Method.java:372)
    E/AndroidRuntime( 9811): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1037)
    E/AndroidRuntime( 9811): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)

  3. 火星前哨站2 2017 年 1 月 11 日

    小米 5S,MIUI8 啟動閃退

發表評論