客户端设置
设置密钥
密钥这部分我没实测,如果遇到问题还是参考官方文档
代码签名允许开发人员使用自己的密钥对更新进行加密签名。然后在应用更新之前在客户端上验证签名,这确保 ISP、CDN、云提供商甚至 EAS 本身无法篡改应用程序运行的更新。
npx expo-updates codesigning:generate --key-output-directory keys --certificate-output-directory certs --certificate-validity-duration-years 10 --certificate-common-name "My App"
会生成:
- expo-updates-client/certs/certificate.pem
- expo-updates-client/keys/private-key.pem
- expo-updates-client/keys/public-key.pem
npx expo-updates codesigning:configure --certificate-input-directory certs --key-input-directory keys
修改客户端的app.json的updates字段:
"updates": {
"url": "http://<你的ip>:3000/api/manifest",
"enabled": true,
"fallbackToCacheTimeout": 0,
"codeSigningCertificate": "./certs/certificate.pem",
"codeSigningMetadata": {
"keyid": "main",
"alg": "rsa-v1_5-sha256"
}
},
把生成的私钥上传到服务器,并修改服务端的环境变量,指向private-key .env.local
PRIVATE_KEY_PATH=code-signing-keys/private-key.pem
客户端设置
编译出一个apk, 参考下面配置
eas init
eas build:configure
eas.json
{
"cli": {
"version": ">= 10.1.1"
},
"build": {
"development": {
"android": {
"buildType": "apk"
},
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
},
"submit": {
"production": {}
}
}
修改app.json中的 runtimeVersion 字段为 app , 当app启动时会向原生服务器发送请求,然后会去 server的 ./updates/app 里去拿到最新更新的代码,实现热更新。(所以要在updates下新建文件夹
然后编译客户端
eas build --platform android --profile development --local
并且安装到手机
服务端设置
首先要在环境变量中加入本机的ip,这样服务器在拼接assets的url才不会出错
.env.local
HOSTNAME=http://<你的ip>:3000
PRIVATE_KEY_PATH=code-signing-keys/private-key.pem
原热更新服务器的代码路径有点问题,修改 common/helper.ts 如下:
export async function getLatestUpdateBundlePathForRuntimeVersionAsync(runtimeVersion: string) {
const updatesDirectoryForRuntimeVersion = `updates/${runtimeVersion}`;
if (!fsSync.existsSync(updatesDirectoryForRuntimeVersion)) {
throw new Error('Unsupported runtime version');
}
const filesInUpdatesDirectory = await fs.readdir(updatesDirectoryForRuntimeVersion);
const directoriesInUpdatesDirectory = (
await Promise.all(
filesInUpdatesDirectory.map(async (file) => {
const fileStat = await fs.stat(path.join(updatesDirectoryForRuntimeVersion, file));
return fileStat.isDirectory() ? file : null;
})
)
)
.filter(truthy)
.sort((a, b) => parseInt(b, 10) - parseInt(a, 10));
// return path.join(updatesDirectoryForRuntimeVersion, directoriesInUpdatesDirectory[0]);
return updatesDirectoryForRuntimeVersion;
启动OTA服务器
cd expo-updates-server
yarn dev
热更新流程
假设现在要对一些UI、逻辑进行修改,修改完成后
将客户端export,这包含了js、图片、expo sdk等文件。默认导出到./dist文件夹
cd expo-updates-client
npx expo export --platform android
# 这一步就是给app.json增加了两个配置
node ./exportClientExpoConfig.js > ./dist/expoConfig.json
再把刚刚导出的内容放在服务端的updates文件夹下, updates文件夹新建个子文件夹,这里用app,也就是刚刚的runtimeVerison
scp -r ./dist/* root@<你的ip>:~/Projects/expo-updates-server/updates/1/
重启app两次,观察是否自动更新