# ReactNative和js版本不一致问题分析
前言:在启动 RN 工程的时候很可能会遇到 javascript
和 react-native
版本不一致的问题,比如:
console.error: "React Native version mismatch. JavaScript version: 0.61.5 Native version: 0.55.0
其实一眼就能明白就是 js 版本和 native 版本不一致导致的,如果按照工程提示执行watchman watch-del-all && react-native start --reset-cache
." 大部分的情况会发现是没有效果的;本文将从如何解决此问题,以及此问题发生的原因两个方面剖析,
废话不多说,先告诉你方案;
# 一、解决方案
通过谷歌发现了有如下几种解决方案:
- 将
native
版本更新到和js
版本一致并重新npm install
;(tips: 如果已经一致了,请看下面的方案)
修改
android/app/build.gradle
下面的implementation "com.facebook.react:react-native:+"
为指定的版本implementation ('com.facebook.react:react-native:0.61.5') { force = true }
// 0.61.5 处变为自己的 JS 工程中的相应版本号
- 关闭所有和
react-native
相关的终端,重新在当前目录启动npm run start
或者react-native run-android
;
原因分析:在运行项目之前,可能本地 node 服务中已经运行了另外一个 RN 项目,而另外那个项目的 js 版本为 0.55.0,要运行的项目 js 版本为 0.61.5。所以就引发了上面的错误。解决办法就是关闭 node 服务,重新运行项目就可以了(react-native run-android 命令启动项目时,如果 node 服务没有启动,会自动启动)node 服务中不能同时运行不同 js 版本的项目。
- 清空
react-native
的缓存,重新npm install
或者yarn
# 缓存清除
rm -rf ~/.rncache
rm package-lock.json
sudo rm $TMPDIR/*
sudo rm -rf $TMPDIR/*
watchman watch-del-all
watchman watch-del-all
rm yarn.lock
rm -rf node_modules/
rm -rf ios/build
# 重新install
npm install
- 如果上述三种方法还存在问题,请查看自己的宿主工程
react-native
的版本是否和当前工程的版本一致此种情况比较特殊:可能你当前运行的 jsbundle 是动态加载的,其宿主工程本身就是一个
react-native
的项目,而宿主工程的版本是 0.55.0 那么新工程如果使用 0.61.5 则 还是会报错 native 的版本不一致
# 二、react-native
版本检查分析
# 1、寻找报错位置
通过搜索关键字 React Native version mismatch
可以发现检测的最终代码在 Libraries/Core/ReactNativeVersionCheck.js
中:
import Platform from "../Utilities/Platform";
const ReactNativeVersion = require("./ReactNativeVersion");
exports.checkVersions = function checkVersions(): void {
const nativeVersion = Platform.constants.reactNativeVersion;
if (
ReactNativeVersion.version.major !== nativeVersion.major ||
ReactNativeVersion.version.minor !== nativeVersion.minor
) {
console.error(
`React Native version mismatch.\n\nJavaScript version: ${_formatVersion(
ReactNativeVersion.version
)}\n` +
`Native version: ${_formatVersion(nativeVersion)}\n\n` +
"Make sure that you have rebuilt the native code. If the problem " +
"persists try clearing the Watchman and packager caches with " +
"`watchman watch-del-all && react-native start --reset-cache`."
);
}
};
查看源码可以发现其JavaScript version
主要来源于ReactNativeVersion.version
而 Native 版本来自于Platform.constants.reactNativeVersion
判断版本是否一致主要是看以上两个是否匹配。
# 2、ReactNativeVersion.version
在同目录下存在一个ReactNativeVersion.js
文件,
exports.version = {
major: 0, //主版本
minor: 61, //小版本
patch: 5, //补丁
prerelease: null,
};
# 3、Platform.constants.reactNativeVersion
可以在Utilities
目录中找到,Platform.android.js
;
//关键内容在
get constants() {
if (this.__constants == null) {
this.__constants = NativePlatformConstantsAndroid.getConstants();
}
return this.__constants;
},
并同步找到NativePlatformConstantsAndroid
文件
import type {TurboModule} from '../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|
isTesting: boolean,
reactNativeVersion: {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|},
Version: number,
Release: string,
Serial: string,
Fingerprint: string,
Model: string,
ServerHost: string,
uiMode: string,
|};
+getAndroidID: () => string;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'PlatformConstants',
): Spec);
查看得知reactNativeVersion
是通过 TurboModuleRegistry.getEnforcing('PlatformConstants')
获取到的;在工程下全局搜索PlatformConstants
得知:
在/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java
文件中可以看到reactNativeVersion
是通过
ReactNativeVersion.VERSION
得到的
@Override
public @Nullable Map<String, Object> getConstants() {
HashMap<String, Object> constants = new HashMap<>();
constants.put("Version", Build.VERSION.SDK_INT);
constants.put("Release", Build.VERSION.RELEASE);
constants.put("Serial", Build.SERIAL);
constants.put("Fingerprint", Build.FINGERPRINT);
constants.put("Model", Build.MODEL);
if (ReactBuildConfig.DEBUG) {
constants.put("ServerHost", getServerHost());
}
constants.put(
"isTesting", "true".equals(System.getProperty(IS_TESTING)) || isRunningScreenshotTest());
constants.put("reactNativeVersion", ReactNativeVersion.VERSION);
constants.put("uiMode", uiMode());
return constants;
}
在与AndroidInfoModule
同目录下存在 ReactNativeVersion.java
public class ReactNativeVersion {
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
"major", 0,
"minor", 61,
"patch", 5,
"prerelease", null);
}
可以看出,
Platform.constants.reactNativeVersion
是在java
侧定义的,最终在原生代码中,我们在build.gradle
文件中引用的com.facebook.react:react-native:+
则包含了这部分代码。
# 4、js 和 java 的版本在哪里设置?
可以看出,在 js
侧有个版本号,同时在 java
侧也有个版本号,两者会在启动的时候进行判断,如果不相同就会抛出错误。
js
和 java
是两个依赖,js
部分在 package.json
中进行依赖,java
部分在 android/app/build.gradle
中依赖,两者必须匹配才能很好的工作,所以有了上述的检查工作
# 5、项目初始化之后版本号如何自动设置
查看 RN 源码得知,java 端的版本的模板在scripts/versiontemplates/ReactNativeVersion.java.template (opens new window)中,通过执行scripts/bump-oss-version.js (opens new window)将版本号注入到模板中
fs.writeFileSync(
"ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java",
cat("scripts/versiontemplates/ReactNativeVersion.java.template")
.replace("${major}", major)
.replace("${minor}", minor)
.replace("${patch}", patch)
.replace(
"${prerelease}",
prerelease !== undefined ? `"${prerelease}"` : "null"
),
"utf-8"
);
同理 js 的版本的模板在scripts/versiontemplates/ReactNativeVersion.js.template (opens new window)中,并通过 scripts/bump-oss-version.js (opens new window)替换
fs.writeFileSync(
"Libraries/Core/ReactNativeVersion.js",
cat("scripts/versiontemplates/ReactNativeVersion.js.template")
.replace("${major}", major)
.replace("${minor}", minor)
.replace("${patch}", patch)
.replace(
"${prerelease}",
prerelease !== undefined ? `'${prerelease}'` : "null"
),
"utf-8"
);
# 总结
在开发环境,RN 启动阶段,会对 js 和 java 两边的版本号进行比较,匹配后才开始真正的系统启动流程。这么设计的原因很可能是和 RN 版本原因;因为 RN 版本更新比较快,很多代码及 API 都是和版本相关的; 保持版本一直的好处可以避免很多因为版本不一致导致的兼容性问题。
- 本文链接: https://mrgaogang.github.io/react/ReactNative%E5%92%8Cjs%E7%89%88%E6%9C%AC%E4%B8%8D%E4%B8%80%E8%87%B4%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90.html
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明出处!