使用expo-updates热更新的总结
做项目确实不能自己一个人埋头干,很容易被一个很小的问题给卡壳。React Native的热更新问题,我花了近一周都没完全搞定,结果同事帮忙查看,被卡的一个问题其实就是文件夹名称不对而已。
先说一下,我们的项目是Expo进行Prebuild手动打包的,我引入了expo-updates,怎么请求怎么报:{"code":"ERR_UPDATES_CHECK"} Error: Call to functionExpoUpdates.checkForUpdateAsynchas been relected.>Caused by: Failed to check forupdate 这种含糊不清的错误(注:后来发现是android端模糊,ios端会更详细)。
于是尝试npx create-expo-app my-app开空项目,发现空项目直接跑expo-updates居然不用改src下的代码就能自动进行热更新。具体参考:OTA Updates With Expo - Pagepro
然后我又尝试把项目prebuild,自行打包跑官方的热更新,其实也是能顺利跑通的(苹果我没测),需要修改些配置,具体参考:React Native OTA Updates with Expo EAS: Step-by-Step Guide & Best Practices - DEV Community
安卓苹果需加包名,runtimeVersion必须是具体版本,请求头requestHeaders得加channel-name,安卓的E:\temp\ota-app\android\app\src\main\AndroidManifest.xml也要配置channel-name(这个参数是使用expo官方热更新才需要配置)。
{
"expo": {
...
"ios": {
"bundleIdentifier": "com.caice.expoota"
},
"android": {
"bundleIdentifier": "com.caice.expoota"
},
"runtimeVersion": "1.0.0",
"updates": {
"url": "https://u.expo.dev/2b99efc1-4531-4a16-907a-90f24d20e0ad",
"enabled": true,
"fallbackToCacheTimeout": 0,
"checkAutomatically": "ON_LOAD",
"requestHeaders": {
"expo-channel-name": "preview"
}
}
}
}
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="@string/expo_runtime_version"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://u.expo.dev/2b99efc1-4531-4a16-907a-90f24d20e0ad"/>
<meta-data android:name="expo.modules.updates.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY" android:value="{"expo-channel-name":"your-channel-name"}"/>
接着是搭建本地服务,用的https://github.com/expo/custom-expo-updates-server,可是不知道哪里配的不对,连它的示例都无法正常使用。
后来用空项目跑通了,修改了两个点,一个是它创建的时间戳文件夹名在windows系统中需要由"expo-publish": "./scripts/publish.sh -d 1/$(date +%s)"改成"expo-publish": "bash -c './scripts/publish.sh -d 1/$(date +%s)'",否则会成生"$(date"这样错误的文件夹。还有一点便是里面的1,我的空项目版本号是1.0.0,而它测试用例其实那个1就是版本号,不一致的话也是跑不通的,我就是被这个问题卡了半天。还以为是chartGPT里说的生成的dist里没有android-index.json / ios-index.json,其实并不需要。chartGPT还是不能太信任,像之前还告诉我需要配置expo_updates_config.xml,也是完全错误的方向,就没有任何文档有提过这东西。
最后就是把这空项目的热更新 拿到我们正式项目里跑了。所以问题其实不在代码里,之前的Updates.checkForUpdateAsync报错完全可以无视掉,在于我们项目加了太多web端不可用的插件,而默认跑npx expo export,那些web端不兼容的牛鬼蛇神就冒出来了。并且npx expo export --platform XXX是只支持打一个端的包,连续打另一个就会把之前的清空。只要在app.json里配置platforms: ["ios", "android"],就可以做到不打web,最终成功实现热更新功能。
import * as Updates from 'expo-updates';
const checkUpdates = async () => {
// 热更新测试代码,不用浪费时间在以下代码上,alert在手机里也是可以用的
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
alert('更新可用,开始下载...');
await Updates.fetchUpdateAsync();
alert('更新下载完成,将在下次启动时生效');
// 如果需要立即重载
await Updates.reloadAsync();
} else {
alert('没有可用更新');
}
} catch (error) {
alert('检查更新失败:' + error);
}
};
总结一下,想要原本已经prebuild的expo项目跑本地服务实现热更新其实不难,具体流程如下:
- npm install expo-updates,引入上述Updates的测试代码(非初始页里也能跑,但在_layout里跑会出错)
- 参考官方文档Install expo-updates in an existing React Native project - Expo Documentation,在Android和Ios里增加相应配置
- 如有需要,可在app.json里配置platforms: ["ios", "android"],屏蔽掉web端的麻烦事
- 先gradlew assembleRelease一个apk,安装到手机上,打开APP看看,检查更新失败报错不用管
- 修改原项目中任意可见内容,用于后续热更新的测试
- 搭建本地服务expo-updates-server,把里面的“expo-updates-client”改成项目文件名,localhost改真实IP(手机能直接访问)
- 运行服务中的yarn expo-publish(特别需注意我提到的的文件夹名称问题)
- 运行服务yarn dev,让服务启动(start需要秘钥我没研究)
- 再次打开APP,它就会自动热更新了,变成修改之后的内容
我以为就此结束了,结果ios又出现问题,它没有任何的报错,所有接口都能顺利跑通,也能识别到是否真的有热更新并成功运行代码。但!它就是没有显示新内容……没有任何的异常,过程全对,却看不到结果。
代码又删改测试了半天,原来是"expo-native-wechat"的registerApp调用了原生模块与热更新产生了冲突,只要把热更新的代码setTimeout延迟执行就可行了。
更多推荐

所有评论(0)