大家好,欢迎来到IT知识分享网。
前言
本人近期才开始接触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)。
总之,目的就是让用户在热更新时可以下载尽量少的数据,以达到更好的用户体验。只要了解了基本原理,后续要怎么优化都可以。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/157830.html