接着上文,原生模块sync之后如果没有报错信息,那么我们就可以进入下一步了。我们还是分两大部门来介绍;rn端和原生端。

rn端环境搭建(进阶) 大家还记得上面这篇博客的这幅图吧。这就是我们执行下面命令,生成的原始目录结构。

npx react-native init AwesomeProject

现在,我们来对它添加一些文件,以完善rn端执行js/ts代码所需要的功能。 我们需要添加两个文件babel.config.js和metro.config.js。首先,babel.config.js是babel转换器的相关配置,因为es2015使用了一些高级语法,babel则是将这些高级语法转换成浏览器引擎能够识别的语法;metro.config.js则是metro打包相关的配置信息。笔者对这些配置信息也没有深入的了解太多,如果只限于搭建rn环境这个需求,大家如下配置即可。

//在babel.config.js文件中copy下面这段代码

module.exports = {

presets: ['module:metro-react-native-babel-preset']

};

//在metro.config.js文件中copy下面这段代码

module.exports = {

transformer: {

getTransformOptions: async () => ({

transform: {

experimentalImportSupport: false,

inlineRequires: false,

},

}),

},

};

细心的同学一定发现了上图中有一个tsconfig.json文件。这个文件是配置相关ts的信息的。因为rn端的代码执行的是js代码,而js代码是动态语言,它最令人恶心的一点是:它是不会报错的。因此,如果用来开发大型项目分分钟搞死开发者,笔者使用的是ts来代替js。因此,需要添加tsconfig.json文件。

//tsconfig.json

{

"compilerOptions": {

"allowJs": true,

"allowSyntheticDefaultImports": true,

"esModuleInterop": true,

"isolatedModules": true,

"jsx": "react-native",

"module": "commonjs",

"lib": ["es6"],

"moduleResolution": "node",

"noEmit": true,

"strict": true,

"target": "esnext",

"baseUrl": ".",

"paths": {

"*": ["src/*"],

"tests": ["tests/*"],

"@components/*": ["src/components/*"],

}

},

"exclude": [

"node_modules",

"babel.config.js",

"metro.config.js",

"jest.config.js"

]

}

具体细节,感兴趣的同学可以查阅相关的资料,我们这里就不介绍了。 接着,我们还需要更改的一个文件就是package.json,我们之前刚初始化成功时生成的内容如下所示:

{

"name": "AwesomeProject",

"version": "0.0.1",

"private": true,

"scripts": {

"start": "node node_modules/react-native/local-cli/cli.js start"

},

"dependencies": {

"react-native": "0.70.3"

}

}

更改后:

{

"name": "AwesomeProject",

"version": "0.0.1",

"private": true,

"scripts": {

"start": "yarn react-native start",

"android": "npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/main.bundle --assets-dest android/app/src/main/res/"

},

//我们这里改下react和react-native的版本,因为0.70.3版本使用的是新架构,笔者暂时还不熟悉,所以我们用旧架构来讲解,记住,react和react-native都需要

"dependencies": {

"react": "16.9.0",

"react-native": "^0.63.4",

},

//devDependencies里面的内容,大家copy即可,有些依赖例如jest,项目中没有用到的可以移除,当然你添加进去不用它也没有问题

"devDependencies": {

"@types/jest": "^27.0.1",

"@types/react": "^17.0.21",

"@types/react-native": "^0.65.0",

"@types/react-test-renderer": "^17.0.1",

"babel-plugin-module-resolver": "^4.1.0",

"typescript": "^4.4.3",

"webpack": "^5.53.0",

"webpack-cli": "^4.8.0"

}

}

dependencies和devDependencies这两个东西到底是做什么的呢?其实这里的东西就有点像是Android原生gradle中的dependencies闭包,如果我们在原生中想要引入某个依赖一般会如下添加:

implementation 'com.google.android.material:material:1.4.0'

当我们在命令行终端执行yarn命令时,node就会下载dependencies和devDependencies所指定的依赖到node_modules文件夹下面。 这里有一个小提醒:每次我们进行开发时,最好删掉我们本地的node_modules文件夹,然后重新yarn一下,以确保我们本地的依赖与dependencies和devDependencies块所指定的依赖时一致的。 官网上是使用npm来下载依赖的,个人不建议使用npm,主要原因就是太慢了,所以大家尽量使用yarn吧!而且有趣的一点是,我们使用npx命令初始化一个rn项目的时候,其实也是用yarn来下载相关的依赖的,因为初始化的工程有一个yarn.lock文件,这就是最好的见证。 我们改动最大的就是scripts块里面的东西

