背景:最近在学习React-Native相关的知识,有个需求,如果已经存在一个成熟的Android 或者 IOS项目,如何实现在后续的开发中用RN来实现部分功能。再此我只是讲解一下Android demo的两种实现方法。
虽说是官方推荐实现,最开始我也是按照上面的教程,一步一步搭建环境,但是上面的内容有些更新不及时,而且有些坑,上面还有提及,所以在这里总结说明一下需要注意的地方,避免大家再次入坑。
首先,环境搭建,可以参考React Native中文网 0.59来安装一些依赖的软件
创建一个空目录用于存放React Native项目,在其中创建一个”/android"子目录,将你现有的Android项目,放到这个子目录中
a. 在项目跟目录下创建文件 ”package.json",了解package.json, 添加如下内容
每个项目的根目录下面,一般都有一个package.json文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。npm install命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。
{
"name": "android_with_rn",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^16.8.6",
"react-native": "^0.59.5"
}
}
b. 然后,在当前项目目录(包含package.json)中,打开终端/命令提示行,通过npm(node 包管理工具)来安装React和React Native模块,运行命令“npm install”,这些模块会被安装根目录的“node_modules"目录中(这个目录我们原则上不复制、不移动、不修改、不上传,随用随装)
把node_modules/目录记录到.gitignore文件中(即不上传到版本控制系统,只保留在本地)。
npm install --save react react-native
a. 在已经存在的Android 项目的app build.gradle 文件添加 React Native 依赖:
- 如果想要指定特定的 React Native 版本,可以用具体的版本号替换 +,当然前提是你从 npm 里下载的是这个版本。
- 注意该版本号需要与package.json文件中配置的RN版本号保持一致。
之所以需要在项目的build.gradle文件中添加maven配置,是因为Android项目默认的依赖包的源jcenter()并不包含最新版的React Native(它只到0.20.1)
dependencies {
...
implementation "com.facebook.react:react-native:+" // From node_modules.
}
b. 在已经存在的Android 项目的 build.gradle 文件添加 React Native 的 Maven 依赖的入口,必须写在 “allprojects” 代码块中
allprojects {
repositories {
maven {
url "$rootDir/node_modules/react-native/android"
}
jcenter()
google()
}
}
a. 在 AndroidManifest.xml 添加权限声明:
如果需要访问 DevSettingsActivity 界面(即开发者菜单),则还需要在 AndroidManifest.xml 中声明下面权限,开发者菜单一般仅用于在开发时从 Packager 服务器刷新 JavaScript 代码,所以在正式发布时你可以去掉这一权限。
b. Android6.0 及以上需要添加动态权限申请悬浮窗权限(overlay)
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();
}
@SuppressLint("WrongViewCast")
private void initView() {
mBtnRn = findViewById(R.id.btn_rn);
mBtnRn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转RN页面
startActivity(new Intent(MainActivity.this, BaseRnActivity.class));
}
});
}
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被拒绝
}
}
}
}
}
a. 创建一个index.js文件(注意在 0.49 版本之前是 index.android.js 文件)
index.js是 React Native 应用在 Android 上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行require/import导入语句。本教程中为了简单示范,把全部的代码都写到了index.js里(当然实际开发中我们并不推荐这样做)。
Index.js
import React from 'react';
import {AppRegistry, StyleSheet, Text, View} from 'react-native';
class HelloWorld extends React.Component {
render() {
return (
RN 项目
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
AppRegistry.registerComponent('Android_With_RN', () => HelloWorld);
b. 应用中添加一个RCTRootView。这个RCTRootView正是用来承载你的 React Native 组件的容器。
注意1:官方推荐不是最新版本,最新RN(0.59.5)不需要自己实DefaultHardwareBackBtnHandler,只要集成ReactActivity,最新版本0.59.5 ,在ReactActivity中,已经帮我们实现了ReactRoot与ReactInstanceManager的配置
public class MyReactActivity extends ReactActivity {
@Nullable
@Override
protected String getMainComponentName() {
return "Android_With_RN";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this,getMainComponentName());
}
}
我们需要在AndroidManifest.xml 把 MyReactActivity 的主题设定为 Theme.AppCompat.Light.NoActionBar ,因为里面有许多组件都使用了这一主题。
c. 实现ReactApplication
注意2:这一点和React Native中文网没有提到
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
在AndroidManifest 配置MainApplication
d. 在 Android Studio 中打包
你也可以使用 Android Studio 来打 release 包!其步骤基本和原生应用一样,只是在每次编译打包之前需要先执行 js 文件的打包(即生成离线的 jsbundle 文件)。具体的 js 打包命令如下:
注意:bundle文件路径,把上述命令中的路径替换为你实际项目的路径。如果 assets 目录不存在,则需要手动的在app/src/main/目录中添加一个assets目录。
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/
–platform : 平台(android/ios)
–dev : 开发模式
–entry-file : 条目文件
–bundle-output : bundle文件生成的目录
–assets-dest : 资源文件生成的目录
如果打包成功,会显示
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
在RN运行命令,运行到android设备中
react-native run-android
未完待续 下一篇讲解 另一种实现方式点我