RN 升级问题记录(0.59.5->0.61.5)

升级思路


因为项目自定义比较多,不适合用各类升级工具,主要参考upgrade helper提供的改动点。

遇到问题

缓存问题

缓存问题无疑是遇到最多的,这里也就不多说,无非就是清lock/删node_module/清pod/rebuild...

Installation problem zlib: unexpected end of file


解决: npm cache clean --force

重装pod,发现首次安装特别慢

发现clone https://github.com/CocoaPods/Specs特别慢,看了代码就会发现这个项目文件特别多,慢是肯定的。
解决:下载到本地,在本地做替换,注意.git文件。
具体可以看https://www.jianshu.com/p/73ba4ee54b72

pod libwebp始终不成功

libwebp下载的源是https://chromium.googlesource.com/webm/libwebp/,这个地址即便你全局翻墙也下不下来
解决方案:替换成github上的镜像源。
具体可以看https://www.jianshu.com/p/9e3eec3d8fe0

安卓gradle编译问题

build failed with: Could not find method enabled() for arguments [[]] on task ':app:bundleDebugJsAndAssets' of type org.gradle.api.tasks.Exec
task.dofirst不存在
解决:把apply from: "../../node_modules/react-native/react.gradleapply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)都放在app/build.grade中,app/build.grade中引用的子模块不要加以上两行,不然就有上述错误。
react.gradle主要是编译打包相关的,任务依赖这个app/build.grade
native_modules.gradle是用于自动导包的

AutoLink

基于上个问题,看文档才发现60+引入了autolink。
对于有native代码的第三方库,npm install 或者 yarn add之后,不需要执行react-native link XXX 了。iOS使用了cocoapods 来管理依赖,我们进入项目的iOS目录,执行pod install即可;安卓之前link完,会在setting.gradlebuild.gradleMainApplication.java三个文件添加引入,现在则都不需要了。

  • iOS中,podfile中多了一下的代码
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

use_native_modules!

看了一下native_modules源码,是一个Ruby脚本文件,就是执行pod install时,执行了这个脚本

This is a function which is used inside your Podfile.
It uses react-native config to grab a list of dependencies, and pulls out.all of the ones
which declare themselves to be iOS dependencies (via having a Podspec) and automatically
imports those into your current target.

这个脚本利用react native config这个cli命令,来抓取项目的所有依赖,然后,把有podspec文件的依赖自动的引入到cocoapods

  • Android中,
    setting.gradle文件也有了变化:
rootProject.name = 'kjkDoctor'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle");
 applyNativeModulesSettingsGradle(settings)
include ':app'

app/build.gradle最后一行多了如下代码

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

applyNativeModulesSettingsGradleapplyNativeModulesAppBuildGradle这两个gradle方法都是在native_modules中的脚本定义的
native_modules是一个gradle脚本,在/node_modules/@react-native-community 文件夹中,源码链接

  1. At build time, before the build script is run:
    1⃣️.A first Gradle plugin (in settings.gradle) runs applyNativeModulesSettingsGradle method. It uses the package metadata from react-native config to add Android projects.
    2⃣️.A second Gradle plugin (in app/build.gradle) runs applyNativeModulesAppBuildGradle method. It creates a list of React Native packages to include in the generated /android/build/generated/rn/src/main/java/com/facebook/react/PackageList.java file.
  2. At runtime, the list of React Native packages generated in step 1.2 is registered by getPackages method of ReactNativeHost in MainApplication.java.

build阶段,在build脚本运行之前,先运行了setting.gradle中的applyNativeModulesSettingsGradle方法,这个方法利用react-native config 命令,拿到package metadata,添加依赖到你的android项目中.
然后,再运行了build.gradle中的applyNativeModulesAppBuildGradle 方法,在/android/build/generated/rn/src/main/java/com/facebook/react/PackageList.java中,生成了一系列的package (之前是在mainApplication中通过new xxxPackage()),注意这个目录是android/build下的目录,是排除版本控制的。
运行阶段,MainApplication.java 中的ReactNativeHost方法会将上一步中生成的package注册到项目中,这样就达到了与之前手动link一样的效果了.
最后,还可以通过react-native.config.js来定制化处理。

AndroidX的支持

support.xx不存在
解决:升级三方库,比如我升了一下几个
lottie、netinfo、viewpager、smartrefreshlayout、code-push、reanimated、react-native-fast-image

代码调整

Android

去除重复库,删掉之前的引入,避免和autolink的重复。如果你使用 AS3.5以上的版本,本地编译会自动帮你去除重复库,如果是3.5以下则会报错,所以当时遇到很奇怪的问题就是代码明明一样,为什么有的同学跑起来了,有的报错了。
frescoVersion升到2.0+,支持webp

iOS

库升级,引用变化,如react-native-fast-image升级,要按新api调整,webp重新注册

JS

引用库的变化

import deepDiffer from "react-native/lib/deepDiffer"
->
react-native/Libraries/Utilities/differ/deepDiffer

React.unstable_Profiler
->
React.Profiler

生命周期废弃

Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

Warning: componentWillUpdate has been renamed, and is not recommended for use.

Warning: componentWillReceiveProps has been renamed, and is not recommended for use.

Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

netinfo

发现新版本从offline切到online,不会更新状态,查官方说仅是模拟器的bug,真机是好的

打包机问题

  • iOS: 在打包机配libwebp的源
  • iOS: xCode版本选择
  • android(debug): 重复库问题
  • android(release):重复资源、watch导致内存不足的问题

样式

Android不支持字重的设置

60以下版本是可以设置100-900,60之后只有normal(400)/bold(700),看issue说是官方的限制。
解决:需要使用自定义字体

未解决问题

  • iOS时常卡死
    同步问题解决进度:

    问题定位到是一直在循环处理accessiblelabel,注释掉就不卡了,最后用了个hack的方式临时解决,问题应该还是出现在使用方法上,官方Demo确实没问题
  • iOS上执行scrollTo,其实变为执行scrollToEnd
    同步问题解决进度:


    这个问题相当诡异,和iOS同学一起定位到问题是MjRefrsh这个库生成出来的调用数组并不是代码上的顺序,也就是和RCTScrollVIew的顺序不一致,导致调用错乱了。
    解决:最后发现是升级61.5,RCTScrollVIew增加了两个属性的定义,加上就解决了。这个库没人维护了,之后RN升级都要注意同步一下,最后是换个库吧。

总结

  • 过程还是很痛苦,主要是一大部分错误提示的都是无效信息,不好定位
  • 结果还是很满意的,60+对安卓提升很明显,是肉眼可见的快了很多
  • 感悟就是多学点端的知识很有必要