expo:不使用eas云服务,搭建热更新(很详细)

868 阅读2分钟

仓库地址:github.com/expo/custom…

客户端设置

设置密钥

密钥这部分我没实测,如果遇到问题还是参考官方文档

参考:docs.expo.dev/eas-update/…

代码签名允许开发人员使用自己的密钥对更新进行加密签名。然后在应用更新之前在客户端上验证签名,这确保 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两次,观察是否自动更新