RN开发初探与踩坑心得

前言

本人近期才开始接触RN开发,在开发环境搭建就遇到一些问题,于是将这阵子折腾的心得整理成本此文。

由于我也是新手,可能讲的有些内容可能不是最好的方案,如果你已经是成熟的RN开发者,那可以直接离开了。

如果你也是RN开发的新手,才正要开始搭建环境,那么你参考此文应该会有些帮助。

 本文从环境搭建,一直讲到热更新包的制作,到此应该就已经掌握RN完整项目的关键技术了,然后就可以进入正式的开发阶段了。

还有,由于本人主业是做Android的,所以只讲Android相关的部分,如果你是从iOS入手,可以移驾别处了。

开发环境

Windows 10,Android Studio3.6.1(gradle:3.6.1)

RN中文官网文档

简介 · React Native 中文网

我主要是以官方文档为基础,但是官方文档中间有些细节不是那么详细,我再找其他参考资料,记录在本文中。

环境搭建

Node.js

官网直接建议我们去浏览器搜索Node,我参考菜鸟教程安装Node.js

Node.js 安装配置 | 菜鸟教程

或者,透过nvm的方式安装合适版本的node,可能有些老项目无法运行在新版node上,可以用nvm切换到合适版本的node。

Windows 安装 nvm-CSDN博客

最终要的结果,就是控制台输入下面指令能看到版本号。

node -v

npm -v

Yarn

根据官网文档,直接输入下列指令安装yarn

npm install -g yarn

安装完,yarn -v能看到版本号,基本就没问题了

初始化项目

初始化官方的模板工程

继续跟着官方文档,用下列指令创建项目

npx react-native@latest init AwesomeProject

然后,他就给我生成下面这么多东西,这个对于新手来说实在不友好,我想要的是循序渐进。

然后,最关键的,我用我的Android Studio打开他生成的android工程,直接Build过程报错,可能是AS版本问题,(AS Giraffe 2022.3.1),而且我还是习惯老版本的gradle的配置方式,所以我就没继续折腾这个模板工程了,直接看官网的” 集成到现有原生应用”

从头初始化纯净项目

此处主要按照官方文档

集成到现有原生应用 · React Native 中文网

的脉络,着重说明过程中遇到的坑,已经填坑的方式

初始化RN工程

先按照官方文档,在项目目录创建好package.json文件

{

  "name": "MyReactNativeApp",

  "version": "0.0.1",

  "private": true,

  "scripts": {

    "start": "react-native start"

  }

}

在此文件夹下执行指令

yarn add react

yarn add react-native

执行完后,会生成yarn.lock文件及node_modules文件夹,如下:

坑:用这种方式生成后,启动rn服务

yarn start

报error No Metro config found的错误

应该是少生成了什么文件,今天(2024-05-15)的版本应该少了什么,未来不知道会不会修复

我的解决方法:

指定一个之前成功初始化并运行成功的版本

yarn add react@18.1.0

yarn add react-native@0.68.1

yarn start

看到这个,离成功又近一步了

创建android工程

在项目目录中创建android文件夹,然后用android studio在此目录创建新的android项目(或是把已有项目丢进来)

在android工程加上配置

官网的教程先教配置 React Native Gradle Plugin,可以自动处理 依赖项的版本,自动打包等。但是我指定的0.68.1版本好像还没提供此插件,下面就说我的所有配置。

