公司要求使用RN开发项目,之前了解过一直没有写过,因网络上大量错误及不相关信息,此博客只记录最开始的配置及运行,不涉及太多代码。本篇基于已配置好RN环境,即npm命令可用,若没有搭建请移步:https://reactnative.cn/docs/0.47/getting-started.html
环境:MacOS + Android Studio3.0 + gradle3.0.0
1.Android Studio新建项目,常规建立项目,本篇Demo为“RNTest”。(注意最小SDK要选择16及以上,选择16即可)
2.Android Studio切换至Project目录结构,在根目录创建package.json,并粘贴以下代码:
{
"name": "RNTest",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "16.0.0-alpha.6",
"react-native": "0.44.3"
}
}
3.接下来打开终端/命令提示符,cd到该项目的根目录(RNTest),输入npm install。
4.在app的gradle里添加:(忽略+的警告,用+是防止固定版本带来的更新找不到包等问题)
dependencies {
...
compile "com.facebook.react:react-native:+" // From node_modules.
}
5.在项目的gradle中添加maven:(这里有坑,详见最后坑3)
allprojects {
repositories {
...
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
...
}
6.在AndroidManifest.xml里添加权限:
<uses-permission android:name="android.permission.INTERNET" />
如果需要访问 DevSettingsActivity
界面(即开发者菜单),则还需要在 AndroidManifest.xml
中声明:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
开发者菜单一般仅用于在开发时从Packager服务器刷新JavaScript代码,所以在正式发布时你可以去掉这一权限。
7.代码集成RN组建:根目录创建一个index.android.js文件,这是RN的门户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}>Hello, React Native</Text>
</View>
)
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
AppRegistry.registerComponent('RNTest', () => HelloWorld);
8.创建一个ReactActivity.java,添加如下代码:
package com.ccl.rntest;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
//import com.facebook.react.LifecycleState;
import com.facebook.react.common.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 ReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
public static final int OVERLAY_PERMISSION_REQ_CODE = 1235;
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_react);
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);
}
}
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
// .setUseDeveloperSupport(BuildConfig.DEBUG)
.setUseDeveloperSupport(true)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();// 注意这里的RNTest必须对应“index.android.js”中的
// “AppRegistry.registerComponent()”的第一个参数
mReactRootView.startReactApplication(mReactInstanceManager, "RNTest", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// super.onActivityResult(requestCode, resultCode, 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...
}
}
}
}
@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);
}
}
以上代码具体可参考最后的参考链接。
9.修改清单文件添加:
<activity
android:name=".ReactActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
10.MainActivity修改如下:(就是添加了点击跳转事件)
package com.ccl.rntest;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.tv_react_native).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, ReactActivity.class);
startActivity(intent);
}
});
}
}
11.终端cd到项目根目录(RNTest),输入npm start。
12.Android Studio运行项目,点击跳转:
坑:
1.细心的话你会发现gradle的v7依赖包默认是26.1.0(compileSdkVersion及targetSdkVersion都是26),但不影响运行,运行之后报错:
Caused by: java.lang.IllegalAccessError: Method 'void android.support.v4.net.ConnectivityManagerCompat.<init>()' is inaccessible to class 'com.facebook.react.modules.netinfo.NetInfoModule' (declaration of 'com.facebook.react.modules.netinfo.NetInfoModule' appears in /data/app/xxc.application1-1/base.apk)
解决方式:修改app下gradle,v7依赖库为23.0.1,修改compileSdkVersion及targetSdkVersion为23。
compile 'com.android.support:appcompat-v7:23.0.1'
可参考:https://github.com/facebook/react-native/issues/6152
2.以上重新build,报如下错误:
error: attribute 'android:roundIcon' not found.
这个好说,按照提示把AndroidManifest.xml下的application里面roundIcon删掉就行,并将同时出现的v26(或其他)xml一并删掉。重新build,报build包下的AndroidManifest.xml错误:
Error:Execution failed for task ':app:preDebugAndroidTestBuild'.
> Conflict with dependency 'com.android.support:support-annotations' in project ':app'. Resolved versions for app (23.0.1) and test app (25.4.0) differ. See https://d.android.com/r/tools/test-apk-dependency-conflicts.html for details.
解决方法:Build -> ReBuild Project
3.继续报错:
Native: Got JS Exception: TypeError: undefined is not a function (evaluating '(bridgeConfig.remoteModuleConfig||[]).forEach')
解决方式:根目录的gradle修改url
allprojects {
repositories {
google()
jcenter()
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/node_modules/react-native/android"
}
}
}
这里要说明一下:网络上对ReactInstanceManager的方法都是onHostXXX的形式,它就是从上面url来的。网路上还有一种版本是onXXX即不带Host的形式,这种是从开始的第5步带“...”的url来的。俩者的LifecycleState的包名也是不同的,不带...的是common包而非直接react包。
参考文献:https://reactnative.cn/docs/0.47/integration-with-existing-apps.html#content