核心概念
如果你正準備從頭開始制作一個新的應用,那么React Native會是個非常好的選擇。但如果你只想給現有的原生應用中添加一兩個視圖或是業務流程,React Native也同樣不在話下。只需簡單幾步,你就可以給原有應用加上新的基于React Native的特性、畫面和視圖等。
把React Native組件植入到Android應用中有如下幾個主要步驟:
- 首先當然要了解你要植入的React Native組件。
- 在Android項目根目錄中使用npm來安裝
react-native
,這樣同時會創建一個node_modules/
的目錄。 - 創建js文件,編寫React Native組件的js代碼。
- 在
build.gradle
文件中添加com.facebook.react:react-native:+
,以及一個指向node_nodules/
目錄中的react-native
預編譯庫的maven
路徑。 - 創建一個React Native專屬的
Activity
,在其中再創建ReactRootView
。 - 啟動React Native的Packager服務,運行應用。
- 根據需要添加更多React Native的組件。
- 在真機上運行、調試。
- 打包。
- 發布應用,升職加薪,走向人生巔峰!??
開發環境準備
首先按照開發環境搭建教程來安裝React Native在安卓平臺上所需的一切依賴軟件(比如npm
)。
在應用中添加JS代碼
在項目的根目錄中運行:
npm init
npm install --save react react-native
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
- 1.npm init`創建了一個空的node模塊(過程需要填寫其實就是創建了一個package.json描述文件)。
- 2.npm install`則創建了node_modules目錄并把react和react-native下載到了其中。
- 3.這一步非必需,可跳過,curl命令,其實質是
下載
.flowconfig配置文件,這個文件用于約束js代碼的寫法。
下面我們打開新創建的package.json
文件,去除:
"test": "echo \"Error: no test specified\" && exit 1"
然后在其scripts
字段中加入:
"start": "node node_modules/react-native/local-cli/cli.js start"
現在你的package.json
內容應該類似這樣:
{
"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
字段沒有太大意義(除非你要把你的項目發布到npm倉庫)。scripts
中是用于啟動packager服務的命令。dependencies
中的react和react-native的版本取決于你的具體需求。一般來說我們推薦使用最新版本。你可以使用npm info react
和npm info react-native
來查看當前的最新版本。另外,react-native對react的版本有嚴格要求,高于或低于某個范圍都不可以。本文無法在這里列出所有react native和對應的react版本要求,只能提醒讀者先嘗試執行npm install,然后注意觀察安裝過程中的報錯信息,例如require react@某.某.某版本, but none was installed
,然后根據這樣的提示,執行npm i -S react@某.某.某版本
。
接下來在項目根目錄中創建index.android.js
文件,然后將下面的代碼復制粘貼進來:
'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)的第一個參數要和package.json中的name一致
準備工作
在你的app中 build.gradle
文件中添加 React Native 依賴:
dependencies {
compile "com.facebook.react:react-native:+" // From node_modules.
}
如果想要指定特定的React Native版本,可以用具體的版本號替換
+
,當然前提是你從npm里下載的是這個版本 。
在項目的 build.gradle
文件中為 React Native 添加一個 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 運行Gradle同步構建時拋出 “Failed to resolve: com.facebook.react:react-native:0.x.x" 異常。
接著,在 AndroidManifest.xml
清單文件中聲明網絡權限:
<uses-permission android:name="android.permission.INTERNET" />
如果需要訪問 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.
添加原生代碼
想要通過原生代碼調用 React Native ,就像這樣,我們需要在一個 Activity
中創建一個 ReactRootView
對象,將它關聯一個 React application 并設為界面的主視圖。
如果你想在安卓5.0以下的系統上運行,請用
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必須對應“index.android.js”中的
// “AppRegistry.registerComponent()”的第一個參數
mReactRootView.startReactApplication(mReactInstanceManager, "myreact", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
如果你的項目名字不是叫“myreact”,則需要將“index.android.js”中的“AppRegistry.registerComponent()”方法中的第一個參數替換為對應的名字。
如果你使用的是 Android Studio , 可以使用Alt + Enter
快捷鍵來自動為MyReactActivity類補上缺失的import語句。注意引入的BuildConfig
應該是在你自己的包中,而不是在...facebook...
的包中。
我們需要把 MyReactActivity
的主題設定為 Theme.AppCompat.Light.NoActionBar
,因為里面有許多組件都使用了這一主題。
<activity
android:name=".MyReactActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
現在activity已就緒,可以運行一些JavaScript代碼了。
配置權限以便開發中的紅屏錯誤能正確顯示,或者你直接把targetSdkVersion設置為22也行
如果你的應用會運行在Android 6.0(API level 23)或更高版本,請確保你在開發版本中有打開懸浮窗(overlay)
權限。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...
}
}
}
}
運行你的應用
運行應用首先需要啟動開發服務器(Packager)。你只需在項目根目錄中執行以下命令即可:
npm install
npm start
保持packager的窗口運行不要關閉,然后像往常一樣編譯運行你的Android應用(在命令行中執行./gradlew installDebug
或是在Android Studio中編譯運行)。
如果你是使用Android Studio來編譯運行,有可能會導致packger報錯退出。先把packager服務窗口關掉,然后再使用AndroidStudio編譯運行Android應用,
這個時候只保持在MainActivity頁面,然后重新在項目根目錄執行npm start命令,然后操作APP進入MyReactActivity的頁面
編譯執行一切順利進行之后,在進入到MyReactActivity時應該就能立刻從packager中讀取JavaScript代碼并執行和顯示:
在Android Studio中打包
你也可以使用Android Studio來打release包!其步驟基本和原生應用一樣,只是在每次編譯打包之前需要先執行js文件的打包(即生成離線的jsbundle文件,這樣APP進入RN編寫的頁面會直接調用本身的JS代碼,不需要去服務器請求)。
具體的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后面的兩個參數指出assets和res文件夾的具體路徑,注意把上述命令中的路徑替換為你實際項目的路徑。如果assets目錄不存在,需要提前自己創建一個。
然后在Android Studio中正常生成release版本即可!
打包好的release版本app運行在許多X64CPU的手機上,打開RN頁面直接閃退
錯誤:
java.lang.UnsatisfiedLinkError: dlopen failed: "xxx/libgnustl_shared.so" is 32-bit instead of 64-bit
解決方案:
1、在項目的根目錄的 gradle.properties里面添加一行代碼
android.useDeprecatedNdk=true.
2、在project的root目錄下的build.gradle中添加如下代碼。
defaultConfig {
···
ndk{
abiFilters "armeabi-v7a","x86"
}
packagingOptions {
exclude "lib/arm64-v8a/librealm-jni.so"
}
}