Skip to content

Commit ebd1794

Browse files
safe1ineclaude
andcommitted
ci: 新增 Android APK 自动打包并发布到 GitHub Release
- tag 触发时构建 APK 并发布到 GitHub Release - 手动触发时仅上传 Artifact 便于调试 - 默认输出 debug APK,配置 KEYSTORE_BASE64 等 Secrets 后自动切换 release 签名 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0fa0392 commit ebd1794

1 file changed

Lines changed: 168 additions & 0 deletions

File tree

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# 打 tag(如 v1.2.3)后自动构建 Android APK,并发布到 GitHub Release。
2+
# 手动运行 workflow 仅上传 Actions Artifact,不创建 Release(便于试打)。
3+
# 默认产出 debug APK(无需签名配置);
4+
# 配置 KEYSTORE_BASE64 等 Secrets 后自动切换为 release 签名 APK。
5+
6+
name: Mobile Release
7+
8+
on:
9+
push:
10+
tags:
11+
- "v*"
12+
workflow_dispatch:
13+
14+
permissions:
15+
contents: write
16+
17+
concurrency:
18+
group: mobile-release-${{ github.ref }}
19+
cancel-in-progress: true
20+
21+
env:
22+
NODE_VERSION: "20"
23+
JAVA_VERSION: "17"
24+
25+
jobs:
26+
android:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v4
30+
31+
# ── Node / pnpm ──────────────────────────────────────────────────────
32+
- uses: pnpm/action-setup@v4
33+
with:
34+
version: 9
35+
36+
- uses: actions/setup-node@v4
37+
with:
38+
node-version: ${{ env.NODE_VERSION }}
39+
cache: pnpm
40+
cache-dependency-path: frontend/pnpm-lock.yaml
41+
42+
# ── Java(Android 构建需要)──────────────────────────────────────────
43+
- uses: actions/setup-java@v4
44+
with:
45+
distribution: temurin
46+
java-version: ${{ env.JAVA_VERSION }}
47+
48+
# ── 设置版本号 ────────────────────────────────────────────────────────
49+
- name: Set version
50+
shell: bash
51+
working-directory: mobile
52+
run: |
53+
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
54+
V="${GITHUB_REF_NAME#v}"
55+
else
56+
V=$(node -p "require('../frontend/package.json').version")
57+
fi
58+
echo "APP_VERSION=$V" >> $GITHUB_ENV
59+
# 同步写入 mobile/package.json
60+
node -e "
61+
const fs=require('fs');
62+
const p='package.json';
63+
const j=JSON.parse(fs.readFileSync(p,'utf8'));
64+
j.version=process.argv[1];
65+
fs.writeFileSync(p,JSON.stringify(j,null,2)+'\n');
66+
" "$V"
67+
# 将版本号写入 Android versionName(versionCode 用 build 号)
68+
BUILD_NUMBER="${{ github.run_number }}"
69+
sed -i "s/versionCode .*/versionCode $BUILD_NUMBER/" android/app/build.gradle
70+
sed -i "s/versionName .*/versionName \"$V\"/" android/app/build.gradle
71+
72+
# ── 编译前端 ──────────────────────────────────────────────────────────
73+
- name: Install frontend dependencies
74+
working-directory: frontend
75+
run: pnpm install --frozen-lockfile
76+
77+
- name: Build frontend
78+
working-directory: frontend
79+
run: pnpm run build
80+
81+
# ── 安装 Capacitor CLI & 同步 Web 资源到 Android ─────────────────────
82+
- name: Install mobile dependencies
83+
working-directory: mobile
84+
run: pnpm install --frozen-lockfile
85+
86+
- name: Capacitor sync
87+
working-directory: mobile
88+
run: pnpm exec cap sync android --no-build
89+
90+
# ── 签名配置(可选)──────────────────────────────────────────────────
91+
# 在仓库 Settings → Secrets 中配置以下变量即可启用 release 签名:
92+
# KEYSTORE_BASE64 keystore 文件的 base64 编码
93+
# KEYSTORE_PASSWORD keystore 密码
94+
# KEY_ALIAS key alias
95+
# KEY_PASSWORD key 密码
96+
- name: Setup release signing
97+
if: ${{ secrets.KEYSTORE_BASE64 != '' }}
98+
shell: bash
99+
run: |
100+
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > mobile/android/app/release.keystore
101+
cat >> mobile/android/app/build.gradle <<'EOF'
102+
103+
android {
104+
signingConfigs {
105+
release {
106+
storeFile file('release.keystore')
107+
storePassword System.getenv('KEYSTORE_PASSWORD')
108+
keyAlias System.getenv('KEY_ALIAS')
109+
keyPassword System.getenv('KEY_PASSWORD')
110+
}
111+
}
112+
buildTypes {
113+
release {
114+
signingConfig signingConfigs.release
115+
}
116+
}
117+
}
118+
EOF
119+
env:
120+
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
121+
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
122+
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
123+
124+
# ── Gradle 构建 APK ───────────────────────────────────────────────────
125+
- name: Grant Gradle execute permission
126+
run: chmod +x mobile/android/gradlew
127+
128+
- name: Build APK
129+
working-directory: mobile/android
130+
run: |
131+
if [[ -f app/release.keystore ]]; then
132+
echo "Building release APK (signed)..."
133+
./gradlew assembleRelease
134+
APK_PATH="app/build/outputs/apk/release/app-release.apk"
135+
else
136+
echo "Building debug APK..."
137+
./gradlew assembleDebug
138+
APK_PATH="app/build/outputs/apk/debug/app-debug.apk"
139+
fi
140+
echo "APK_PATH=mobile/android/$APK_PATH" >> $GITHUB_ENV
141+
env:
142+
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
143+
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
144+
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
145+
146+
# ── 重命名产物 ────────────────────────────────────────────────────────
147+
- name: Rename APK
148+
shell: bash
149+
run: |
150+
SUFFIX=$(echo "$APK_PATH" | grep -q 'release' && echo "release" || echo "debug")
151+
APK_NAME="MonkeyCode-${{ env.APP_VERSION }}-android-${SUFFIX}.apk"
152+
cp "$APK_PATH" "$APK_NAME"
153+
echo "APK_NAME=$APK_NAME" >> $GITHUB_ENV
154+
155+
# ── 上传 Artifact(每次构建都保留)──────────────────────────────────
156+
- uses: actions/upload-artifact@v4
157+
with:
158+
name: android-apk
159+
path: ${{ env.APK_NAME }}
160+
if-no-files-found: error
161+
162+
# ── 发布到 GitHub Release(仅 tag 触发)──────────────────────────────
163+
- name: Upload to GitHub Release
164+
if: startsWith(github.ref, 'refs/tags/v')
165+
uses: softprops/action-gh-release@v2
166+
with:
167+
files: ${{ env.APK_NAME }}
168+
tag_name: ${{ github.ref_name }}

0 commit comments

Comments
 (0)