🥳📱 如果 Expo 预览能像 Vercel 部署一样丝滑该多好?🫰
Expo 是一个开源框架,用于使用 React 开发通用的原生应用程序。它支持在 Android、iOS 和 Web 平台上运行。
Vercel 是一个云平台,专为前端开发者设计,用于托管和部署 Jamstack 网站和应用程序。它提供了从开发到生产的无缝工作流程,支持自动化部署、全球 CDN 分发、以及与 Git 仓库的集成,适用于使用 React、Vue、Next.js 等框架的项目。
如果你用过 Vercel 的预览部署,你就知道那种神奇的感觉:提交 PR,瞬间就能获得一个可以分享的在线链接。无需手动部署,无需等待。
如果我们能为 Expo 移动应用也实现这样无缝的体验,岂不是很棒?
这正是我们所构建的。通过一个简单的 GitHub Action,现在每个 PR 都会自动生成一个 Expo 二维码,让你能够像 Vercel 一样在手机上即时预览变更!
最棒的是?**设置过程不到一分钟!**⏳
让我们开始吧 👇
🔧 第一步:添加必需的 GitHub Secrets
要实现这个功能,我们需要两个令牌来与 Expo 和 GitHub 进行认证。
1️⃣ 创建 GitHub 个人访问令牌(GH_PAT)
-
点击 "生成新令牌(经典)"
-
设置过期时间(选择较长的时间以避免频繁更新)
-
选择以下权限范围:
-
✅
repo(私有仓库的完全控制权限) -
✅
workflow(允许 GitHub Actions 访问工作流) -
✅
read:packages(如果你使用私有 npm 包)
-
-
点击 "生成令牌" 并复制它
-
进入你的 GitHub 仓库 → 设置 → Secrets
-
添加一个名为
GH_PAT的新密钥并粘贴令牌
2️⃣ 创建 Expo 令牌(EXPO_TOKEN)
你可以直接在 Expo 项目设置中创建这个令牌:
-
打开 Expo.dev
-
进入 账户设置 → 访问令牌
-
点击 "生成新令牌"
-
复制令牌并将其添加为名为
EXPO_TOKEN的 GitHub Secret
🛠️ 第二步:添加用于 Expo 预览的 GitHub Action
现在我们有了令牌,需要设置 GitHub Actions:
-
在你的仓库中创建新文件:
.github/workflows/expo-preview.yml -
复制并粘贴以下 GitHub Actions 工作流:
name: Expo 预览二维码
on:
pull_request:
types: [opened, synchronize]
jobs:
preview:
runs-on: ubuntu-latest
permissions:
pull-requests: write
timeout-minutes: 15
steps:
- name: 🏗 设置代码仓库
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
- name: 🏗 设置 Node 环境
uses: actions/setup-node@v4
with:
node-version: 22.x
- name: 📦 缓存依赖
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: 📦 安装依赖
run: npm install
continue-on-error: true
id: npm_install
- name: 📦 重试安装依赖
if: steps.npm_install.outcome == 'failure'
run: |
rm -rf node_modules
npm cache clean --force
npm install --no-cache
- name: 🏗 设置 EAS
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: 🚀 创建预览并提取详细信息
id: create-preview
continue-on-error: true
run: |
OUTPUT=$(eas update --auto --branch ${{ github.event.pull_request.head.ref }})
echo "$OUTPUT"
# 提取更新组ID (groupId)
GROUP_ID=$(echo "$OUTPUT" | grep -oP 'Update group ID\s+\K[\w-]+')
# 提取 EAS 仪表盘 URL
EAS_DASHBOARD_URL=$(echo "$OUTPUT" | grep -oP 'EAS Dashboard\s+\Khttps://expo.dev/accounts/[^ ]+')
# 动态解析账户名和项目标识
ACCOUNT_NAME=$(echo "$EAS_DASHBOARD_URL" | awk -F'/' '{print $(NF-3)}')
PROJECT_SLUG=$(echo "$EAS_DASHBOARD_URL" | awk -F'/' '{print $(NF-1)}')
# 使用 `eas project:info` 获取正确的 appId
echo "正在获取 EAS 项目信息..."
PROJECT_INFO=$(eas project:info)
echo "EAS 项目信息输出:$PROJECT_INFO"
# 使用 grep 提取 appId
APP_ID=$(echo "$PROJECT_INFO" | grep -oP 'ID\s+\K[\w-]+')
# 从提交时间戳提取最后更新时间
COMMIT_TIMESTAMP=$(echo "$OUTPUT" | grep -oP 'Commit\s+\K[\w\d]+')
# 转换时间戳为可读的 UTC 格式
LAST_UPDATED=$(date -u -d "@$(git show -s --format=%ct $COMMIT_TIMESTAMP)" "+%b %-d, %Y %-I:%M%p UTC")
if [ -z "$APP_ID" ] || [ -z "$GROUP_ID" ] || [ -z "$ACCOUNT_NAME" ] || [ -z "$PROJECT_SLUG" ] || [ -z "$LAST_UPDATED" ]; then
echo "❌ 无法提取所需的值,请检查输出信息。"
exit 1
fi
DEEP_LINK="exp+://expo-development-client/?url=https://u.expo.dev/$APP_ID/group/$GROUP_ID"
UPDATE_LINK="https://expo.dev/accounts/$ACCOUNT_NAME/projects/$PROJECT_SLUG/updates/$GROUP_ID"
QR_CODE_URL="https://qr.expo.dev/eas-update?slug=exp&projectId=$APP_ID&groupId=$GROUP_ID&host=u.expo.dev&scale=2"
echo "深层链接:$DEEP_LINK"
echo "UPDATE_LINK=$UPDATE_LINK" >> $GITHUB_ENV
echo "QR_CODE_URL=$QR_CODE_URL" >> $GITHUB_ENV
echo "LAST_UPDATED=$LAST_UPDATED" >> $GITHUB_ENV
- name: 📢 在 PR 中更新或发布 Expo 二维码
if: success()
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const updateLink = process.env.UPDATE_LINK;
const qrCodeUrl = process.env.QR_CODE_URL;
const lastUpdated = process.env.LAST_UPDATED;
if (!updateLink || !qrCodeUrl || !lastUpdated) {
console.error("❌ 缺少更新链接、二维码 URL 或最后更新时间戳。");
return;
}
const { owner, repo, number } = context.issue;
const commentIdentifier = "🚀 **Expo 预览就绪!**"; // 唯一标识符
// 生成带有二维码的评论内容
const commentBody = `
🚀 **Expo 预览就绪!** — *更新时间: ${lastUpdated}*
📱 扫描下方二维码在 **Expo Dev Client** 中测试:

<a href="${updateLink}" target="_blank"><strong>打开 Expo 更新 ↗︎</strong></a>
---
📋 **调试信息**
- 分支: \`${context.payload.pull_request.head.ref}\`
- 提交: \`${context.sha}\`
- Node版本: \`22.x\`
- Expo CLI版本: \`latest\`
如遇问题,请确保已安装最新版本的 Expo Go 应用。
`
// 获取现有评论
const comments = await github.rest.issues.listComments({
owner,
repo,
issue_number: number
});
const existingComment = comments.data.find(comment =>
comment.body.includes(commentIdentifier)
);
if (existingComment) {
// 更新现有评论
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existingComment.id,
body: commentBody
});
console.info("✅ 已更新现有 Expo 预览评论。");
} else {
// 创建新评论
await github.rest.issues.createComment({
owner,
repo,
issue_number: number,
body: commentBody
});
console.info("✅ 已创建新的 Expo 预览评论。");
}
🎯 第三步:提交 PR 并获取 Expo 预览
现在,每当你提交或更新 PR 时,GitHub Actions 将:
✅ 启动 Expo 预览服务器
✅ 生成二维码
✅ 自动在 PR 中添加预览链接评论
🥳 就是这样,尽情享受你的新自动化 Expo PR 流程吧!🥳
🔍 为什么这个方案如此有效(以及我们为什么这样构建)
🔹 受 Vercel 预览功能启发
Vercel 改变了我们部署前端应用的方式。我们希望为 Expo 和 React Native 项目带来同样流畅的体验。
🔹 移动优先的协作方式
不再需要手动启动 Expo 服务器并在 Slack 中发送链接。现在每个 PR 都自带预览链接。
🔹 更快的测试,更少的麻烦
让设计师、产品经理和利益相关者进行 QA 测试和反馈变得更加容易。
⚡ 常见问题与故障排除
❌ GitHub Actions 失败?
请确保:
-
你已将
GH_PAT和EXPO_TOKEN都添加到 GitHub Secrets -
你的 Expo 账户有权限生成预览
-
尝试在本地环境中重启 Expo CLI 看看是否正常工作
❌ PR 评论中没有显示二维码?
检查 GitHub 中的 PR Actions 日志,看看 Expo 服务器是否正确启动。
❌ 仍然遇到问题?
💡 最后的思考
通过这个简单的 GitHub Action,你可以完全自动化 PR 的 Expo 预览,就像 Vercel 为网页应用所做的那样。
不再需要手动分享链接。不再需要等待他人启动 Expo 服务器。只需扫描二维码即可立即测试。