我們知道從0開始搭建ReactNative項(xiàng)目的話,參照官方的Getting Started來的話基本是沒有問題的袜硫。但是如果我們想把現(xiàn)有的項(xiàng)目集成RN的話,雖然有官方的Integration with Existing Apps集成步驟,但是有個(gè)別的地方說的還是不清不楚孽惰,可能對(duì)于初學(xué)者埋下了坑點(diǎn)。本人也是第一次集成嗤无,現(xiàn)在講集成的點(diǎn)點(diǎn)滴滴寫出來猴贰,本文基本思路還是引用官方的集成步驟來的对雪。
開發(fā)環(huán)境搭建
- 新建Android Studio工程為AndroidRnDemo,項(xiàng)目SDK版本等信息
//最低版本
minSdkVersion 19
//目標(biāo)版本
targetSdkVersion 26
// support v7
implementation 'com.android.support:appcompat-v7:26.1.0'
//gradle
classpath 'com.android.tools.build:gradle:3.0.1'
- 配置ReactNative的js環(huán)境
我們進(jìn)入到AndroidRnDemo的項(xiàng)目根目錄,接下來我們開始在終端輸入:
npm init
我們可以看到init讓你生成一個(gè)package.json文件米绕,當(dāng)然這里里面的配置信息就是讓你剛剛init填寫的配置參數(shù):
//init命令提示輸入的信息
name: (AndroidRnDemo) androidrndemo
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author: loen
license: (ISC)
//package.json
{
"name": "androidrndemo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "loen",
"license": "ISC"
}
添加ReactNative到項(xiàng)目
接下來我們將React瑟捣、ReactNative添加到項(xiàng)目中:
npm install --save react react-native
安裝完成之后,我們?cè)偃ヅ渲?flowconfig栅干,這個(gè)是對(duì)js代碼做約束的迈套,建議配置(也可以不配置)。
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
當(dāng)然你也可以在項(xiàng)目根目錄新建.flowconfig非驮,然后把這個(gè)鏈接的文件內(nèi)容復(fù)制到.flowconfig中交汤。
添加start到package.json文件
這樣我們就可以時(shí)時(shí)的調(diào)用本地調(diào)試服務(wù)進(jìn)行熱加載了
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node node_modules/react-native/local-cli/cli.js start"
},
好了雏赦,現(xiàn)在看下我們的項(xiàng)目目錄吧
添加ReactNative到Android項(xiàng)目
添加ReactNative依賴到Android項(xiàng)目
配置你的maven
添加ReactNative的依賴到你的app目錄下的build.gradle中:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
...
// From node_modules.
api "com.facebook.react:react-native:+"
}
配置項(xiàng)目根目錄下的build.gradle:
這里有個(gè)小插曲:
//官方配置
allprojects {
repositories {
...
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
//...
}
// 由于官方的android項(xiàng)目是放在android/目錄下劫笙,所以他的路徑是這樣的
"$rootDir/../node_modules/react-native/android"
//而我們?yōu)榱朔奖鉇S編譯,直接放在項(xiàng)目根目錄配置RN的星岗,所以這里的路徑要改一下
url "$rootDir/../node_modules/react-native/android"
//我們的目錄正確配置
allprojects {
repositories {
maven {
url "$rootDir/node_modules/react-native/android"
}
jcenter()
}
}
為了防止個(gè)別機(jī)型.so庫(kù)和findbugsbug問題填大,建議在app/build.gradle中增加下面的代碼:
android {
defaultConfig {
ndk {
//選擇要添加的對(duì)應(yīng)cpu類型的.so庫(kù)。
abiFilters 'armeabi', "armeabi-v7a","armeabi-v7a","x86"
}
}
//...
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
}
}
AndroidManifest.xml
添加權(quán)限:
<uses-permission android:name="android.permission.INTERNET"/>
/**設(shè)置調(diào)試 的權(quán)限**/
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
添加debug模式Activity(正式打包注釋掉就好了)
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
debug模式下需要懸浮窗的權(quán)限俏橘,這個(gè)需要手動(dòng)設(shè)置允华,每部手機(jī)姿勢(shì)不一樣,具體請(qǐng)百度調(diào)整姿勢(shì)寥掐。如果沒有設(shè)置的話靴寂,個(gè)別手機(jī)在debug模式下reload會(huì)出現(xiàn)異常
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@fc0db15 -- permission denied for this window type
添加ReactNative界面
添加index.js
首先我們?cè)陧?xiàng)目根目錄添加index.js,這個(gè)文件作為RN的入口文件。
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}>Hello, World</Text>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
AppRegistry.registerComponent('AndroidRnDemoApp', () => HelloWorld);
注意 AppRegistry.registerComponent('AndroidRnDemoApp', () => HelloWorld);里面的AndroidRnDemoApp,這個(gè)作為接下來我們要綁定的activity的入口通道名召耘。
配置Android動(dòng)態(tài)權(quán)限--->(非必須百炬,針對(duì)targetSdk>=23版本(android 6.0))
我們的項(xiàng)目目標(biāo)sdk是26,所以我們需要去代碼請(qǐng)求窗口浮層的權(quán)限污它,為了方便起見呢剖踊,我們將在MainActivity里面配置這個(gè)權(quán)限:
public class MainActivity extends AppCompatActivity {
static final int OVERLAY_PERMISSION_REQ_CODE = 1000;
private AppCompatButton mBtnRn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initEvent();
}
private void initEvent() {
initView();
checkAppPermission();
}
private void initView() {
mBtnRn = (AppCompatButton) findViewById(R.id.btn_rn);
mBtnRn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳轉(zhuǎn)RN頁(yè)面
}
});
}
private void checkAppPermission() {
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);
}
}
}
@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被拒絕
}
}
}
}
}
添加RN Activity界面
我們新建一個(gè)Activity作為RN界面展示的容器庶弃。這里姑且叫BaseRnActivity吧。
public class BaseRnActivity extends Activity 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")
.setJSMainModulePath("index")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
//這里的AndroidRnDemoApp必須對(duì)應(yīng)“index.js”中的“AppRegistry.registerComponent()”的第一個(gè)參數(shù)
mReactRootView.startReactApplication(mReactInstanceManager, "AndroidRnDemoApp", null);
//加載ReactRootView到布局中
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
/**
* ReactInstanceManager生命周期同activity
*/
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy(this);
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
}
最后不要忘了在AndroidManifest中添加:
<activity
android:name=".BaseRnActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
RN打離線包到Android
由于我們?cè)贐aseRnActivity的ReactInstanceManager中setBundleAssetName("index.android.bundle")了android離線包德澈,所以在運(yùn)行之前我們app之前先打個(gè)離線包JSBundle到android項(xiàng)目中歇攻。
首先在項(xiàng)目app/src/main下面必須要?jiǎng)?chuàng)建一個(gè)assets目錄,然后我們就開始打離線包啦:
//注意路徑
react-native bundle --platform android --dev false --entry-file index.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/
# 控制臺(tái)這樣輸出的話 梆造,表示打包成功
Loading dependency graph, done.
bundle: start
bundle: finish
bundle: Writing bundle output to: app/src/main/assets/index.android.bundle
bundle: Done writing bundle output
運(yùn)行ReactNative
由于我們是已有項(xiàng)目集成RN,所以我們就不可以使用命令react-native run-android了缴守。沒關(guān)系我們手動(dòng)編譯唄。
//先開啟本地react native服務(wù)
adb reverse tcp:8081 tcp:8081
npm start
這里需要注意的是連接Debug server的話镇辉,需要我們手機(jī)連接pc的代理斧散,具體請(qǐng)參考
ok 運(yùn)行成功
遇到的坑
- 未添加NDK的so庫(kù)
java.lang.UnsatisfiedLinkError: could find DSO to load: libreactnativejni.so
java.lang.UnsatisfiedLinkError: dlopen failed: "xxx/libgnustl_shared.so" is 32-bit instead of 64-bit
這個(gè)錯(cuò)誤前面在我集成的項(xiàng)目中已經(jīng)添加了 ,如果你沒有添加摊聋,那就報(bào)錯(cuò)了鸡捐。
android {
defaultConfig {
ndk {
//選擇要添加的對(duì)應(yīng)cpu類型的.so庫(kù)。
abiFilters 'armeabi', "armeabi-v7a","armeabi-v7a","x86"
}
}
//...
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
}
}
2.依賴錯(cuò)誤:
Error:Execution failed for task ':app:prepareDebugAndroidTestDependencies'.
在app/build.gradle中添加
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
}
3.待補(bǔ)充...