android项目根目录下的build.gradle,allprojects { repositories { 下加上

        maven {

            // All of React Native (JS, 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")

        }

settings.gradle加上

apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)

app下的 build.gradle,dependencies { 加上

    implementation "com.facebook.react:react-native:0.68.1" // From node_modules

    implementation "org.webkit:android-jsc:+"

以及最后加上

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

注:官方文档中 com.facebook.react:react-native: 没有指定版本,由于我没有用 React Native Gradle Plugin插件,这样找不到,所以要指定版本0.68.1

这里找的是本地仓库,从 maven { url "$rootDir/../node_modules/react-native/android" } 得知我们添加了一个本地仓库,在这个目录下有react-native:0.68.1的库

配置加好后 Sync Now,最终看到 BUILD SUCCESSFUL,我们离成功又近了一步

在Activity中添加ReactRootView

这部分按着官方文档做就好了,包括:

声明网络权限

允许明文传输(http 接口)(开发调试用,正式包可取消)

在RN项目目录加上 index.js 的 Hello, World 页面

悬浮窗(overlay)权限

在Activity中加上ReactRootView相关代码

…等

最终,运行后看到下面画面,整个项目搭建就算初步成功了

然后,你可以试着修改index.js的文字,保存,看APP画面是否会实时加载更新。

其他Android的踩坑经验

Android 34崩溃问题

一开始我用的是android 30模拟器在跑都正常,后来换成android 34模拟器,直接崩溃

原因分析

我的项目原来设置 targetSdkVersion 34会崩溃,当我改成33就不崩溃了,但这方法毕竟不太好,因为应用商店是会要求 targetSdkVersion的最低版本的。

不过至少确定问题是targetSdkVersion造成的,看一下android官方说了什么

行为变更:以 Android 14 或更高版本为目标平台的应用  |  Android Developers

然后根据一番的调试追踪,最后在 react-native:0.68.1 中的 DevSupportManagerBase.java 里的 reload() 方法看到问题的关键。

他这里注册广播时,没有指定 flags,就是这里造成的崩溃。

解决办法

我在我的RNActivity中,设置 DevSupportManagerFactory 成我自己继承重写的 MyFactory

这个 MyFactory,就是继承自DefaultDevSupportManagerFactory,重写了 create方法,设置传入我自定的 MyContext

在MyContext中,重写了registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) 方法,使其在新版本中传入 flags

如此,崩溃问题得解。

注:其实这算是治标的方法,react-native:0.68.1的targetSdkVersion是31,真正治本的方法是找一个targetSdkVersion 34的新RN版本。

Cloud not connect to development server.

解决了崩溃问题,我的android 34还是出不来正常画面,而是出现了一个大大的红屏

我换成真机也是这样,以经确认的在浏览器中输入我的电脑ip:8081是能正常访问的,不是网络问题。

产生原因

安装的app没有设置服务器和端口号。

ReactNative环境搭建扩展篇——安装后报错解决方案-腾讯云开发者社区-腾讯云

解决办法

在真机上摇一摇,会弹出下面这个菜单

设置完后就能正常显示页面了

模拟器无法摇一摇?

用adb输入菜单键

adb shell input keyevent 82

输入完模拟器就弹菜单了,接下来同样操作即可

项目打包

官方文档说,如果使用了React Native Gradle Plugin,按正常打包就可以了。但是我们没使用插件,需要输入指令生成离线的 jsbundle 文件,官方给的命令如下:

npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/

在RN项目目录直接这么输入肯定是不行的,因为里面的 com/your-company-name/app-package-name 需要替换成你实际的项目目录,例如我的打包指令如下:

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

注:输入命令前,需自己先手动建好assets目录

执行完命令后,会在assets下生成index.android.bundle 文件

然后,按正常流程打包,安装,运行,就能看到成功的画面了。

打包调试

每次更新 jsbundle后,都要打包看效果,这样效率太低了。

在 RNActivity 的 ReactInstanceManager.builder 中有一个 setUseDeveloperSupport 方法,官方的代码是写 .setUseDeveloperSupport(BuildConfig.DEBUG)。开发调试阶段是true,面板就会先找电脑的8081服务,打包后是false,面板就会优先找assets目录。如果是要在开发阶段测试 index.android.bundle 包的效果,直接在这里传入false即可。

热更新初版

如果只是更新 assets 中的 jsbundle 文件重新打包,就无法充分利用RN可以热更新的特性了。

RN的热更新,官方文档已有给出解决方案 pushy。

热更新其实完全可以不依赖第三方来实现,自己实现也能更了解RN项目的架构原理,我主要参考下面这篇:

https://www.jianshu.com/p/b4b58dc93ac9

实现流程

把上一步生成的 index.android.bundle放到服务器上。

APP下载这个文件到本机,我是下载到 Context.getCacheDir() 得到的缓存目录 data/data/包名/cache,你也可以下载到手机的其他地方,只是用这个缓存不需要申请另外的权限。

在RNActivity的 ReactInstanceManager.builder 透过setJSBundleFile设置jsbundle的档案路径 ,例如我的就是 data/data/包名/cache/index.android.bundle

接下来运行看看,是不是把缓存区的那个jsbundle的内容显示出来了。

注:setBundleAssetName是设置读assets目录的,setJSBundleFile是设置读其他外部目录的。这两方法会互相覆盖,如果先设setJSBundleFile后又设setBundleAssetName,这样最后读的还是assets里的那个。所以需确保setJSBundleFile在setBundleAssetName之后调用,或是设了setJSBundleFile就不设setBundleAssetName。你可以让assets中的jsbundle跟服务器上的jsbundle显示不同内容,以确定你显示的到底是那一个。

图片的处理方法

一个完整的页面,怎么少的了图片呢?下面我就说明图片的打包处理方法。

先在我的rn项目创建一个res文件夹,文件夹内放上我用显示的图片。

这里我放了名为 ic_play_arrow_333_32dp.png的两张图片。@2x @3x表示是这张图片的2倍图,3倍图。这个是iOS的机制,android就是drawable-xdpi与xxdpi的意思。app会根据手机分辨率自动选择合适尺寸的图片来使用。

然后在index.js加上Image显示这张图片

然后用npx react-native bundle …这条命令打包,打包完成后,可以看到这两张图片已经自动归到drawable-xdpi及drawable-xxdpi了,并且档名前还加了res_ 的文件夹名称

带图片的热更新

我们在之前的热更新时,已经将index.android.bundle下载到缓存目录了。RN如果读取的是这个jsbundle时,要如何能找到图片呢?

其实,就是将drawable相关的文件夹,放到跟jsbundle的同级目录下即可。

为了简单起见,我将我的升级包做成一个zip,里面就是jsbundel以及drawable等文件夹(直接从打包的项目复制过来)。

然后,把这个MyReactNativeApp.zip放到服务器,下载到缓存区后解压

如此,就实现了简单的热更新了

下面是我自己实现的源码

RNDemo: 本项目是我个人新接触RN(React Native)开发,自己写的一个Demo。

我加上了一个 rn_version.json ,里面记录了RN包的版本信息,可以让APP判断目前缓存的RN包是否是最新版本,如果有新版本才需要重新下载。以及加上了md5验证RN包的完整性等。

后续,可以继续优化这个热更新的机制。例如:将jsbundle与图片资源分离,分开不同的版本来管理。又或是其他手段来优化(例如:BSDiff)。

总之,目的就是让用户在热更新时可以下载尽量少的数据,以达到更好的用户体验。只要了解了基本原理,后续要怎么优化都可以。

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
rn和flutter都是目前非常流行的移动应用开发框架。 React NativeRN)是Facebook推出的一种开源框架,它运用了Facebook自家的React框架,能够基于JavaScript创建原生的移动应用。RN的优势在于它可以使用一套代码同时在iOS和Android平台上运行,大大减少了开发者的工作量。此外,RN还提供了丰富的组件库和强大的社区支持,使开发者能够快速搭建漂亮、高效的移动应用。 相较之下,Flutter是Google推出的开源框架,它使用Dart语言进行开发。Flutter通过自定义的渲染引擎绘制UI,可以创建高性能且美观的跨平台移动应用。Flutter具有热重载功能,使开发过程更加迅速和便捷。同时,Flutter提供了丰富的组件库和通用的API,使开发者能够轻松创建各种复杂的用户界面。 然而,RN和Flutter也存在一些不同之处。RN使用JavaScript进行开发,而Flutter使用Dart语言,这意味着开发者需要学习不同的编程语言。另外,RN采用的是原生组件的渲染方式,而Flutter则是通过自定义渲染引擎进行绘制。这一差异导致Flutter在性能和用户体验方面更具优势,但对于复杂界面和特定平台功能的需求,RN可能更加灵活。 综上所述,RN和Flutter都是优秀的移动应用开发框架,具有各自的优点和适用场景。开发者可以根据项目需求、个人技能和团队资源来选择适合的框架。无论选择哪个,都能够高效地开发出高质量的移动应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值