# Expo 热更新接入：使用 Pakta 发布 OTA

配置根布局、渠道和 Release 构建，再发布第一条更新。

## 选择 Expo 热更新工作流 {#update-workflow}

本指南使用 Pakta 的 `rn-update` 客户端与 `pakta` CLI 发布 Expo OTA 更新。如果你正在比较 `expo-updates` 和 EAS Update，先阅读 [Expo Updates 与 Pakta 对比](/docs/expo-updates-vs-pakta)。从其他 OTA 客户端迁移需要新的原生构建，并让一个系统负责加载 bundle。

## 准备 {#before}

本页适用于 Expo 原生 App，不能在 Expo Go 中验证。iOS 自动接入按本项目 Pods 配置要求使用 Expo 50 或以上；保留项目现有的 Expo/RN 版本组合。

先在项目根目录安装并选择应用：

```bash
npx expo install rn-update
npm install -g rn-update-cli
pakta login
pakta selectApp --platform android
```

没有应用时先到控制台创建，或执行 `pakta createApp --platform android --name ExpoDemo`。iOS 同样选择对应的 `ios` 应用。

## 包住根布局 {#layout}

使用 Expo Router 时，在已有 `app/_layout.tsx` 中加入 Provider。下面是仅含 Stack 的最小例子，已有主题、字体加载、登录逻辑都保留：

```tsx title="app/_layout.tsx"
import { Stack } from 'expo-router';
import { Platform } from 'react-native';
import { Pakta, UpdateProvider } from 'rn-update';
import updateConfig from '../update.json';

const configs = updateConfig as Record<string, { appKey: string }>;
const appKey = configs[Platform.OS]?.appKey;
if (!appKey) throw new Error(`Missing appKey for ${Platform.OS}`);

const client = new Pakta({ appKey, updateStrategy: 'silentAndLater' });

export default function RootLayout() {
  return (
    <UpdateProvider client={client}>
      <Stack />
    </UpdateProvider>
  );
}
```

若布局在 `src/app/_layout.tsx`，把 JSON 导入改成 `../../update.json`。没有 Expo Router 的项目按[普通根组件接入](/docs/integration#basic)处理。

## 可选：配置渠道 {#channel}

只用 `default` 时跳过本节。自定义渠道先在控制台[创建渠道](/docs/channels#manage)。`rn-update` 已内置 Config Plugin，不要创建本地插件。

将下面配置加入现有 `app.json` 的 `expo.plugins` 数组：

```json title="app.json · 合并到现有配置"
{
  "expo": {
    "plugins": [
      ["rn-update", { "channel": "staging" }]
    ]
  }
}
```

`channel` 会同时写入 Android Manifest 和 iOS `Info.plist`。不同平台使用不同渠道时，使用不同构建配置分别设置 `channel`；`default` 不需要此配置。

## 构建并检查 {#build}

运行 `npx expo prebuild`，检查生成的 Android Manifest 或 iOS Info.plist 中 `channel` 的值。EAS Build 会执行同一插件。

```bash title="Android"
npx expo run:android --variant release
```

```bash title="iOS · macOS"
npx expo run:ios --configuration Release
```

使用 EAS production 构建流程也可以。热更新必须在 Release App 中验证。

## 上传并发布 {#publish}

1. 保留设备安装的同一份 APK / IPA，用 `uploadApk` / `uploadIpa` 上传；见[登记安装包](/docs/publish#register-native)。
2. 改一处页面文字，再生成更新包：

```bash
pakta bundle --platform android --expo --output .pakta/output/android.ppk --no-interactive
```

3. 按[首次发布](/docs/publish#publish)发布，渠道和版本填写解析安装包得到的值。
4. 在已安装的 Release App 中检查、等待下载、完全关闭再启动，确认文字改变。

iOS 使用 `--platform ios` 和自己的输出路径。修改原生插件、渠道或 SDK 原生代码后，要重新构建安装包，不能只发 `.ppk`。
