Skip to content

Commit 81cf2d4

Browse files
feat: 添加 FOSS APK 构建矩阵工作流
1 parent a4865b5 commit 81cf2d4

File tree

3 files changed

+354
-19
lines changed

3 files changed

+354
-19
lines changed
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
name: Android Build and Release (Matrix)
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
release_notes:
7+
description: '发布注释(可选,支持多行)'
8+
required: false
9+
default: ''
10+
type: string
11+
push:
12+
tags:
13+
- 'v*.*.*'
14+
15+
env:
16+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17+
18+
permissions:
19+
contents: write
20+
21+
jobs:
22+
build-foss-split:
23+
name: Build FOSS Split APKs
24+
runs-on: ubuntu-latest
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
abi: [arm64-v8a, armeabi-v7a, x86, x86_64, riscv64]
29+
env:
30+
JAVA_HOME_21_X64: /usr/lib/jvm/java-21-openjdk-amd64
31+
steps:
32+
- name: Checkout repository
33+
uses: actions/checkout@v4
34+
35+
- name: Init submodules (llama.cpp)
36+
run: |
37+
git submodule update --init --depth 1
38+
39+
- name: Set up JDK 21
40+
uses: actions/setup-java@v4
41+
with:
42+
java-version: '21'
43+
distribution: 'temurin'
44+
45+
- name: Cache Gradle
46+
uses: actions/cache@v4
47+
with:
48+
path: |
49+
~/.gradle/caches
50+
~/.gradle/wrapper/
51+
key: gradle-cache-${{ runner.os }}-v1
52+
53+
- name: Grant execute permission for gradlew
54+
run: chmod +x ./gradlew
55+
56+
- name: Accept Android SDK licenses
57+
run: |
58+
if [ -f "/usr/local/lib/android/sdk/cmdline-tools/latest/bin/sdkmanager" ]; then
59+
SDK_MANAGER="/usr/local/lib/android/sdk/cmdline-tools/latest/bin/sdkmanager"
60+
else
61+
SDK_MANAGER=$(find $ANDROID_HOME -name sdkmanager | head -n 1)
62+
fi
63+
if [ -n "$SDK_MANAGER" ]; then
64+
yes | $SDK_MANAGER --licenses || true
65+
else
66+
yes | sdkmanager --licenses || true
67+
fi
68+
69+
- name: Decode keystore (if provided)
70+
shell: bash
71+
env:
72+
RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }}
73+
run: |
74+
set -euo pipefail
75+
if [ -n "${RELEASE_KEYSTORE_BASE64:-}" ]; then
76+
mkdir -p app/release
77+
echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "$PWD/app/release/release-keystore.jks"
78+
chmod 600 "$PWD/app/release/release-keystore.jks"
79+
fi
80+
81+
- name: Build FOSS ${{ matrix.abi }}
82+
env:
83+
RELEASE_KEYSTORE_KEY: ${{ secrets.RELEASE_KEYSTORE_KEY }}
84+
RELEASE_KEYSTORE_SUBKEY: ${{ secrets.RELEASE_KEYSTORE_SUBKEY }}
85+
run: |
86+
set -euo pipefail
87+
export GRADLE_OPTS="-Xmx3g"
88+
89+
STORE_FILE="$PWD/app/release/release-keystore.jks"
90+
SIGNING_PROPS=""
91+
if [ -f "$STORE_FILE" ] && [ -n "${RELEASE_KEYSTORE_KEY:-}" ] && [ -n "${RELEASE_KEYSTORE_SUBKEY:-}" ]; then
92+
SIGNING_PROPS="-Pandroid.injected.signing.store.file=$STORE_FILE -Pandroid.injected.signing.store.password=${RELEASE_KEYSTORE_KEY} -Pandroid.injected.signing.key.password=${RELEASE_KEYSTORE_SUBKEY} -Pandroid.injected.signing.key.alias=release"
93+
fi
94+
95+
./gradlew clean assembleFossRelease -PabiFilter=${{ matrix.abi }} $SIGNING_PROPS
96+
97+
- name: Upload Artifact
98+
uses: actions/upload-artifact@v4
99+
with:
100+
name: apk-foss-${{ matrix.abi }}
101+
path: app/build/outputs/apk/foss/release/*.apk
102+
retention-days: 1
103+
104+
build-foss-universal:
105+
name: Build FOSS Universal APK
106+
runs-on: ubuntu-latest
107+
env:
108+
JAVA_HOME_21_X64: /usr/lib/jvm/java-21-openjdk-amd64
109+
steps:
110+
- name: Checkout repository
111+
uses: actions/checkout@v4
112+
113+
- name: Init submodules (llama.cpp)
114+
run: |
115+
git submodule update --init --depth 1
116+
117+
- name: Set up JDK 21
118+
uses: actions/setup-java@v4
119+
with:
120+
java-version: '21'
121+
distribution: 'temurin'
122+
123+
- name: Cache Gradle
124+
uses: actions/cache@v4
125+
with:
126+
path: |
127+
~/.gradle/caches
128+
~/.gradle/wrapper/
129+
key: gradle-cache-${{ runner.os }}-v1
130+
131+
- name: Grant execute permission for gradlew
132+
run: chmod +x ./gradlew
133+
134+
- name: Accept Android SDK licenses
135+
run: |
136+
if [ -f "/usr/local/lib/android/sdk/cmdline-tools/latest/bin/sdkmanager" ]; then
137+
SDK_MANAGER="/usr/local/lib/android/sdk/cmdline-tools/latest/bin/sdkmanager"
138+
else
139+
SDK_MANAGER=$(find $ANDROID_HOME -name sdkmanager | head -n 1)
140+
fi
141+
if [ -n "$SDK_MANAGER" ]; then
142+
yes | $SDK_MANAGER --licenses || true
143+
else
144+
yes | sdkmanager --licenses || true
145+
fi
146+
147+
- name: Decode keystore (if provided)
148+
shell: bash
149+
env:
150+
RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }}
151+
run: |
152+
set -euo pipefail
153+
if [ -n "${RELEASE_KEYSTORE_BASE64:-}" ]; then
154+
mkdir -p app/release
155+
echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "$PWD/app/release/release-keystore.jks"
156+
chmod 600 "$PWD/app/release/release-keystore.jks"
157+
fi
158+
159+
- name: Build FOSS Universal
160+
env:
161+
RELEASE_KEYSTORE_KEY: ${{ secrets.RELEASE_KEYSTORE_KEY }}
162+
RELEASE_KEYSTORE_SUBKEY: ${{ secrets.RELEASE_KEYSTORE_SUBKEY }}
163+
run: |
164+
set -euo pipefail
165+
export GRADLE_OPTS="-Xmx3g"
166+
167+
STORE_FILE="$PWD/app/release/release-keystore.jks"
168+
SIGNING_PROPS=""
169+
if [ -f "$STORE_FILE" ] && [ -n "${RELEASE_KEYSTORE_KEY:-}" ] && [ -n "${RELEASE_KEYSTORE_SUBKEY:-}" ]; then
170+
SIGNING_PROPS="-Pandroid.injected.signing.store.file=$STORE_FILE -Pandroid.injected.signing.store.password=${RELEASE_KEYSTORE_KEY} -Pandroid.injected.signing.key.password=${RELEASE_KEYSTORE_SUBKEY} -Pandroid.injected.signing.key.alias=release"
171+
fi
172+
173+
./gradlew clean assembleFossRelease $SIGNING_PROPS
174+
175+
- name: Upload Artifact
176+
uses: actions/upload-artifact@v4
177+
with:
178+
name: apk-foss-universal
179+
path: app/build/outputs/apk/foss/release/*universal.apk
180+
retention-days: 1
181+
182+
build-full:
183+
name: Build Full Flavor APKs
184+
runs-on: ubuntu-latest
185+
env:
186+
JAVA_HOME_21_X64: /usr/lib/jvm/java-21-openjdk-amd64
187+
steps:
188+
- name: Checkout repository
189+
uses: actions/checkout@v4
190+
191+
- name: Init submodules (llama.cpp)
192+
run: |
193+
git submodule update --init --depth 1
194+
195+
- name: Set up JDK 21
196+
uses: actions/setup-java@v4
197+
with:
198+
java-version: '21'
199+
distribution: 'temurin'
200+
201+
- name: Cache Gradle
202+
uses: actions/cache@v4
203+
with:
204+
path: |
205+
~/.gradle/caches
206+
~/.gradle/wrapper/
207+
key: gradle-cache-${{ runner.os }}-v1
208+
209+
- name: Grant execute permission for gradlew
210+
run: chmod +x ./gradlew
211+
212+
- name: Accept Android SDK licenses
213+
run: |
214+
if [ -f "/usr/local/lib/android/sdk/cmdline-tools/latest/bin/sdkmanager" ]; then
215+
SDK_MANAGER="/usr/local/lib/android/sdk/cmdline-tools/latest/bin/sdkmanager"
216+
else
217+
SDK_MANAGER=$(find $ANDROID_HOME -name sdkmanager | head -n 1)
218+
fi
219+
if [ -n "$SDK_MANAGER" ]; then
220+
yes | $SDK_MANAGER --licenses || true
221+
else
222+
yes | sdkmanager --licenses || true
223+
fi
224+
225+
- name: Decode keystore (if provided)
226+
shell: bash
227+
env:
228+
RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }}
229+
run: |
230+
set -euo pipefail
231+
if [ -n "${RELEASE_KEYSTORE_BASE64:-}" ]; then
232+
mkdir -p app/release
233+
echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "$PWD/app/release/release-keystore.jks"
234+
chmod 600 "$PWD/app/release/release-keystore.jks"
235+
fi
236+
237+
- name: Build Full Flavor
238+
env:
239+
RELEASE_KEYSTORE_KEY: ${{ secrets.RELEASE_KEYSTORE_KEY }}
240+
RELEASE_KEYSTORE_SUBKEY: ${{ secrets.RELEASE_KEYSTORE_SUBKEY }}
241+
run: |
242+
set -euo pipefail
243+
export GRADLE_OPTS="-Xmx3g"
244+
245+
STORE_FILE="$PWD/app/release/release-keystore.jks"
246+
SIGNING_PROPS=""
247+
if [ -f "$STORE_FILE" ] && [ -n "${RELEASE_KEYSTORE_KEY:-}" ] && [ -n "${RELEASE_KEYSTORE_SUBKEY:-}" ]; then
248+
SIGNING_PROPS="-Pandroid.injected.signing.store.file=$STORE_FILE -Pandroid.injected.signing.store.password=${RELEASE_KEYSTORE_KEY} -Pandroid.injected.signing.key.password=${RELEASE_KEYSTORE_SUBKEY} -Pandroid.injected.signing.key.alias=release"
249+
fi
250+
251+
./gradlew clean assembleFullRelease $SIGNING_PROPS
252+
253+
- name: Upload Artifact
254+
uses: actions/upload-artifact@v4
255+
with:
256+
name: apk-full
257+
path: app/build/outputs/apk/full/release/*.apk
258+
retention-days: 1
259+
260+
release:
261+
name: Create Release
262+
needs: [build-foss-split, build-foss-universal, build-full]
263+
runs-on: ubuntu-latest
264+
steps:
265+
- name: Checkout repository
266+
uses: actions/checkout@v4
267+
268+
- name: Download All Artifacts
269+
uses: actions/download-artifact@v4
270+
with:
271+
path: release_artifacts
272+
merge-multiple: true
273+
274+
- name: Compute release metadata
275+
id: meta
276+
env:
277+
RELEASE_NOTES: ${{ github.event.inputs.release_notes }}
278+
run: |
279+
set -euo pipefail
280+
# Derive version (Gradle file preferred, fallback to properties)
281+
VERSION=""
282+
if [ -f app/build.gradle ]; then
283+
VERSION=$(grep -m1 "versionName" app/build.gradle | sed -E "s/.*versionName[[:space:]]+['\"]([^'\"]+)['\"].*/\1/" || true)
284+
fi
285+
if [ -z "$VERSION" ] && [ -f app/build.gradle.kts ]; then
286+
VERSION=$(grep -m1 "versionName" app/build.gradle.kts | sed -E "s/.*versionName\\s*=?\\s*\"([^\"]+)\".*/\1/" || true)
287+
fi
288+
if [ -z "$VERSION" ] && [ -f gradle.properties ]; then
289+
VERSION=$(grep -m1 -E "^(VERSION_NAME|versionName|VERSION)=" gradle.properties | cut -d'=' -f2- | tr -d '[:space:]' || true)
290+
fi
291+
VERSION=${VERSION:-"build-${GITHUB_RUN_ID}"}
292+
293+
COMMIT_ID=$(git rev-parse --short HEAD)
294+
# Ensure tag name is version with a leading 'v' (e.g., v0.0.1)
295+
case "$VERSION" in
296+
v*|V*) TAG_NAME="$VERSION" ;;
297+
*) TAG_NAME="v$VERSION" ;;
298+
esac
299+
300+
# Prefer user-provided release notes from workflow dispatch input; fallback to git log
301+
if [ -n "${RELEASE_NOTES:-}" ]; then
302+
BODY="$RELEASE_NOTES"
303+
else
304+
BODY=$(git log --pretty=format:"%h %ad - %s (%an)" --date=short --no-merges -n 200)
305+
fi
306+
307+
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
308+
echo "release_name=${VERSION}" >> "$GITHUB_OUTPUT"
309+
{
310+
echo 'body<<EOF'
311+
echo "$BODY"
312+
echo EOF
313+
} >> "$GITHUB_OUTPUT"
314+
315+
- name: Create GitHub Release and upload APKs
316+
uses: softprops/action-gh-release@v1
317+
env:
318+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
319+
with:
320+
tag_name: ${{ steps.meta.outputs.tag_name }}
321+
name: ${{ steps.meta.outputs.release_name }}
322+
body: ${{ steps.meta.outputs.body }}
323+
fail_on_unmatched_files: false
324+
files: release_artifacts/*.apk

0 commit comments

Comments
 (0)