React Native是如今移動開發新的可選方案,也帶來了原屬於Web領域的React的優秀開發特性。另外一方面,React Native的技術棧一經掌握,能夠用於iOS、Android及Windows(見此)多個平臺,即所說的「learn once, write anywhere」。html
如何使用React Native?參照官方指南,你會發現官方告訴你的是:請用react-native init
命令來建立一個React Native項目。這個項目的根目錄結構是這樣:node
可是,以Android爲例,一個普通原生項目的根目錄結構倒是這樣(Android Studio 2.1.2):react
能夠看到,Android原生項目(上圖的Drill
根目錄)平級於生成的React Native項目的android
目錄。那麼,若是一直以來都是Android原生開發,如今想要引入React Native,考慮部分頁面用React Native實現,應該如何作呢?android
這就是React Native植入原生應用的問題。顯然,react-native init
命令生成的項目在結構上不太相符,它的出發點更像是「徹底用React Native作一個多平臺應用」,但咱們可能須要的是「一個原生應用但有部份內容是用React Native作的」。ios
在本文的時間點,React Native的最新版是0.27。官方對此已給出植入原生Android應用的指南,但它不夠準確,也缺乏一些細節。所以,本文將提供一個React Native植入原生Android應用的更詳細一點的流程。git
若是你想了解iOS版的,能夠閱讀這篇文章。github
這篇流程是windows及Android Studio,若是你已是一個Android Studio原生應用開發者,以及Node.js用戶,那麼所需的環境你基本已經有了。詳情請參考windows環境搭建文字教程以及開始使用React Native,什麼都沒有也不要緊,正好從頭搭建。npm
此外,Android模擬器使用了Genymotion,註冊後就能夠供我的使用,會比官方模擬器性能要好一些。json
讓咱們從一個全新的Android原生應用開始。windows
用Android Studio建立一個新項目,注意Minimum SDK應設置爲API 16及以上(React Native要求Android4.1以上的環境):
到Android原生項目的根目錄(也能夠新建一個目錄,但根目錄比較經常使用)新建一個文件package.json
,內容以下(這裏起名爲react-native-module
):
{ "name": "react-native-module", "version": "0.0.1", "private": true, "scripts": { "start": "node node_modules/react-native/local-cli/cli.js start" }, "dependencies": { "react": "^15.1.0", "react-native": "^0.27.2" } }
下面的dependencies
的內容要如何得知呢?答案是參考react-native init
生成的項目,畢竟版本號是會不斷更新的。若是你已經init
生成過項目,能夠運行react-native upgrade
更新後再參考。
而後,在這個package.json
的所在位置,執行:
npm install
安裝好所需的npm組件。
一樣在根目錄,增長一個文件index.android.js
,這是React Native開發的具體內容,是任意的,這裏給一個簡單的例子:
import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View } from 'react-native'; class App extends Component { render() { return ( <View style={styles.container}> <Text style={styles.note}> acgtofe.com with react native </Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, note: { fontSize: 20 } }); AppRegistry.registerComponent('react-native-module', () => App);
注意上面代碼最後的react-native-module
這個名字比較重要,能夠自定,但後面還會在其餘地方用到,須要保持一致。
回到Android Studio,到app
的build.gradle
文件(module級別的gradle)裏添加依賴:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' compile "com.facebook.react:react-native:0.27.2" }
最後一行的react-native
就是咱們新增的,注意這裏的版本號要和package.json
裏的一致。
運行一次Gradle Sync,你必然會獲得這個錯誤:
這是由於Android項目默認的依賴包的源jcenter()
並不包含最新版的React Native(它只到0.20.1
)。新版的React Native都只在npm裏發佈,所以你須要增長一下依賴包的源,到根目錄的build.gradle
文件(project級別的gradle)內增長如下內容(從官方的這句註釋也能夠了解到這一點):
allprojects { repositories { jcenter() maven { // All of React Native (JS, Android binaries) is installed from npm url "$projectDir/../node_modules/react-native/android" } } }
這裏的url
路徑,將取決於你放置node_modules
的位置(你能夠根據須要選擇放置在其餘地方)。以上是node_modules
位於根目錄時的url
路徑,把它改成"$rootDir/node_modules/react-native/android"
也是能夠的,它們等效。如何知道這個路徑寫對了呢?反覆試就能夠了,若是路徑不對,Gradle Sync的時候必定會提示你前面的錯誤。
你可能在不少別的地方看到的都是這樣的寫法:
compile "com.facebook.react:react-native:+"
不太建議這樣作,由於沒有明確的版本號,你沒法讓系統幫你判斷前面的url
路徑寫的是否正確。若是寫錯,Android將使用發佈在jcenter()
的舊版React Native,而這將引起其餘錯誤(見後文)。
新建一個繼承自ReactActivity
的activity(這裏起名爲LiveActivity
),Android Studio會提醒你必須實現3個方法,通常寫成這樣:
public class LiveActivity extends ReactActivity { @Override protected String getMainComponentName() { return "react-native-module"; } @Override protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage() ); } }
getMainComponentName()
的字符串返回值,必須和前面的index.android.js
內的組件名一致。
getUseDeveloperSupport()
是一個邏輯返回值,表示是否啓用開發者模式。這裏寫BuildConfig.DEBUG
就能夠自動根據gradle構建的類型(debug或release)來決定。
getPackages()
是模塊列表,通常像上面代碼這樣就能夠。若是你須要在JavaScript裏調用原生Java模塊,就要把它們添加到這裏,具體能夠參考這篇文章。
到Android清單文件AndroidManifest.xml
添加如下內容(省略了無關部分):
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.acgtofe.drill"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <application ... > ... <activity android:name=".LiveActivity" /> <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> </application> </manifest>
前面的權限都是React Native開發環境須要用到的。後面的LiveActivity
是剛纔的React Native運行界面,DevSettingsActivity
則是如下這個Dev Settings
的界面:
它也是開發版所必需的。
到package.json
的位置,打開命令行,運行packager server:
react-native start
也能夠用npm start
。啓動後的狀態看起來像這樣:
這是最後一步了。build這個Android項目,安裝到模擬器裏,而後打開應用,切換到LiveActivity
界面(用按鈕跳轉,或者直接設置爲啓動界面均可以),這時候應該只看到一片空白。
按ctrl
+ m
(這是Genymotion的用法,事實上,這是Android的Menu鍵,如今的實體設備基本沒有這個鍵,但搖一搖能夠觸發)開啓調試菜單,選擇Dev Settings
,打開前面貼過圖的DevSettingsActivity
,設置Debug server host & port for device
爲本機ip地址(命令行內ipconfig
查看)。最後,回到LiveActivity
,開啓調試菜單選擇Reload JS
,等待一下子,若是你看到了像下圖這樣的界面:
就說明完成了!對應的,packager server裏應該能夠看到每一次請求的記錄:
接下來,你就能夠開始React Native的開發了,改動保存後,從新Reload JS
,就能夠看到新的效果。
建議使用Android 5.0+的設備(包括模擬器),它們支持直接USB傳輸packager server返回的那個bundle js文件。若是是Android 5.0+,能夠USB鏈接電腦後(若是是模擬器,那就等於已經鏈接)運行如下命令:
adb reverse tcp:8081 tcp:8081
而後就能夠省略掉前面流程裏設置本機ip地址那一步,直接Reload JS
。注意設備須要開啓USB調試(模擬器不用),並且電腦同時只鏈接一個設備。
相對於前面設置本機ip地址的方式,這幫你免去了同一WiFi環境、代理等麻煩。
雖然流程看起來輕鬆愉快,但並不怎麼能一次成功。下面是我在流程中碰到過的一些問題及其記錄,能夠用做參考。
錯誤提示以下:
參照github上的issue,這個錯誤的引起緣由是packager server的React Native版本和Android應用內的不一致。好比應用內的gradle依賴寫的是compile "com.facebook.react:react-native:+"
但url
路徑寫得不對,結果用的就是jcenter()
裏的0.20.1
的舊版,就會有這個問題。
所以,建議用compile "com.facebook.react:react-native:0.27.2"
這樣的寫法,並檢查版本號是否和package.json
裏的一致。
這是說index.android.js
文件不存在的錯誤。但我遇見的是文件就在那,也出這個錯誤。
這多是由不正確的緩存引發,個人解決方法:關閉server,刪除index.android.js
,而後重啓server,刷新,獲得真正的404,而後還原index.android.js
,再刷新即解決。
先按照Try the following to fix the issue:
下給出的解決方法依次檢查和嘗試。若是仍不能解決,刪除掉node_modules
目錄,從新npm install
,而後重開server。
windows下刪除node_modules
目錄可能有路徑過長的問題,推薦用rimraf來刪除。
這個問題須要具體看server的輸出,我這裏的錯誤信息是:Error: Unable to find file with path: ......polyfills\prelude_dev.js
。相似前面的沒法鏈接server,我也是刪除node_modules
後從新安裝獲得解決。
流程中可能碰到的問題能夠分爲兩類,Android應用(client)和server。若是看到錯誤,打開瀏覽器訪問http://localhost:8081/index.android.bundle?platform=android
,若是能看到輸出的JavaScript代碼,那說明server是比較正常的,更多是Android應用的問題。反過來,若是瀏覽器裏一樣看到錯誤信息,那更可能就是server的問題。
你可能在開始用React Native的過程當中據說了Flow和Nuclide,它們分別是JavaScript類型檢查工具及React Native的推薦IDE。
但請注意,在本文的時間點,它們尚未windows版。我是用Atom來開發React Native的。
React Native的開發版是須要有一個packager server來隨時發送更新後的bundle js文件的。但若是要獲得真正簽名的正式版(app-release
),你須要把bundle js文件保存到Android應用的資源目錄內。這樣,正式版再也不須要server支持,能夠獨立運行。
參照官方的發行APK包指南,你只須要這樣幾步:
app/src/main/assets
。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/
Build
→Generate Signed APK...
,生成正式版的apk。官方有提到使用react.gradle
文件的方法,但我以爲像上面這樣不用它更簡單。
看起來正式版把bundle js文件保存到了apk內,這好像就丟失了React Native的即時更新?對的,但仍然有辦法實現它,你能夠看看React-Native-Remote-Update,這個項目已通過時了,但裏面貼出的原理很值得參考。
如今,你能夠用react-native-auto-updater來幫助你實現React Native的即時更新。
我在寫本文的過程當中參考了下面三個資料集合,以爲很是棒,在此也貼出來:
React Native的Android版本是去年9月(2015.9.15)才推出,此前只有iOS版。相對來講,Android的相關教程要比iOS少不少。因 此,我以爲有這樣一份windows + React Native for Android的組合流程會頗有幫助。
來嘗試新的移動開發方案吧!