ReactNative实战

ReactNative实战

一、环境准备

注*:下面习惯将ReactNative简称为RN

详细步骤可参见 -> RN环境搭建

nodeyarn,开发工具android studiovscode

需要用到react-native脚手架搭建项目,yarn global add react-native

创建RN项目,react-native init app-demo,可以看到当前项目生成了一个app-demo目录,里面有android目录和ios目录,分别表示android开发和ios开发的,因为RN实际上只是是跨平台的UI库,大多数涉及到系统开发的逻辑需要通过与原声交互的方式实现

通过命令行进入app-demo目录,使用yarn install下载依赖,命令会检索package.json文件中的dependenciesdevDependencies节点的依赖下载到当前目录的node-modules文件夹下

常见问题(一)

直接启动RN项目在下载android相关依赖时可能会因为网络问题导致下载包失败

设置android依赖设置为国内镜像,提高下载速度,打开android目录,编辑build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        buildToolsVersion = "28.0.3"
        minSdkVersion = 16
        compileSdkVersion = 28
        targetSdkVersion = 28
        // googlePlayServicesVersion = "16.1.0" // default: "16.1.0" - pre-AndroidX, override for AndroidX
    }
    repositories {
        // google()
        // jcenter()
        
        // 替换成国内镜像源
        maven { url 'https://maven.aliyun.com/repository/jcenter' }
        maven { url 'https://maven.aliyun.com/repository/google' }
    }
    dependencies {
        classpath('com.android.tools.build:gradle:3.5.2')

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        // 先本地maven仓库中找
        mavenLocal()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url("$rootDir/../node_modules/react-native/android")
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../node_modules/jsc-android/dist")
        }

        maven { url 'https://maven.aliyun.com/repository/jcenter' }
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://jitpack.io' }

        // google()
    }
}
常见问题(二)

这样直接运行RN项目可能会遇上一个奇怪的bug,页面直接报错,Cannot find entry file index.android.js in any of the roots,原因是RN默认是去找index.android.js这个文件,而初始化的RN项目的入口文件名叫index.js,所以需要修改android/app/build.gradle

project.ext.react = [
    entryFile: "index.js",
    enableHermes: false,  // clean and rebuild if changing
    bundleInDebug: true
]
运行RN项目

打开package.json文件,找到scripts节点,目前只关心androidstart命令,可通过yarn android运行scripts节点下的命令,相当与间接运行react-native run-android

"scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
},

手机进入开发者模式,并设置连接方式为文件传输,运行adb devices命令确保设备已正常运行并连接,运行yarn android安装应用。

start命令会启动一个守护进程,用来监控app,可以实现app的热更新,通过r键刷新app,d在app上打开调试菜单

二、ReactNative是什么

React有着Learn One, Write Any的名号,RN也不例外,它完全可以用React的语法进行编码开发

对于使用过React的人并不陌生,render函数是React在渲染页面时使用的方法,对于RN来说,render函数也是渲染app页面的重要函数

但React和RN在render函数中的使用规则有着比较大的区别,就是React在浏览器中使用时,可以在render函数中使用任何标签,例如<div></div>等,而RN中只能使用预定义好的标签,比如<View></View>,在RN中,可以把View标签当作div来用

之所以不能使用普通的html标签是因为RN和普通的WebView实现的app不一样,它需要保证App的性能,所以需要做一些定制化工作,比如View这些标签实际上在android或ios有着自己原生代码的实现,就拿android来说,RN在实现View标签的时候,在android底层封装了一个active.xml,使用View标签就相当与在底层使用了这个active.xml的布局文件,所以RN的性能并不会和原声Android相差太多

因为RN的UI组件都是经过原生代码封装过的,所以它无法想WebView那样做到任意的定制化布局,它的想象空间被极大的限制住了。但是RN还是有着自己独特的优点,它能让不熟悉原生android的前端开发人员也能具备开发一些简单的“Curd App”的能力,然并luan!如果想用RN开发出来一款真正的产品,仅仅是写写页面是微不足道的,他离不开原生开发的支持。比如做个百度地图需要用到GPS,登录页的人脸识别需要相机,需要在AndroidManifest.xml文件中配置app所需要的权限,比如接下来我要讲的硬件监控需要读取android系统的/proc/stat(CPU使用情况)或者/proc/meminfo(内存使用情况)等。直接用RN是做不到的,虽然网上有类似的插件(react-native-device-info),但我测试的时候发现获取内存信息和磁盘信息数据量不准确的问题,还有不支持获取cpu和流量信息。

可以看到,当想要把app真正的作为一款产品来开发的话,绝对是离不开原生开发的支持的,就算RN发展的如火如荼,但不管怎样,毕竟Android和ios才是地头蛇,如果只是一味的想要比较WebView、RN、原声这些app开发技术到底哪个好,最终只会是限制自己的发展

三、使用RN的第三方插件

大多数RN的第三方插件也是通过原生代码实现的

以上面提过的react-native-device-info为例,其它的RN插件引入RN的方式和这个一样,像react-native-fs(文件读写)、react-native-background-timer(后台定时任务,虽然用RN的Headless也可以实现)这些插件,能提高我们的开发效率,当然,如果经历允许的话,也可以自己编写插件并发布到网上。

参考 react-native-device-info使用

可能插件官方的教程适用于旧版RN,对于我0.61.5较新的版本来说,需要稍作改动

  1. yarn add react-native-device-info

  2. 修改android/settings.gradle,添加

    include ':react-native-device-info'
    project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
    
  3. 修改android/app/build.gradle,在dependencies节点添加

    implementation project(':react-native-device-info')
    

然后就可以直接在js上使用了

四、RN与原生交互

创建一个简单的工具类,然自己可以通过js调用android的代码,工具类需要继承ReactContextBaseJavaModule并实现getName方法,getName方法返回的字符串就是工具类的标识

下面定义的toastMsg方法接收js传过来的参数字符串并将参数作为提示弹出到app页面上

提供给js调用的方法需要加上@ReactMethod注解

在js中可以通过NativeModules.ToastExample.toastMsg("提示")这种方法调用

public class ToastModule extends ReactContextBaseJavaModule {

    public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @NonNull
    @Override
    public String getName() {
        return "ToastExample";
    }

    /**
     * 弹出一个提示
     */
    @ReactMethod
    public void toastMsg(String msg) {
        Toast.makeText(getReactApplicationContext(), msg, Toast.LENGTH_SHORT).show();
    }
}

第二步,还需要将自定义的工具类注册一下,再创建个自定义的包管理器,实现ReactPackage接口

public class AnExampleReactPackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        // 将刚刚的工具类放上去
        modules.add(new ToastModule(reactContext));
        return modules;
    }
}

第三步,修改MainApplication.java文件,在ReactNativeHost内部类实现的getPackages方法中加上刚刚的自定义包管理器

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    public boolean getUseDeveloperSupport() {
        return BuildConfig.DEBUG;
    }

    @Override
    protected List<ReactPackage> getPackages() {
        @SuppressWarnings("UnnecessaryLocalVariable")
        List<ReactPackage> packages = new PackageList(this).getPackages();
        // 将自定义包管理器放进去
        packages.add(new AnExampleReactPackage());
        // Packages that cannot be autolinked yet can be added manually here, for example:
        // packages.add(new MyReactNativePackage());
        return packages;
    }

    @Override
    protected String getJSMainModuleName() {
        return "index";
    }
};

大功告成!

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×