原生项目中引入ReactNative介绍篇
工程目录结构介绍
项目结构介绍
- MyDemon
- demon_android
- demon_rn
叙述
工程名称:MyDemon ,包含两个子项目:安卓(demon_android), RN(demon_rn)。
强调:一般网文介绍的RN混编项目目录结构
- RN项目名称
- android文件夹
- ios文件夹
- node_module
- ....
- index.js
- package-lock.json
- package.json
这种项目结构适用于以RN界面为核心,原生为辅的移动应用,最上面文章说的项目结构适用于以原生界面为核心,RN为辅的移动应用。所以各位看官还需弄清楚定位,如果不适还请酌情观看,当然也有可借鉴的地方,谢谢赏脸。
接入过程
参考博客或者文档链接
此处接入的核心库版本:androidx.appcompact:appcompact:1.0.2, com.facebook.react:react-native:0.63.3
安卓项目配置(demon_android)
app的build.gradle文件配置
def useIntJsc = false
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
//需要加载的react_native库
implementation('com.facebook.react:react-native:+')
//此处出现了herm需要加载的so库,但找不到的异常的情况
if (useIntJsc) {
implementation('org.webkit:android-jsc-intl:+')
} else {
implementation('org.webkit:android-jsc:+')
}
}
app的AndroidMainifest.xml的文件配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wnp.hybrid">
<application android:networkSecurityConfig="@xml/network_security_config">
<activity
android:name="com.wnp.hybrid.rn.MyReactActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>
app的MyReactActivity配置
package com.wnp.hybrid.rn;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactInstanceManagerBuilder;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.JSBundleLoaderDelegate;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.PermissionListener;
import com.facebook.react.shell.MainReactPackage;
import com.wnp.hybrid.BuildConfig;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
/**
* @Author : xiaowei
* @Date 2020/10/23 7:26
*/
public class MyReactActivity extends FragmentActivity implements DefaultHardwareBackBtnHandler {
/**
* 以下两个变量作为传递数据到RN的key, so需要与RN团队协调传值key的规则
*/
private static final String ARGS_JSON = "args_json";
private static final String ROUTE_PATH = "route_path";
//设置开发者开发信息
private static final String DEVELOPER_HOST = "192.168.0.110:8081";
private static final String DEV_URL = "http://" + DEVELOPER_HOST + "/index.bundle?platform=android";
public static class Launcher {
final static String ROUTE = "route";
final static String ARGS = "args";
public static void launch(Context packageContext, String routePath, String argsJson) {
Intent intent = new Intent(packageContext, MyReactActivity.class);
intent.putExtra(ROUTE, routePath);
intent.putExtra(ARGS, argsJson);
packageContext.startActivity(intent);
}
}
/**
* react—native 视图容器
*/
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder();
builder.setApplication(getApplication())
.setCurrentActivity(this)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackages(getPackages())
.setUseDeveloperSupport(getUseDeveloperSupport())
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
builder.setJSBundleLoader(new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
String path = null;
if (getUseDeveloperSupport()) {
//开发者模式
path = DEV_URL;
delegate.setSourceURLs(null, DEV_URL);
} else {
//正式环境模式
path = "file://android_asset/xxxBundle";
delegate.loadScriptFromAssets(getAssets(), "file://android_asset/xxxBundle", true);
}
return path;
}
});
mReactRootView.startReactApplication(mReactInstanceManager = builder.build(), getMainComponentName(), getLaunchOptions());
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onResume() {
super.onResume();
mReactInstanceManager.onHostResume(this);
}
@Override
protected void onPause() {
super.onPause();
mReactInstanceManager.onHostPause(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
mReactInstanceManager.onHostDestroy(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @androidx.annotation.Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mReactInstanceManager.onActivityResult(this, requestCode, resultCode, data);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (getUseDeveloperSupport()
&& keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
event.startTracking();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
return super.onKeyLongPress(keyCode, event);
}
@Override
public void onBackPressed() {
mReactInstanceManager.onBackPressed();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
mReactInstanceManager.onNewIntent(intent);
}
/**
* 返回主Component注册的名字
*
* @return
*/
protected String getMainComponentName() {
return "react-example";//需要与index.js文件第一个注册的Component名字相同
}
/**
* 用于传递数据给MainComponent
* 一般传递的数据包含:
* 1.routePath -- 页面的路由路径
* 2.argsJson -- 传递给页面的数据
*/
@Nullable
protected Bundle getLaunchOptions() {
Bundle bundle = new Bundle();
bundle.putString(ROUTE_PATH, getIntent().getStringExtra(Launcher.ROUTE));
bundle.putString(ARGS_JSON, getIntent().getStringExtra(Launcher.ARGS));
return bundle;
}
/**
* 作用:用于在开发期间,产生的错误及时显示在界面上
*
* @return
*/
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
protected List<ReactPackage> getPackages() {
List<ReactPackage> list = new ArrayList<>();
list.add(new MainReactPackage());
return list;
}
}
project的build.gradle配置
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.31'
repositories {
maven {
url "$rootDir/../demo-rn/node_modules/react-native/android"
}
maven {
// Android JSC is installed from npm
url("$rootDir/../demo-rn/node_modules/jsc-android/dist")
}
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven {
url "$rootDir/../demo-rn/node_modules/react-native/android"
}
maven {
// Android JSC is installed from npm
url("$rootDir/../demo-rn/node_modules/jsc-android/dist")
}
google()
jcenter()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
RN项目配置(demon_rn)
创建package.json
{
"name": "MyDemo",
"version": "1.0.0",
"description": "react_native",
"main": "index.js",
"scripts": {
//注意:需另外加上
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "xiaowei",
"license": "ISC",
"dependencies": {
"react": "^17.0.1",
"react-native": "^0.63.3"
}
}
创建index.js, 界面显示HelloWorld文本
'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, World</Text>
</View>
)
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
AppRegistry.registerComponent('react-example', () => HelloWorld);
项目执行流程 —— 关键执行命令
执行命令: 在demon_rn文件夹目录下,执行'yarn add react-native',等待数分钟生成一个node_module文件夹用于提供依赖
启动node.js服务器,执行命令:'react-native start'
编译打包demon_android项目并打包生成APK安装到手机上,跳转到MyReactActivity, 就会正常显示HelloWorld文本
接入流程注意点
基于以原生为主,混编为辅的项目结构,使得开发效率得到最大的提升,在研究一番之后做出如下调整,(文档未说明)
builder.setJSBundleLoader(new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
String path = null;
if (getUseDeveloperSupport()) {
//开发者模式
path = DEV_URL;
delegate.setSourceURLs(null, DEV_URL);
} else {
//正式环境模式
path = "file://android_asset/xxxBundle";
delegate.loadScriptFromAssets(getAssets(), "file://android_asset/xxxBundle", true);
}
return path;
}
});
上面的代码用了两种模式加载RN的代码.模式一:在开发模式下,直接使用远程服务器调试界面代码.模式二:在生产环境下,使用Asset文件夹下的android_bundle包加载RN代码,当然可以用以任何路径下文件的形式,提供框架加载RN代码
多种项目目录结构介绍,对应git的使用
基于第一种项目结构,git使用
因为RN与原生项目相互独立,不互相影响,那么git就按常规使用即可
基于第二种的项目结构,git使用
因为RN项目包含原生项目,相互影响,那么git在使用过程中需要注意:
1.如果希望原生项目与RN项目分开提交git记录,那么需要用到'git submodule init' 命令,用于初始化原生的项目,目的使得各自的代码提交记录分开。
2.如果不在乎原生项目与RN项目git记录混为一起,那么可忽略上面第一点
网友评论