核心概念
如果你正準(zhǔn)備從頭開始制作一個(gè)新的應(yīng)用棍厂,那么React Native會(huì)是個(gè)非常好的選擇颗味。但如果你只想給現(xiàn)有的原生應(yīng)用中添加一兩個(gè)視圖或是業(yè)務(wù)流程,React Native也同樣不在話下牺弹。只需簡(jiǎn)單幾步浦马,你就可以給原有應(yīng)用加上新的基于React Native的特性、畫面和視圖等张漂。
把React Native組件植入到Android應(yīng)用中有如下幾個(gè)主要步驟:
- 首先當(dāng)然要了解你要植入的React Native組件晶默。
- 在Android項(xiàng)目根目錄中使用npm來(lái)安裝
react-native
,這樣同時(shí)會(huì)創(chuàng)建一個(gè)node_modules/
的目錄航攒。 - 創(chuàng)建js文件磺陡,編寫React Native組件的js代碼。
- 在
build.gradle
文件中添加com.facebook.react:react-native:+
漠畜,以及一個(gè)指向node_nodules/
目錄中的react-native
預(yù)編譯庫(kù)的maven
路徑币他。 - 創(chuàng)建一個(gè)React Native專屬的
Activity
,在其中再創(chuàng)建ReactRootView
盆驹。 - 啟動(dòng)React Native的Packager服務(wù)圆丹,運(yùn)行應(yīng)用。
- 根據(jù)需要添加更多React Native的組件躯喇。
- 在真機(jī)上運(yùn)行辫封、調(diào)試。
- 打包廉丽。
- 發(fā)布應(yīng)用倦微,升職加薪,走向人生巔峰正压!??
開發(fā)環(huán)境準(zhǔn)備
首先按照開發(fā)環(huán)境搭建教程來(lái)安裝React Native在安卓平臺(tái)上所需的一切依賴軟件(比如npm
)欣福。
在應(yīng)用中添加JS代碼
在項(xiàng)目的根目錄中運(yùn)行:
npm init
npm install --save react react-native
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
- 1.npm init`創(chuàng)建了一個(gè)空的node模塊(過(guò)程需要填寫其實(shí)就是創(chuàng)建了一個(gè)package.json描述文件)。
- 2.npm install`則創(chuàng)建了node_modules目錄并把react和react-native下載到了其中焦履。
- 3.這一步非必需拓劝,可跳過(guò)雏逾,curl命令,其實(shí)質(zhì)是
下載
.flowconfig配置文件郑临,這個(gè)文件用于約束js代碼的寫法栖博。
下面我們打開新創(chuàng)建的package.json
文件,去除:
"test": "echo \"Error: no test specified\" && exit 1"
然后在其scripts
字段中加入:
"start": "node node_modules/react-native/local-cli/cli.js start"
現(xiàn)在你的package.json
內(nèi)容應(yīng)該類似這樣:
{
"name": "myreact",
"version": "1.0.0",
"description": "test",
"main": "index.js",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"author": "AFinalStone",
"license": "ISC",
"dependencies": {
"react": "^15.4.2",
"react-native": "^0.41.2",
"react-native-storage": "^0.2.1"
}
}
示例中的
version
字段沒(méi)有太大意義(除非你要把你的項(xiàng)目發(fā)布到npm倉(cāng)庫(kù))厢洞。scripts
中是用于啟動(dòng)packager服務(wù)的命令仇让。dependencies
中的react和react-native的版本取決于你的具體需求。一般來(lái)說(shuō)我們推薦使用最新版本躺翻。你可以使用npm info react
和npm info react-native
來(lái)查看當(dāng)前的最新版本丧叽。另外,react-native對(duì)react的版本有嚴(yán)格要求公你,高于或低于某個(gè)范圍都不可以踊淳。本文無(wú)法在這里列出所有react native和對(duì)應(yīng)的react版本要求,只能提醒讀者先嘗試執(zhí)行npm install省店,然后注意觀察安裝過(guò)程中的報(bào)錯(cuò)信息嚣崭,例如require react@某.某.某版本, but none was installed
,然后根據(jù)這樣的提示懦傍,執(zhí)行npm i -S react@某.某.某版本
雹舀。
接下來(lái)在項(xiàng)目根目錄中創(chuàng)建index.android.js
文件,然后將下面的代碼復(fù)制粘貼進(jìn)來(lái):
'use strict';
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
class HelloWorld extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.hello}>Congratulations on your success</Text>
</View>
)
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
AppRegistry.registerComponent('myreact', () => HelloWorld);
- 注意粗俱,AppRegistry.registerComponent('myreact', () => HelloWorld)的第一個(gè)參數(shù)要和package.json中的name一致
準(zhǔn)備工作
在你的app中 build.gradle
文件中添加 React Native 依賴:
dependencies {
compile "com.facebook.react:react-native:+" // From node_modules.
}
如果想要指定特定的React Native版本说榆,可以用具體的版本號(hào)替換
+
,當(dāng)然前提是你從npm里下載的是這個(gè)版本 寸认。
在項(xiàng)目的 build.gradle
文件中為 React Native 添加一個(gè) maven 依賴的入口签财,必須寫在 "allprojects" 代碼塊中:
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/node_modules/react-native/android"
}
}
}
確保依賴路徑的正確!以免在 Android Studio 運(yùn)行Gradle同步構(gòu)建時(shí)拋出 “Failed to resolve: com.facebook.react:react-native:0.x.x" 異常偏塞。
接著唱蒸,在 AndroidManifest.xml
清單文件中聲明網(wǎng)絡(luò)權(quán)限:
<uses-permission android:name="android.permission.INTERNET" />
如果需要訪問(wèn) DevSettingsActivity
界面,也需要在 AndroidManifest.xml
中聲明:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
This is only really used in dev mode when reloading JavaScript from the development server, so you can strip this in release builds if you need to.
添加原生代碼
想要通過(guò)原生代碼調(diào)用 React Native 灸叼,就像這樣神汹,我們需要在一個(gè) Activity
中創(chuàng)建一個(gè) ReactRootView
對(duì)象,將它關(guān)聯(lián)一個(gè) React application 并設(shè)為界面的主視圖古今。
如果你想在安卓5.0以下的系統(tǒng)上運(yùn)行屁魏,請(qǐng)用
com.android.support:appcompat
包中的AppCompatActivity
代替Activity
。
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
public class MyReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
// 注意這里的myreact必須對(duì)應(yīng)“index.android.js”中的
// “AppRegistry.registerComponent()”的第一個(gè)參數(shù)
mReactRootView.startReactApplication(mReactInstanceManager, "myreact", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
如果你的項(xiàng)目名字不是叫“myreact”捉腥,則需要將“index.android.js”中的“AppRegistry.registerComponent()”方法中的第一個(gè)參數(shù)替換為對(duì)應(yīng)的名字氓拼。
如果你使用的是 Android Studio , 可以使用Alt + Enter
快捷鍵來(lái)自動(dòng)為MyReactActivity類補(bǔ)上缺失的import語(yǔ)句。注意引入的BuildConfig
應(yīng)該是在你自己的包中,而不是在...facebook...
的包中桃漾。
我們需要把 MyReactActivity
的主題設(shè)定為 Theme.AppCompat.Light.NoActionBar
坏匪,因?yàn)槔锩嬗性S多組件都使用了這一主題。
<activity
android:name=".MyReactActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
現(xiàn)在activity已就緒呈队,可以運(yùn)行一些JavaScript代碼了剥槐。
配置權(quán)限以便開發(fā)中的紅屏錯(cuò)誤能正確顯示,或者你直接把targetSdkVersion設(shè)置為22也行
如果你的應(yīng)用會(huì)運(yùn)行在Android 6.0(API level 23)或更高版本,請(qǐng)確保你在開發(fā)版本中有打開懸浮窗(overlay)
權(quán)限宪摧。If your app is targeting the Android API level 23
or greater, make sure you have the overlay
permission enabled for the development build. You can check it with Settings.canDrawOverlays(this);
. This is required in dev builds because react native development errors must be displayed above all the other windows. Due to the new permissions system introduced in the API level 23, the user needs to approve it. This can be acheived by adding the following code to the Activity file in the onCreate() method. OVERLAY_PERMISSION_REQ_CODE is a field of the class which would be responsible for passing the result back to the Activity.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
}
Finally, the onActivityResult()
method (as shown in the code below) has to be overridden to handle the permission Accepted or Denied cases for consistent UX.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW permission not granted...
}
}
}
}
運(yùn)行你的應(yīng)用
運(yùn)行應(yīng)用首先需要啟動(dòng)開發(fā)服務(wù)器(Packager)。你只需在項(xiàng)目根目錄中執(zhí)行以下命令即可:
npm install
npm start
保持packager的窗口運(yùn)行不要關(guān)閉颅崩,然后像往常一樣編譯運(yùn)行你的Android應(yīng)用(在命令行中執(zhí)行./gradlew installDebug
或是在Android Studio中編譯運(yùn)行)几于。
如果你是使用Android Studio來(lái)編譯運(yùn)行,有可能會(huì)導(dǎo)致packger報(bào)錯(cuò)退出沿后。先把packager服務(wù)窗口關(guān)掉沿彭,然后再使用AndroidStudio編譯運(yùn)行Android應(yīng)用,
這個(gè)時(shí)候只保持在MainActivity頁(yè)面尖滚,然后重新在項(xiàng)目根目錄執(zhí)行npm start命令喉刘,然后操作APP進(jìn)入MyReactActivity的頁(yè)面
編譯執(zhí)行一切順利進(jìn)行之后,在進(jìn)入到MyReactActivity時(shí)應(yīng)該就能立刻從packager中讀取JavaScript代碼并執(zhí)行和顯示:
在Android Studio中打包
你也可以使用Android Studio來(lái)打release包漆弄!其步驟基本和原生應(yīng)用一樣睦裳,只是在每次編譯打包之前需要先執(zhí)行js文件的打包(即生成離線的jsbundle文件,這樣APP進(jìn)入RN編寫的頁(yè)面會(huì)直接調(diào)用本身的JS代碼,不需要去服務(wù)器請(qǐng)求)撼唾。
具體的js打包命令如下:
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
其中--bundle-output后面的兩個(gè)參數(shù)指出assets和res文件夾的具體路徑廉邑,注意把上述命令中的路徑替換為你實(shí)際項(xiàng)目的路徑。如果assets目錄不存在倒谷,需要提前自己創(chuàng)建一個(gè)蛛蒙。
然后在Android Studio中正常生成release版本即可!
打包好的release版本app運(yùn)行在許多X64CPU的手機(jī)上渤愁,打開RN頁(yè)面直接閃退
錯(cuò)誤:
java.lang.UnsatisfiedLinkError: dlopen failed: "xxx/libgnustl_shared.so" is 32-bit instead of 64-bit
解決方案:
1牵祟、在項(xiàng)目的根目錄的 gradle.properties里面添加一行代碼
android.useDeprecatedNdk=true.
2、在project的root目錄下的build.gradle中添加如下代碼抖格。
defaultConfig {
···
ndk{
abiFilters "armeabi-v7a","x86"
}
packagingOptions {
exclude "lib/arm64-v8a/librealm-jni.so"
}
}