234 行
5.5 KiB
Markdown
234 行
5.5 KiB
Markdown
# 版本与插件更新
|
||
|
||
`@xuqm/rn-update` 提供两类能力:
|
||
|
||
- Android 整包检查、下载、安装和应用商店跳转。
|
||
- 可选的 RN 插件检查、安装和启动。
|
||
|
||
SDK 返回更新信息和当前网络状态,是否弹窗、是否允许使用移动网络以及何时开始下载由宿主
|
||
决定。
|
||
|
||
## 整包更新
|
||
|
||
### 检查
|
||
|
||
```ts
|
||
import { UpdateSDK } from '@xuqm/rn-update'
|
||
|
||
const result = await UpdateSDK.checkAppUpdate()
|
||
|
||
switch (result.status) {
|
||
case 'UPDATE_AVAILABLE':
|
||
showUpdateDialog(result.update, result.network)
|
||
break
|
||
case 'LOGIN_REQUIRED':
|
||
case 'SERVICE_DISABLED':
|
||
case 'NO_UPDATE':
|
||
// 正常跳过,不阻断应用
|
||
break
|
||
case 'FAILED':
|
||
// 记录一次非阻断诊断
|
||
console.warn(result.errorCode, result.message)
|
||
break
|
||
}
|
||
```
|
||
|
||
检查状态:
|
||
|
||
| 状态 | 宿主建议 |
|
||
| --- | --- |
|
||
| `UPDATE_AVAILABLE` | 根据 `forceUpdate` 展示宿主自己的更新弹窗 |
|
||
| `NO_UPDATE` | 继续启动 |
|
||
| `LOGIN_REQUIRED` | 未登录时跳过,登录后可再次检查 |
|
||
| `SERVICE_DISABLED` | 服务未启用,继续运行 |
|
||
| `FAILED` | 记录诊断,不阻断宿主 |
|
||
|
||
`result.network` 包含连接类型、是否已连接和是否按流量计费。租户平台不替宿主配置网络
|
||
策略。
|
||
|
||
### 下载并安装
|
||
|
||
用户确认后调用:
|
||
|
||
```ts
|
||
await UpdateSDK.downloadAndInstallApp(result.update!, {
|
||
destination: 'SDK_PRIVATE',
|
||
onProgress(progress) {
|
||
setProgress(progress.percent)
|
||
},
|
||
})
|
||
```
|
||
|
||
需要把安装包保留在系统 Downloads:
|
||
|
||
```ts
|
||
await UpdateSDK.downloadAndInstallApp(result.update!, {
|
||
destination: 'PUBLIC_DOWNLOADS',
|
||
})
|
||
```
|
||
|
||
下载失败或应用退出后不会在下次启动时自动继续。
|
||
|
||
### 只下载、稍后安装
|
||
|
||
```ts
|
||
import { NativeAppUpdate, UpdateSDK } from '@xuqm/rn-update'
|
||
|
||
const downloaded = await UpdateSDK.downloadApk(result.update!, {
|
||
destination: 'SDK_PRIVATE',
|
||
})
|
||
|
||
console.log(downloaded.localPath)
|
||
|
||
await NativeAppUpdate.installDownloaded({
|
||
versionCode: result.update!.versionCode!,
|
||
sha256: result.update!.sha256,
|
||
})
|
||
```
|
||
|
||
取消当前下载:
|
||
|
||
```ts
|
||
await NativeAppUpdate.cancel()
|
||
```
|
||
|
||
如果系统禁止安装未知来源应用:
|
||
|
||
```ts
|
||
await NativeAppUpdate.openInstallPermissionSettings()
|
||
```
|
||
|
||
### 跳转应用商店
|
||
|
||
宿主不传商店地址,只传检查接口返回的更新对象:
|
||
|
||
```ts
|
||
const opened = await UpdateSDK.openStore(result.update!)
|
||
```
|
||
|
||
Android 会优先打开当前设备对应的应用商店,不可用时使用平台提供的通用下载页。iOS 或
|
||
HarmonyOS 没有配置商店地址时返回 `false`,宿主应提示当前无法提供下载服务。
|
||
|
||
### 忽略可选版本
|
||
|
||
```ts
|
||
await UpdateSDK.ignoreAppVersion(result.update!.versionCode!)
|
||
const ignoredVersion = await UpdateSDK.getIgnoredAppVersion()
|
||
await UpdateSDK.clearIgnoredAppVersion()
|
||
```
|
||
|
||
强制更新不能被忽略。
|
||
|
||
## 不启用插件化
|
||
|
||
普通项目可以只使用上述整包更新 API,不创建 `common/app/buz` 模块,也不需要接入插件
|
||
运行时。后续需要插件化时再执行初始化命令即可。
|
||
|
||
## 启用插件化
|
||
|
||
在项目根目录执行交互式初始化:
|
||
|
||
```bash
|
||
pnpm exec xuqm-rn init
|
||
pnpm run xuqm:doctor
|
||
```
|
||
|
||
初始化工具会创建 `xuqm.modules.json`、补充必要脚本并提示宿主完成最少原生配置。不要
|
||
手工复制其他项目的模块表。
|
||
|
||
Metro 使用:
|
||
|
||
```js
|
||
const { getDefaultConfig } = require('@react-native/metro-config')
|
||
const { withXuqmModuleConfig } = require('@xuqm/rn-update/metro')
|
||
|
||
module.exports = withXuqmModuleConfig(getDefaultConfig(__dirname))
|
||
```
|
||
|
||
Android 宿主应用一次构建脚本:
|
||
|
||
```groovy
|
||
apply from: file("../../node_modules/@xuqm/rn-update/android/xuqm-bundles.gradle")
|
||
```
|
||
|
||
### 注册宿主运行时
|
||
|
||
```ts
|
||
import { XuqmRuntime } from '@xuqm/rn-update'
|
||
|
||
XuqmRuntime.configure({
|
||
plugins: pluginRegistrations,
|
||
context: {
|
||
navigate(route, params) {
|
||
navigationRef.navigate(route, params)
|
||
},
|
||
emit(event, payload) {
|
||
hostEvents.emit(event, payload)
|
||
},
|
||
getHostState() {
|
||
return appStore.getState()
|
||
},
|
||
},
|
||
async loadBundle(_moduleId, bundlePath) {
|
||
await loadNativeBundle(bundlePath)
|
||
},
|
||
})
|
||
```
|
||
|
||
模块入口注册:
|
||
|
||
```ts
|
||
import { definePlugin } from '@xuqm/rn-update'
|
||
|
||
definePlugin({
|
||
moduleId: 'orders',
|
||
activate(context) {
|
||
context.navigate('OrdersHome')
|
||
},
|
||
})
|
||
```
|
||
|
||
### 检查与安装插件
|
||
|
||
自动完成检查和安装:
|
||
|
||
```ts
|
||
const plan = await UpdateSDK.checkAndInstallPlugin('orders', {
|
||
onProgress(moduleId, progress) {
|
||
console.log(moduleId, progress.percent)
|
||
},
|
||
})
|
||
|
||
await XuqmRuntime.activate('orders', {
|
||
reloadBundle: plan !== null,
|
||
})
|
||
```
|
||
|
||
宿主需要先展示确认弹窗时:
|
||
|
||
```ts
|
||
const plan = await UpdateSDK.checkPluginRelease('orders')
|
||
|
||
if (plan && (await showPluginUpdateDialog(plan))) {
|
||
await UpdateSDK.installPluginRelease(plan)
|
||
}
|
||
```
|
||
|
||
只检查不会下载或修改本地状态。插件检查失败时,宿主应继续打开已有的本地健康版本。
|
||
|
||
## 启动策略
|
||
|
||
- 启动时先检查整包更新。
|
||
- 不需要整包更新时,再检查 App 插件。
|
||
- 业务插件在进入前分别检查。
|
||
- Debug 默认不自动检查;开发页可以显式使用 `UpdateSDK.developer` 下的测试入口。
|
||
- 更新 SDK 不绘制业务弹窗,所有提示和确认交互由宿主实现。
|
||
|
||
## 打包与发布
|
||
|
||
初始化生成的脚本支持 Debug、Release、插件构建和上传。发布令牌只通过 CI 环境变量
|
||
`XUQM_API_TOKEN` 注入,不写入项目配置、源码或产物。
|
||
|
||
SDK 自身制品发布与应用/插件发布是不同操作。应用开发者不需要发布 SDK,也不得把 SDK
|
||
发布凭据加入宿主工程。
|