Skip to content

Commit 5e0c14b

Browse files
committed
Add GitHub release workflow for v1.0
1 parent 030dd93 commit 5e0c14b

5 files changed

Lines changed: 224 additions & 1 deletion

File tree

.github/workflows/release.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Release APK
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: 'Existing tag to release, for example v0.1.0'
11+
required: true
12+
type: string
13+
14+
permissions:
15+
contents: write
16+
17+
jobs:
18+
release:
19+
name: Build signed APK and publish release
20+
runs-on: ubuntu-latest
21+
env:
22+
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
23+
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
24+
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
25+
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
26+
27+
steps:
28+
- name: Check out repository
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0
32+
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
33+
34+
- name: Set up JDK
35+
uses: actions/setup-java@v4
36+
with:
37+
distribution: temurin
38+
java-version: '17'
39+
cache: gradle
40+
41+
- name: Install Android SDK packages
42+
run: |
43+
yes | sdkmanager --licenses >/dev/null
44+
sdkmanager "platforms;android-36" "build-tools;36.0.0"
45+
46+
- name: Decode release signing key
47+
run: |
48+
missing=0
49+
for name in ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS; do
50+
if [ -z "${!name}" ]; then
51+
echo "::error::$name secret is required for release signing"
52+
missing=1
53+
fi
54+
done
55+
if [ "$missing" -ne 0 ]; then
56+
exit 1
57+
fi
58+
59+
mkdir -p "$RUNNER_TEMP/signing"
60+
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$RUNNER_TEMP/signing/release.jks"
61+
62+
- name: Build release APK
63+
env:
64+
ANDROID_KEYSTORE_FILE: ${{ runner.temp }}/signing/release.jks
65+
run: |
66+
./gradlew --no-daemon :app:lintDebug :app:testDebugUnitTest :app:assembleRelease
67+
68+
- name: Verify signed APK
69+
run: |
70+
apk=$(find app/build/outputs/apk/release -name '*.apk' ! -name '*unsigned*' -print -quit)
71+
if [ -z "$apk" ]; then
72+
echo "::error::Signed release APK was not produced"
73+
find app/build/outputs/apk/release -maxdepth 1 -type f -print || true
74+
exit 1
75+
fi
76+
77+
APK="$apk" scripts/verify_apk.sh
78+
"$ANDROID_HOME/build-tools/36.0.0/apksigner" verify --verbose --print-certs "$apk"
79+
80+
tag_name="${GITHUB_REF_NAME}"
81+
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
82+
tag_name="${{ inputs.tag }}"
83+
fi
84+
85+
mkdir -p dist
86+
release_apk="dist/pixel-proxy-gateway-${tag_name}.apk"
87+
cp "$apk" "$release_apk"
88+
sha256sum "$release_apk" > "${release_apk}.sha256"
89+
90+
- name: Upload workflow artifact
91+
uses: actions/upload-artifact@v4
92+
with:
93+
name: pixel-proxy-gateway-release
94+
path: dist/*
95+
if-no-files-found: error
96+
97+
- name: Create or update GitHub Release
98+
env:
99+
GH_TOKEN: ${{ github.token }}
100+
run: |
101+
tag_name="${GITHUB_REF_NAME}"
102+
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
103+
tag_name="${{ inputs.tag }}"
104+
fi
105+
106+
if gh release view "$tag_name" >/dev/null 2>&1; then
107+
gh release upload "$tag_name" dist/* --clobber
108+
else
109+
gh release create "$tag_name" dist/* \
110+
--title "Pixel Proxy Gateway ${tag_name}" \
111+
--generate-notes \
112+
--verify-tag
113+
fi

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ app/build/
44
local.properties
55
*.apk
66
*.aab
7+
*.jks
8+
*.keystore
9+
keystore.properties
710
*.iml
811
.idea/
912
third_party/

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,48 @@ scripts/host_preflight.sh
130130

131131
This writes `reports/host-preflight-*` with shell syntax checks, status parser self-test, ADB start guard self-test, LAN smoke strict-assertion self-test, Gradle build/lint/unit-test, APK packaging plus stability-critical manifest checks, GOST provenance, ADB device status, and a short device-validation checklist.
132132

133+
## Release APK
134+
135+
GitHub Actions builds a signed APK when a `v*` tag is pushed, then uploads the APK and SHA256 file to the GitHub Release.
136+
137+
Before the first release, generate a long-lived release signing key locally:
138+
139+
```sh
140+
keytool -genkeypair -v \
141+
-keystore release.jks \
142+
-alias pixel-proxy-gateway \
143+
-keyalg RSA \
144+
-keysize 4096 \
145+
-validity 10000
146+
```
147+
148+
Do not commit `release.jks`. Convert it to one-line base64, then paste it into the GitHub repository under `Settings` -> `Secrets and variables` -> `Actions`:
149+
150+
```sh
151+
base64 -i release.jks | tr -d '\n' | pbcopy
152+
```
153+
154+
Add these repository secrets:
155+
156+
- `ANDROID_KEYSTORE_BASE64`: the base64 value copied above
157+
- `ANDROID_KEYSTORE_PASSWORD`: keystore password
158+
- `ANDROID_KEY_ALIAS`: for example `pixel-proxy-gateway`
159+
- `ANDROID_KEY_PASSWORD`: key password; leave it empty when it matches the keystore password
160+
161+
To publish a new version, first update `versionName` and `versionCode` in `app/build.gradle`, then push a tag:
162+
163+
```sh
164+
git tag -a v1.0 -m "Pixel Proxy Gateway v1.0"
165+
git push origin v1.0
166+
```
167+
168+
After Actions completes, the Release page will include:
169+
170+
```text
171+
pixel-proxy-gateway-v1.0.apk
172+
pixel-proxy-gateway-v1.0.apk.sha256
173+
```
174+
133175
## Install And Control
134176

135177
Install and start:

README.zh-CN.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ Pixel Proxy Gateway 是一个单 APK、侧载安装的 Android 应用,用来
88

99
本应用有意不实现 Android `VpnService`,这样手机侧 VPN 可以继续占用系统 VPN 槽位。Pixel Proxy Gateway 作为一个普通 Android 应用运行:它在手机上监听代理端口,并从手机上的应用进程发起出站连接。
1010

11+
非专业人员只需要阅读经典使用场景,从右侧release下载apk安装即可,本应用界面易于使用
12+
1113
## 为什么做这个项目
1214

1315
- **基于 GOST:** 代理引擎是固定版本、从源码构建的 GOST 二进制,并随 APK 打包,启动前会做校验。
1416
- **面向长期稳定运行:** 应用内置前台服务、wake lock、进程监管、端口 watchdog、请求 watchdog、日志轮转、开机/升级恢复和 ADB 诊断。
1517
- **稳定的 Every Proxy 替代方案:** 对于常驻局域网代理网关场景,本项目目标是比 Every Proxy 这类轻量代理共享应用更稳定、更可诊断,同时保持开源、免费、无广告。
1618
- **可观测、可排障:** 状态、日志、健康检查、监听器状态和恢复行为都可以查看,而不是被藏在一个很轻量但不透明的界面后面。
19+
- 为了能在不支持地区使用先进但容易封号的AI服务,如Claude,GPT等。不少机场节点容易被封号或是降智。但是我发现Google Pixel手机内置Google VPN可以提供纯净的Google LLC节点,可以帮助你全速,安全的使用AI服务。
1720

1821
## 典型使用场景
1922

@@ -130,6 +133,48 @@ scripts/host_preflight.sh
130133

131134
该命令会写入 `reports/host-preflight-*`,内容包括 shell 语法检查、状态解析器自测、ADB 启动防护自测、LAN smoke 严格断言自测、Gradle build/lint/unit-test、APK 打包与稳定性关键 manifest 检查、GOST 来源校验、ADB 设备状态,以及简短的设备验证清单。
132135

136+
## 发布 APK
137+
138+
GitHub Actions 会在推送 `v*` tag 时构建已签名 APK,并把 APK 和 SHA256 文件上传到 GitHub Release。
139+
140+
首次发布前,在本机生成长期保存的 release 签名 key:
141+
142+
```sh
143+
keytool -genkeypair -v \
144+
-keystore release.jks \
145+
-alias pixel-proxy-gateway \
146+
-keyalg RSA \
147+
-keysize 4096 \
148+
-validity 10000
149+
```
150+
151+
不要提交 `release.jks`。把它转成一行 base64 后,填到 GitHub 仓库的 `Settings` -> `Secrets and variables` -> `Actions`
152+
153+
```sh
154+
base64 -i release.jks | tr -d '\n' | pbcopy
155+
```
156+
157+
需要添加这些 repository secrets:
158+
159+
- `ANDROID_KEYSTORE_BASE64`: 上面复制的 base64 内容
160+
- `ANDROID_KEYSTORE_PASSWORD`: keystore 密码
161+
- `ANDROID_KEY_ALIAS`: 例如 `pixel-proxy-gateway`
162+
- `ANDROID_KEY_PASSWORD`: key 密码;如果和 keystore 密码相同,可以留空
163+
164+
发布新版本时,先确认 `app/build.gradle` 里的 `versionName``versionCode` 已更新,然后推送 tag:
165+
166+
```sh
167+
git tag -a v1.0 -m "Pixel Proxy Gateway v1.0"
168+
git push origin v1.0
169+
```
170+
171+
Actions 完成后,Release 页面会出现:
172+
173+
```text
174+
pixel-proxy-gateway-v1.0.apk
175+
pixel-proxy-gateway-v1.0.apk.sha256
176+
```
177+
133178
## 安装与控制
134179

135180
安装并启动:

app/build.gradle

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ plugins {
33
id 'org.jetbrains.kotlin.android'
44
}
55

6+
def releaseKeystoreFile = System.getenv('ANDROID_KEYSTORE_FILE')
7+
def releaseKeystorePassword = System.getenv('ANDROID_KEYSTORE_PASSWORD')
8+
def releaseKeyAlias = System.getenv('ANDROID_KEY_ALIAS')
9+
def releaseKeyPassword = System.getenv('ANDROID_KEY_PASSWORD') ?: releaseKeystorePassword
10+
def hasReleaseSigning = releaseKeystoreFile && releaseKeystorePassword && releaseKeyAlias && releaseKeyPassword
11+
612
android {
713
namespace 'com.wsy.pixelproxygateway'
814
compileSdk 36
@@ -13,11 +19,25 @@ android {
1319
minSdk 29
1420
targetSdk 36
1521
versionCode 1
16-
versionName '0.1.0'
22+
versionName '1.0'
23+
}
24+
25+
signingConfigs {
26+
release {
27+
if (hasReleaseSigning) {
28+
storeFile file(releaseKeystoreFile)
29+
storePassword releaseKeystorePassword
30+
keyAlias releaseKeyAlias
31+
keyPassword releaseKeyPassword
32+
}
33+
}
1734
}
1835

1936
buildTypes {
2037
release {
38+
if (hasReleaseSigning) {
39+
signingConfig signingConfigs.release
40+
}
2141
minifyEnabled false
2242
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
2343
}

0 commit comments

Comments
 (0)