"scripts": {

"start": "yarn react-native start",

"android": "npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/main.bundle --assets-dest android/app/src/main/res/"

},

start是我们调试代码用到的。后面会讲解如何使用这个功能。android则是打包bundle的命令,上例中我们指定了生成的bundle的名字为main.bundle,将生成的bundle放置在assets目录下,将rn端用到的图片放置在res目录下。即–bundle-output 后面的参数和–assets-dest后面的参数可以自定义的。我们在命令行终端执行yarn android命令,即可生成main.bundle。

这样,我们就完成了rn端环境的搭建了。现在,我们来写下rn页面的代码来测试下。首先,我们新建一个src文件夹,用来存放我们缩写的rn代码。如下所示: 然后,我们在src建立一个HelloWorld.tsx文件。

import React from "react";

import {StyleSheet, Text, View} from "react-native";

const styles = StyleSheet.create({

container: {

// flex: 1,

justifyContent: 'center',

alignItems:'center'

},

hello: {

fontSize: 20,

textAlign: 'center',

margin: 10

}

});

export class HelloWorld extends React.Component {

render() {

return (

{"setData"}

);

}

}

然后,在index.js文件中添加如下代码

import React from 'react';

import {AppRegistry,} from 'react-native';

import {HelloWorld} from "./src/view/HelloWorld";

//如果原生端想要引用rn端的控件,则必须要使用registerComponent方法注册,如果单纯只是给rn端使用,那么就不必使用registerComponent方法注册。

//例如:我们原生想要调用HelloWorld这个rn组件,那么原生就必须通过“MyReactNativeApp”这个键找到HelloWorld这个控件,如果HelloWorld只是被rn端的其他ts文件引用,那么就不必在这里注册了

AppRegistry.registerComponent(

'MyReactNativeApp',//这个名字可以随便定义,但是必须是字符串

() => HelloWorld

);

这样,我们rn端的第一个页面就写好了。

原生环境搭建(进阶) 首先,我们要自定义一个application,该application需要实现ReactApplication接口。

package com.example.demo;

import android.app.Application;

import android.content.Context;

import com.facebook.soloader.SoLoader;

/**

* Created by Brett.li on 2021/9/21.

*/

public class MyReactApplication extends Application implements ReactApplication {

@Override

public ReactNativeHost getReactNativeHost() {

return new ReactNativeHost(this) {

@Override

public boolean getUseDeveloperSupport() {

return BuildConfig.DEBUG;

}

@Override

protected List getPackages() {

return new PackageList(this).getPackages();

}

@Nullable

@Override

protected String getBundleAssetName() {

//就是我们打包出来的bundle的名字,不能写错,不然就加载不到bundle

return "main.bundle";//bundle的名字,默认是index.android.bundle

}

@Override

protected String getJSMainModuleName() {

//即打包脚本中--entry-file后面的参数名。不能写错

return "index";

}

};

}

@Override

public void onCreate() {

super.onCreate();

SoLoader.init(this, /* native exopackage */ false);

}

}

//application中需要做两件事

//1.实现getReactNativeHost接口

//2.添加SoLoader.init(this, /* native exopackage */ false);这句代码

接着,我们在activity做如下修改:

public class MainActivity extends AppCompatActivity {

private BaseRNActivityDelegate mDelegate;

protected BaseRNActivityDelegate createReactActivityDelegate() {

return new BaseRNActivityDelegate(this, "MyReactNativeApp");//表示,我们要加载MyReactNativeApp所对应的rn控件

}

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mDelegate = createReactActivityDelegate();

mDelegate.onCreate( savedInstanceState);

}

//ReactActivityDelegate其实就是个代理,这个类里面帮助我们做了大量的工作,我们,只要在其构造方法中传入index.js中注册的控件的键名即可调用对应的控件。至于为什么要继承ReactActivityDelegate类,是因为该类里面很多方法都是protected的,我们根本不能直接调用

class BaseRNActivityDelegate extends ReactActivityDelegate{

public BaseRNActivityDelegate(Activity activity, @Nullable String mainComponentName) {

super(activity, mainComponentName);

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

}

}

}

这样,我们运行程序,MainActivity页面就能够加载到HelloWorld.tsx文件里面的内容了。

记得要修改androidManifest.xml文件

package="com.example.demo">

android:name=".MyReactApplication"

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:roundIcon="@mipmap/ic_launcher_round"

android:supportsRtl="true"

android:theme="@style/Theme.Demo"

android:usesCleartextTraffic="true">

android:exported="true">

好了,到这里我们已经基本搭建好了rn的环境的。后面,笔者会继续讲解如何封装原生的代码的。

推荐阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: