Add CI/CD configuration and API documentation

This commit is contained in:
2026-07-01 21:40:53 +08:00
commit c590135d68
4168 changed files with 740252 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
+254
View File
@@ -0,0 +1,254 @@
# CI/CD 配置检查报告
## ✅ 检查完成
已完成对 GitHub Actions CI/CD 配置文件的全面检查。
---
## 📁 已创建的文件
| 文件 | 路径 | 说明 |
|------|------|------|
| build.yml | `.github/workflows/build.yml` | 主工作流配置文件 |
| README.md | `.github/workflows/README.md` | 详细配置说明文档 |
| QUICKSTART.md | `.github/workflows/QUICKSTART.md` | 快速入门指南 |
| setup-secrets.sh | `.github/workflows/setup-secrets.sh` | macOS/Linux 配置脚本 |
| setup-secrets.ps1 | `.github/workflows/setup-secrets.ps1` | Windows 配置脚本 |
---
## 🔧 已修复的问题
### 问题 1: iOS 签名身份 Secret 名称不一致
- **位置**: build.yml 第 218 行
- **问题**: 使用了 `IOS_SIGNING_identity` (小写 identity)
- **修复**: 改为 `IOS_SIGNING_IDENTITY` (全大写,符合命名规范)
### 问题 2: 条件判断过于复杂
- **位置**: 多处
- **问题**: 使用了 `startsWith(github.ref, 'refs/tags/v') || github.event.inputs.release_type == 'release'` 复杂条件
- **修复**: 简化为 `startsWith(github.ref, 'refs/tags/v')`,只在创建标签时触发 Release 构建
---
## ✅ 配置验证清单
### 工作流触发条件
- ✅ Push 到 main 分支 - 触发构建
- ✅ Push 到 develop 分支 - 触发 Debug 构建
- ✅ Pull Request - 触发 Debug 构建
- ✅ 创建版本标签 (v*) - 触发 Release 构建
- ✅ 手动触发 - 可选择构建平台和类型
### Android 构建步骤
- ✅ 检出代码和子模块
- ✅ 安装 JDK 11
- ✅ 安装 Go 1.23
- ✅ 安装 Android SDK
- ✅ 创建 local.properties
- ✅ 配置签名密钥 (Release)
- ✅ 构建 APK
- ✅ 上传构建产物
### iOS 构建步骤
- ✅ 检出代码和子模块
- ✅ 安装 Xcode 15.0
- ✅ 安装开发者证书 (Release)
- ✅ 安装 Provisioning Profile (Release)
- ✅ 解析 Swift Package 依赖
- ✅ 构建 Debug 版本 (模拟器)
- ✅ 构建并归档 Release 版本
- ✅ 导出 IPA
- ✅ 上传构建产物
### 发布步骤
- ✅ 下载 Android APK
- ✅ 下载 iOS IPA
- ✅ 创建 GitHub Release
- ✅ 上传文件到 Release
- ✅ 上传到 TestFlight (Beta 和正式版)
- ✅ 发送 Telegram 通知
- ✅ 清理旧的构建产物
---
## ⚠️ 使用前必须配置的 Secrets
### Android 构建 (发布版本必需)
| Secret 名称 | 说明 | 如何获取 |
|------------|------|---------|
| `ANDROID_KEYSTORE_BASE64` | 签名密钥库的 Base64 编码 | 使用 base64 命令转换 |
| `ANDROID_KEYSTORE_PASSWORD` | 密钥库密码 | 创建密钥库时设置 |
| `ANDROID_KEY_ALIAS` | 密钥别名 | 创建密钥库时设置 |
| `ANDROID_KEY_PASSWORD` | 密钥密码 | 创建密钥库时设置 |
**注意**: Debug 构建不需要配置这些 Secrets。
### iOS 构建 (发布版本必需)
| Secret 名称 | 说明 | 如何获取 |
|------------|------|---------|
| `IOS_CERTIFICATES_P12` | 开发者证书的 Base64 编码 | 从钥匙串导出 .p12 文件 |
| `IOS_CERTIFICATES_PASSWORD` | 证书密码 | 导出时设置 |
| `IOS_TEAM_ID` | Apple Team ID | Apple Developer 账号 |
| `IOS_SIGNING_IDENTITY` | 签名身份 | 如: "Apple Distribution: Name (TEAM_ID)" |
| `IOS_PROVISIONING_PROFILE` | Provisioning Profile 的 Base64 编码 | Apple Developer 网站下载 |
**注意**: Debug 构建不需要配置这些 Secrets。
### TestFlight 上传 (可选)
| Secret 名称 | 说明 | 如何获取 |
|------------|------|---------|
| `APP_STORE_CONNECT_ISSUER_ID` | Issuer ID | App Store Connect API Keys |
| `APP_STORE_CONNECT_API_KEY_ID` | API Key ID | 创建 API Key 时获得 |
| `APP_STORE_CONNECT_API_PRIVATE_KEY` | API 私钥 | 下载的 .p8 文件内容 |
### 通知 (可选)
| Secret 名称 | 说明 | 如何获取 |
|------------|------|---------|
| `TELEGRAM_BOT_TOKEN` | Bot Token | 通过 @BotFather 创建 |
| `TELEGRAM_CHAT_ID` | Chat ID | 邀请 Bot 后获取 |
---
## 🚀 快速开始步骤
### 1. 配置 Secrets
**Windows 用户**:
```powershell
cd D:\Code\UUVPN\.github\workflows
.\setup-secrets.ps1
```
**macOS/Linux 用户**:
```bash
cd /path/to/UUVPN/.github/workflows
chmod +x setup-secrets.sh
./setup-secrets.sh
```
### 2. 推送代码测试
```bash
# 推送到 develop 分支触发 Debug 构建
git checkout -b develop
git push origin develop
# 查看 Actions 页面确认构建成功
```
### 3. 创建发布版本
```bash
# 创建 Alpha 版本
git tag v1.0.0-alpha
git push origin v1.0.0-alpha
# 创建 Beta 版本 (会自动上传到 TestFlight)
git tag v1.0.0-beta
git push origin v1.0.0-beta
# 创建正式版本
git tag v1.0.0
git push origin v1.0.0
```
---
## 📊 预期行为
### Debug 构建 (develop 分支或 PR)
**Android**:
- ✅ 使用 Debug 签名
- ✅ 构建 `app-meta-alpha-debug.apk`
- ✅ 上传到 Artifacts (保留 30 天)
**iOS**:
- ✅ 无签名
- ✅ 构建模拟器版本
- ✅ 上传 .app 文件到 Artifacts (保留 7 天)
### Release 构建 (创建标签)
**Android**:
- ✅ 使用自定义签名密钥
- ✅ 构建 Release APK
- ✅ 重命名为 `UUVPN-Android-v1.0.0.apk`
- ✅ 上传到 GitHub Release
**iOS**:
- ✅ 使用开发者证书签名
- ✅ 导出 IPA 文件
- ✅ 重命名为 `UUVPN-iOS-v1.0.0.ipa`
- ✅ 上传到 GitHub Release
- ✅ Beta 和正式版上传到 TestFlight
---
## ⏱️ 预计构建时间
| 平台 | Debug 构建 | Release 构建 |
|------|-----------|-------------|
| Android | 5-10 分钟 | 10-15 分钟 |
| iOS | 15-20 分钟 | 20-30 分钟 |
**总计**: 完整构建约 25-45 分钟
---
## 💰 成本估算
GitHub Actions 免费账户每月 2000 分钟:
| 构建类型 | 消耗时间 | 每月可构建次数 |
|---------|---------|--------------|
| 仅 Android | ~10 分钟 | ~200 次 |
| 仅 iOS | ~200 分钟 (按 10 倍计) | ~10 次 |
| Android + iOS | ~210 分钟 | ~9 次 |
**建议**: 节省 macOS runner 时间,只在需要时构建 iOS 版本。
---
## 🎯 下一步行动
1.**配置 Secrets**
- 使用配置脚本或手动配置
- 至少配置 Debug 构建所需的 Secrets
2.**测试 Debug 构建**
- 推送代码到 develop 分支
- 确认构建成功
3.**配置发布 Secrets**
- 配置 Android 签名密钥
- 配置 iOS 证书和 Profile
4.**创建第一个版本**
- 创建标签触发 Release 构建
- 验证 GitHub Release 创建成功
5.**配置 TestFlight** (可选)
- 配置 App Store Connect API Keys
- 验证自动上传到 TestFlight
---
## 📞 获取帮助
如遇到问题,请查看:
1. [GitHub Actions 日志](https://github.com/你的用户名/UUVPN/actions)
2. [配置文档](.github/workflows/README.md)
3. [快速入门](.github/workflows/QUICKSTART.md)
4. [项目 Issues](https://github.com/nicolastinkl/UUVPN/issues)
---
**配置检查完成! 🎉**
+363
View File
@@ -0,0 +1,363 @@
# GitHub Actions CI/CD 快速入门指南
本指南帮助你快速配置和使用 UUVPN 的自动构建系统。
---
## 🚀 5 分钟快速开始
### 第一步: 准备工作
确保你已拥有:
- ✅ GitHub 账号
- ✅ UUVPN 代码仓库的写权限
- ✅ Apple Developer 账号 (iOS 构建必需)
- ✅ Android 签名密钥库 (Android Release 构建必需)
### 第二步: 安装 GitHub CLI
**Windows**:
```powershell
winget install GitHub.cli
```
**macOS**:
```bash
brew install gh
```
**Linux**:
```bash
# Debian/Ubuntu
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install gh
```
### 第三步: 登录 GitHub
```bash
gh auth login
```
按照提示选择:
- GitHub.com
- HTTPS
- 使用浏览器登录或粘贴 token
### 第四步: 配置 Secrets
#### 方法一: 使用自动配置脚本 (推荐)
**Windows**:
```powershell
cd D:\Code\UUVPN\.github\workflows
.\setup-secrets.ps1
```
**macOS/Linux**:
```bash
cd /path/to/UUVPN/.github/workflows
chmod +x setup-secrets.sh
./setup-secrets.sh
```
#### 方法二: 手动配置
在 GitHub 仓库页面:
1. 进入 `Settings``Secrets and variables``Actions`
2. 点击 `New repository secret`
3. 添加所需的 secrets (详见下方)
### 第五步: 触发构建
```bash
# 推送代码触发构建
git push origin main
# 或创建标签触发发布
git tag v1.0.0-alpha
git push origin v1.0.0-alpha
```
---
## 📋 必需的 Secrets 清单
### Android 构建
| Secret | 必需 | 说明 |
|--------|------|------|
| `ANDROID_KEYSTORE_BASE64` | ✅ | 签名密钥库的 Base64 编码 |
| `ANDROID_KEYSTORE_PASSWORD` | ✅ | 密钥库密码 |
| `ANDROID_KEY_ALIAS` | ✅ | 密钥别名 |
| `ANDROID_KEY_PASSWORD` | ✅ | 密钥密码 |
### iOS 构建
| Secret | 必需 | 说明 |
|--------|------|------|
| `IOS_CERTIFICATES_P12` | ✅ | 开发者证书 Base64 编码 |
| `IOS_CERTIFICATES_PASSWORD` | ✅ | 证书密码 |
| `IOS_TEAM_ID` | ✅ | Apple Team ID |
| `IOS_SIGNING_IDENTITY` | ✅ | 签名身份 |
| `IOS_PROVISIONING_PROFILE` | ✅ | Provisioning Profile Base64 |
### TestFlight 上传 (可选)
| Secret | 必需 | 说明 |
|--------|------|------|
| `APP_STORE_CONNECT_ISSUER_ID` | ⭐ | App Store Connect Issuer ID |
| `APP_STORE_CONNECT_API_KEY_ID` | ⭐ | API Key ID |
| `APP_STORE_CONNECT_API_PRIVATE_KEY` | ⭐ | API 私钥 |
### 通知 (可选)
| Secret | 必需 | 说明 |
|--------|------|------|
| `TELEGRAM_BOT_TOKEN` | | Telegram Bot Token |
| `TELEGRAM_CHAT_ID` | | Telegram Chat ID |
---
## 🔧 详细配置步骤
### Android 签名密钥库
#### 1. 创建密钥库 (如果没有)
```bash
keytool -genkey -v \
-keystore release.keystore \
-alias uuvpn \
-keyalg RSA \
-keysize 2048 \
-validity 10000
```
按提示输入:
- 密钥库密码
- 个人信息
- 密钥密码
#### 2. 转换为 Base64
**macOS/Linux**:
```bash
base64 -i release.keystore -o release.keystore.base64
```
**Windows PowerShell**:
```powershell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("release.keystore")) | Out-File release.keystore.base64
```
#### 3. 添加到 GitHub Secrets
复制 `release.keystore.base64` 文件内容,添加为 `ANDROID_KEYSTORE_BASE64` secret。
### iOS 开发者证书
#### 1. 导出证书
1. 打开 "钥匙串访问" (Keychain Access)
2. 找到 "Apple Distribution" 证书
3. 右键 → 导出
4. 选择 .p12 格式
5. 设置密码
#### 2. 转换为 Base64
**macOS**:
```bash
base64 -i certificate.p12 -o certificate.p12.base64
```
#### 3. 下载 Provisioning Profile
1. 登录 [Apple Developer](https://developer.apple.com/)
2. 进入 Certificates, Identifiers & Profiles
3. 下载对应的 Provisioning Profile
#### 4. 转换为 Base64
```bash
base64 -i uuvpn.mobileprovision -o uuvpn.mobileprovision.base64
```
### App Store Connect API Key
#### 1. 创建 API Key
1. 登录 [App Store Connect](https://appstoreconnect.apple.com/)
2. 进入 Users and Access → Keys
3. 点击 "Generate API Key"
4. 选择 "App Manager" 权限
5. 下载 .p8 文件
#### 2. 记录信息
- **Issuer ID**: 在 Keys 页面顶部
- **Key ID**: 创建后显示
- **Private Key**: 下载的 .p8 文件内容
---
## 🎯 构建类型说明
### Debug 构建
**触发条件**:
- Pull Request
- 推送到 develop 分支
**特点**:
- 无需签名配置
- 快速构建
- 不发布到 Release
### Release 构建
**触发条件**:
- 推送到 main 分支
- 创建版本标签
**特点**:
- 需要签名配置
- 自动发布到 GitHub Releases
- 可选上传到 TestFlight
### 版本标签格式
```bash
# Alpha 版本 (预发布)
git tag v1.0.0-alpha
git push origin v1.0.0-alpha
# Beta 版本 (预发布,上传 TestFlight)
git tag v1.0.0-beta
git push origin v1.0.0-beta
# 正式版本 (发布,上传 TestFlight)
git tag v1.0.0
git push origin v1.0.0
```
---
## 📥 下载构建产物
### 方法一: Actions Artifacts
1. 进入 GitHub 仓库
2. 点击 "Actions" 标签
3. 选择具体的 workflow 运行记录
4. 在页面底部 "Artifacts" 区域下载
### 方法二: GitHub Releases
1. 进入 GitHub 仓库
2. 点击 "Releases" 标签
3. 找到对应版本
4. 下载 APK 或 IPA 文件
---
## 🛠️ 故障排查
### 构建失败
1. **查看日志**:
- 进入 Actions 页面
- 点击失败的步骤
- 查看详细错误信息
2. **常见错误**:
- ❌ 签名错误: 检查 Secrets 配置
- ❌ 证书过期: 更新证书和 Profile
- ❌ 构建超时: 优化构建配置
### iOS 签名失败
检查清单:
- [ ] 证书未过期
- [ ] Provisioning Profile 包含正确 App ID
- [ ] Team ID 正确
- [ ] 证书和 Profile 匹配
### TestFlight 上传失败
检查清单:
- [ ] API Key 有 App Manager 权限
- [ ] App ID 在 App Store Connect 已创建
- [ ] 版本号未重复
---
## 💡 最佳实践
### 1. 分支策略
```
main (稳定版本)
develop (开发版本)
feature/* (功能分支)
```
### 2. 版本号规范
使用语义化版本:
- `v1.0.0-alpha`: 内部测试版本
- `v1.0.0-beta`: 公开测试版本
- `v1.0.0`: 正式发布版本
### 3. 节省构建时间
- 只在需要时构建 iOS (macOS runner 费用高)
- 使用缓存加速构建
- 手动触发选择性构建
### 4. 安全建议
- 定期更新签名密钥
- 使用最小权限原则
- 不要在代码中硬编码敏感信息
---
## 📞 获取帮助
### 文档
- [GitHub Actions 文档](https://docs.github.com/en/actions)
- [详细配置说明](./README.md)
- [API 配置指南](../../API配置指南.md)
### 支持
- 查看仓库 [Issues](https://github.com/nicolastinkl/UUVPN/issues)
- Telegram: @fastlink
---
## ✅ 配置验证清单
完成配置后,检查以下内容:
- [ ] 已安装 GitHub CLI
- [ ] 已登录 GitHub CLI
- [ ] 已配置 Android Secrets (如需 Android 构建)
- [ ] 已配置 iOS Secrets (如需 iOS 构建)
- [ ] 已配置 App Store Connect API (如需 TestFlight)
- [ ] 已推送代码触发构建
- [ ] 构建成功
- [ ] 可以下载构建产物
---
**祝你构建顺利! 🎉**
+525
View File
@@ -0,0 +1,525 @@
# GitHub Actions CI/CD 配置说明
本文档说明如何配置和使用 UUVPN 的 GitHub Actions 自动构建流程。
---
## 📋 目录
- [功能特性](#功能特性)
- [前置要求](#前置要求)
- [配置 Secrets](#配置-secrets)
- [使用方法](#使用方法)
- [构建产物](#构建产物)
- [自定义配置](#自定义配置)
- [常见问题](#常见问题)
---
## 功能特性
### ✅ 自动构建
- **Android APK**: 支持 Debug 和 Release 构建
- **iOS IPA**: 支持 Debug 和 Release 构建
- **多架构支持**: Android 支持 armeabi-v7a, arm64-v8a, x86, x86_64
### ✅ 自动发布
- **GitHub Releases**: 自动创建 Release 并上传构建产物
- **TestFlight**: 自动上传 iOS 版本到 TestFlight
- **Telegram 通知**: 构建完成后发送通知
### ✅ 触发条件
- 推送到 main/develop 分支
- 创建版本标签 (v*)
- Pull Request
- 手动触发
---
## 前置要求
### Android 构建
1. **JDK 11**: 已在 Actions 中自动配置
2. **Android SDK**: 已在 Actions 中自动配置
3. **Go 1.23**: 用于编译核心库
4. **签名密钥**: Release 构建需要签名密钥库
### iOS 构建
1. **Apple Developer 账号**: $99/年
2. **Xcode 15.0+**: 已在 Actions 中自动配置
3. **开发者证书**: .p12 格式
4. **Provisioning Profile**: .mobileprovision 文件
5. **App Store Connect API Key**: 用于上传到 TestFlight
---
## 配置 Secrets
在 GitHub 仓库中配置以下 Secrets:
### Android Secrets
| Secret 名称 | 描述 | 获取方式 |
|------------|------|---------|
| `ANDROID_KEYSTORE_BASE64` | 签名密钥库的 Base64 编码 | 见下方说明 |
| `ANDROID_KEYSTORE_PASSWORD` | 密钥库密码 | 创建密钥库时设置 |
| `ANDROID_KEY_ALIAS` | 密钥别名 | 创建密钥库时设置 |
| `ANDROID_KEY_PASSWORD` | 密钥密码 | 创建密钥库时设置 |
**生成 ANDROID_KEYSTORE_BASE64**:
```bash
# 在本地执行
keytool -genkey -v -keystore release.keystore -alias uuvpn -keyalg RSA -keysize 2048 -validity 10000
# 转换为 Base64
base64 -i release.keystore -o release.keystore.base64
# 或者使用 PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("release.keystore")) | Out-File release.keystore.base64
```
### iOS Secrets
| Secret 名称 | 描述 | 获取方式 |
|------------|------|---------|
| `IOS_CERTIFICATES_P12` | 开发者证书的 Base64 编码 | 见下方说明 |
| `IOS_CERTIFICATES_PASSWORD` | 证书密码 | 导出证书时设置 |
| `IOS_SIGNING_IDENTITY` | 签名身份 | 如: "Apple Distribution: Your Name (TEAM_ID)" |
| `IOS_PROVISIONING_PROFILE` | Provisioning Profile 的 Base64 编码 | 见下方说明 |
| `IOS_TEAM_ID` | Apple Team ID | 在 Apple Developer 账号中查看 |
**生成 IOS_CERTIFICATES_P12**:
1. 在 Keychain Access 中导出证书
2. 选择 "Apple Distribution" 证书
3. 右键 → 导出 → 选择 .p12 格式
4. 设置密码
5. 转换为 Base64:
```bash
base64 -i certificate.p12 -o certificate.p12.base64
# 或者使用 PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("certificate.p12")) | Out-File certificate.p12.base64
```
**生成 IOS_PROVISIONING_PROFILE**:
1. 在 Apple Developer 网站下载 Provisioning Profile
2. 转换为 Base64:
```bash
base64 -i uuvpn.mobileprovision -o uuvpn.mobileprovision.base64
# 或者使用 PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("uuvpn.mobileprovision")) | Out-File uuvpn.mobileprovision.base64
```
### App Store Connect Secrets
| Secret 名称 | 描述 | 获取方式 |
|------------|------|---------|
| `APP_STORE_CONNECT_ISSUER_ID` | App Store Connect API Issuer ID | 在 App Store Connect 中创建 API Key |
| `APP_STORE_CONNECT_API_KEY_ID` | App Store Connect API Key ID | 创建 API Key 时获得 |
| `APP_STORE_CONNECT_API_PRIVATE_KEY` | App Store Connect API 私钥 | 创建 API Key 时下载的 .p8 文件内容 |
**获取方式**:
1. 登录 [App Store Connect](https://appstoreconnect.apple.com/)
2. 进入 Users and Access → Keys
3. 点击 "Generate API Key"
4. 选择 "App Manager" 权限
5. 下载 .p8 文件并保存私钥内容
### 通知 Secrets (可选)
| Secret 名称 | 描述 | 获取方式 |
|------------|------|---------|
| `TELEGRAM_BOT_TOKEN` | Telegram Bot Token | 通过 @BotFather 创建 Bot |
| `TELEGRAM_CHAT_ID` | Telegram 群组/频道 ID | 邀请 Bot 到群组后获取 |
**获取方式**:
1. 在 Telegram 中找到 @BotFather
2. 发送 `/newbot` 创建新 Bot
3. 获取 Bot Token
4. 创建群组或频道,邀请 Bot
5. 获取 Chat ID: `https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates`
---
## 使用方法
### 方法一: 自动触发
#### 推送到分支
```bash
# 推送到 main 分支,触发构建
git push origin main
# 推送到 develop 分支,触发 Debug 构建
git push origin develop
```
#### 创建版本标签
```bash
# 创建 Alpha 版本
git tag v1.0.0-alpha
git push origin v1.0.0-alpha
# 创建 Beta 版本
git tag v1.0.0-beta
git push origin v1.0.0-beta
# 创建正式版本
git tag v1.0.0
git push origin v1.0.0
```
#### Pull Request
创建 Pull Request 到 main 分支会自动触发 Debug 构建。
### 方法二: 手动触发
1. 进入 GitHub 仓库
2. 点击 "Actions" 标签
3. 选择 "Build UUVPN" workflow
4. 点击 "Run workflow"
5. 选择构建选项:
- `build_android`: 是否构建 Android APK
- `build_ios`: 是否构建 iOS IPA
- `release_type`: 构建类型 (alpha/beta/release)
6. 点击 "Run workflow" 按钮
---
## 构建产物
### Android 构建产物
构建完成后,可以在以下位置找到 APK:
1. **Actions Artifacts**: 每个 workflow 运行都会保存 APK artifact
2. **GitHub Releases**: 创建标签后,APK 会自动上传到 Release
**APK 文件命名**:
- Debug: `app-meta-alpha-debug.apk`
- Release: `UUVPN-Android-v1.0.0.apk`
### iOS 构建产物
构建完成后,可以在以下位置找到 IPA:
1. **Actions Artifacts**: 每个 workflow 运行都会保存 IPA artifact
2. **GitHub Releases**: 创建标签后,IPA 会自动上传到 Release
3. **TestFlight**: Beta 和正式版本会自动上传到 TestFlight
**IPA 文件命名**:
- Release: `UUVPN-iOS-v1.0.0.ipa`
---
## 自定义配置
### 修改 Android 构建变体
编辑 `.github/workflows/build.yml` 中的构建命令:
```yaml
- name: Build Android APK
run: |
cd Android-kotlin-Code
# 修改为你需要的构建变体
./gradlew app:assembleMeta-BetaRelease --stacktrace
```
### 修改 iOS Scheme
编辑 `.github/workflows/build.yml` 中的 scheme:
```yaml
- name: Build iOS App
run: |
cd iOS-SwiftUI-Code
xcodebuild build \
-project uuvpn.xcodeproj \
-scheme SFT \ # 修改为你需要的 scheme
-sdk iphoneos \
...
```
### 添加构建缓存
在 workflow 中添加缓存以加速构建:
```yaml
- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Cache Swift packages
uses: actions/cache@v4
with:
path: |
~/Library/Caches/org.swift.swiftpm
.build
key: ${{ runner.os }}-swift-${{ hashFiles('**/Package.resolved') }}
restore-keys: |
${{ runner.os }}-swift-
```
### 添加自定义构建步骤
在 workflow 中添加自定义步骤:
```yaml
- name: Custom build step
run: |
# 你的自定义命令
echo "Running custom build step"
```
---
## 工作流程说明
### 完整构建流程
```
┌─────────────────┐
│ 触发构建 │
└────────┬────────┘
├─────────────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 构建 Android │ │ 构建 iOS │
│ APK │ │ IPA │
└────────┬────────┘ └────────┬────────┘
│ │
└──────────┬──────────┘
┌─────────────────────┐
│ 创建 GitHub Release │
│ (仅标签触发) │
└──────────┬──────────┘
├─────────────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 上传 APK 到 │ │ 上传 IPA 到 │
│ GitHub Release │ │ TestFlight │
└─────────────────┘ └─────────────────┘
┌─────────────────────┐
│ 发送通知 │
└─────────────────────┘
```
### 构建类型说明
| 触发条件 | Android | iOS | 发布 |
|---------|---------|-----|------|
| Push to develop | Debug APK | Debug App | 否 |
| Pull Request | Debug APK | Debug App | 否 |
| Push to main | Release APK | Release IPA | 否 |
| Tag v*-alpha | Release APK | Release IPA | GitHub Release (Pre-release) |
| Tag v*-beta | Release APK | Release IPA | GitHub Release + TestFlight |
| Tag v* | Release APK | Release IPA | GitHub Release + TestFlight |
---
## 常见问题
### Q1: Android 构建失败,提示找不到签名密钥?
**A**: 检查以下内容:
- 确认已配置 `ANDROID_KEYSTORE_BASE64` secret
- 确认 Base64 编码正确
- 确认密钥库密码、别名和密钥密码正确
### Q2: iOS 构建失败,提示签名错误?
**A**: 检查以下内容:
- 确认证书未过期
- 确认 Provisioning Profile 包含正确的 App ID
- 确认 Team ID 正确
- 确认证书和 Provisioning Profile 匹配
### Q3: iOS 构建时间过长?
**A**: iOS 构建通常需要 10-20 分钟,这是正常的。可以:
- 使用缓存加速构建
- 只在需要时构建 iOS 版本
- 使用手动触发选择性构建
### Q4: 如何跳过某个平台的构建?
**A**: 使用手动触发时,取消勾选对应平台的构建选项。
### Q5: 构建产物在哪里下载?
**A**:
1. 进入 Actions 页面
2. 点击具体的 workflow 运行记录
3. 在页面底部 "Artifacts" 区域下载
### Q6: 如何查看构建日志?
**A**:
1. 进入 Actions 页面
2. 点击具体的 workflow 运行记录
3. 点击左侧的 job 名称
4. 展开各个步骤查看详细日志
### Q7: TestFlight 上传失败?
**A**: 检查以下内容:
- 确认 App Store Connect API Key 配置正确
- 确认 API Key 有 App Manager 权限
- 确认 App ID 在 App Store Connect 中已创建
- 确认版本号未重复
### Q8: 如何修改构建触发条件?
**A**: 编辑 `.github/workflows/build.yml``on` 部分:
```yaml
on:
push:
branches:
- main
- develop
- feature/* # 添加更多分支
tags:
- 'v*'
pull_request:
branches:
- main
- develop
```
---
## 进阶配置
### 添加代码质量检查
在构建前添加代码检查:
```yaml
jobs:
lint:
name: Code Quality Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Android Lint
run: |
cd Android-kotlin-Code
./gradlew lint
- name: Swift Lint
run: |
brew install swiftlint
cd iOS-SwiftUI-Code
swiftlint
```
### 添加单元测试
```yaml
jobs:
test:
name: Run Tests
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Android Tests
run: |
cd Android-kotlin-Code
./gradlew test
- name: iOS Tests
run: |
cd iOS-SwiftUI-Code
xcodebuild test \
-project uuvpn.xcodeproj \
-scheme SFI \
-destination 'platform=iOS Simulator,name=iPhone 15'
```
### 添加多版本构建
```yaml
strategy:
matrix:
xcode-version: ['14.3', '15.0', '15.2']
include:
- xcode-version: '14.3'
ios-deployment-target: '14.0'
- xcode-version: '15.0'
ios-deployment-target: '15.0'
- xcode-version: '15.2'
ios-deployment-target: '16.0'
```
---
## 成本估算
### GitHub Actions 免费额度
- **总时长**: 每月 2000 分钟 (免费账户)
- **macOS runner**: 按 10 倍计算
- **Linux runner**: 按 1 倍计算
### 实际消耗估算
| 构建类型 | Android | iOS | 总计 |
|---------|---------|-----|------|
| Debug 构建 | ~5 分钟 | ~100 分钟 | ~105 分钟 |
| Release 构建 | ~10 分钟 | ~150 分钟 | ~160 分钟 |
| 完整流程 | ~15 分钟 | ~200 分钟 | ~215 分钟 |
### 建议
- 免费账户每月可进行约 **9-10 次完整构建**
- 建议只在必要时构建 iOS 版本
- 使用手动触发选择性构建
- 考虑升级 GitHub Pro 获得更多额度
---
## 总结
通过 GitHub Actions CI/CD 配置,你可以:
✅ 无需本地 Mac 设备即可构建 iOS 应用
✅ 自动化构建和发布流程
✅ 支持 Android 和 iOS 双平台
✅ 自动上传到 TestFlight 和 GitHub Releases
✅ 接收构建通知
配置好 Secrets 后,只需推送代码或创建标签,即可自动完成构建和发布!
+423
View File
@@ -0,0 +1,423 @@
name: Build UUVPN
on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
workflow_dispatch:
inputs:
build_android:
description: 'Build Android APK'
required: false
default: true
type: boolean
build_ios:
description: 'Build iOS IPA'
required: false
default: true
type: boolean
release_type:
description: 'Release type'
required: false
default: 'alpha'
type: choice
options:
- alpha
- beta
- release
env:
# Android 配置
ANDROID_COMPILE_SDK: "33"
ANDROID_BUILD_TOOLS: "33.0.0"
ANDROID_TARGET_SDK: "33"
ANDROID_JDK_VERSION: "11"
# iOS 配置
IOS_XCODE_VERSION: "15.0"
IOS_DEPLOYMENT_TARGET: "15.0"
jobs:
# ==================== Android 构建 ====================
build-android:
name: Build Android APK
runs-on: ubuntu-latest
if: ${{ github.event.inputs.build_android != 'false' }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: ${{ env.ANDROID_JDK_VERSION }}
distribution: 'temurin'
cache: 'gradle'
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Grant execute permission for gradlew
run: |
cd Android-kotlin-Code
chmod +x gradlew
- name: Create local.properties
run: |
cd Android-kotlin-Code
echo "sdk.dir=$ANDROID_HOME" > local.properties
- name: Create signing.properties (Debug)
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
run: |
cd Android-kotlin-Code
echo "keystore.path=debug.keystore" > signing.properties
echo "keystore.password=android" >> signing.properties
echo "key.alias=androiddebugkey" >> signing.properties
echo "key.password=android" >> signing.properties
- name: Create signing.properties (Release)
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd Android-kotlin-Code
echo "keystore.path=release.keystore" > signing.properties
echo "keystore.password=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" >> signing.properties
echo "key.alias=${{ secrets.ANDROID_KEY_ALIAS }}" >> signing.properties
echo "key.password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> signing.properties
- name: Decode Android keystore
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd Android-kotlin-Code
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore
- name: Build Android Debug APK
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
run: |
cd Android-kotlin-Code
./gradlew app:assembleMeta-AlphaDebug --stacktrace
- name: Build Android Release APK
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd Android-kotlin-Code
./gradlew app:assembleMeta-AlphaRelease --stacktrace
- name: Build Android APK (Default)
if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') && github.ref != 'refs/heads/develop' }}
run: |
cd Android-kotlin-Code
./gradlew app:assembleMeta-AlphaRelease --stacktrace
- name: Upload Android APK Artifact
uses: actions/upload-artifact@v4
with:
name: android-apk-${{ github.sha }}
path: |
Android-kotlin-Code/app/build/outputs/apk/**/*.apk
Android-kotlin-Code/app/build/outputs/apk/**/*.json
retention-days: 30
- name: Get APK filename
id: apk_name
run: |
if [ "${{ startsWith(github.ref, 'refs/tags/v') }}" = "true" ]; then
APK_NAME="UUVPN-Android-${{ github.ref_name }}.apk"
else
APK_NAME="UUVPN-Android-${{ github.sha }}.apk"
fi
echo "apk_name=$APK_NAME" >> $GITHUB_OUTPUT
- name: Rename APK for release
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd Android-kotlin-Code/app/build/outputs/apk
find . -name "*.apk" -type f -exec mv {} "${{ steps.apk_name.outputs.apk_name }}" \;
# ==================== iOS 构建 ====================
build-ios:
name: Build iOS IPA
runs-on: macos-latest
if: ${{ github.event.inputs.build_ios != 'false' }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ env.IOS_XCODE_VERSION }}
- name: Show Xcode version
run: |
xcodebuild -version
swift --version
- name: Install Apple Certificate
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
uses: apple-actions/import-codesign-certs@v2
with:
p12-file-base64: ${{ secrets.IOS_CERTIFICATES_P12 }}
p12-password: ${{ secrets.IOS_CERTIFICATES_PASSWORD }}
- name: Install Provisioning Profile
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
echo "${{ secrets.IOS_PROVISIONING_PROFILE }}" | base64 -d > ~/Library/MobileDevice/Provisioning\ Profiles/uuvpn.mobileprovision
- name: Resolve Swift Package Dependencies
run: |
cd iOS-SwiftUI-Code
xcodebuild -resolvePackageDependencies -project uuvpn.xcodeproj -scheme SFI | xcpretty
- name: Build iOS App (Debug)
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
run: |
cd iOS-SwiftUI-Code
xcodebuild clean build \
-project uuvpn.xcodeproj \
-scheme SFI \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 15,OS=latest' \
-configuration Debug \
CODE_SIGN_IDENTITY="" \
CODE_SIGNING_REQUIRED=NO \
| xcpretty
- name: Build and Archive iOS App (Release)
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd iOS-SwiftUI-Code
xcodebuild clean archive \
-project uuvpn.xcodeproj \
-scheme SFI \
-sdk iphoneos \
-configuration Release \
-archivePath build/UUVPN.xcarchive \
CODE_SIGN_IDENTITY="${{ secrets.IOS_SIGNING_IDENTITY }}" \
PROVISIONING_PROFILE_SPECIFIER="uuvpn" \
| xcpretty
- name: Create ExportOptions.plist
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd iOS-SwiftUI-Code
cat > ExportOptions.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>${{ secrets.IOS_TEAM_ID }}</string>
<key>uploadSymbols</key>
<true/>
<key>compileBitcode</key>
<false/>
</dict>
</plist>
EOF
- name: Export IPA
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd iOS-SwiftUI-Code
xcodebuild -exportArchive \
-archivePath build/UUVPN.xcarchive \
-exportPath build/ipa \
-exportOptionsPlist ExportOptions.plist \
| xcpretty
- name: Upload iOS IPA Artifact
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
uses: actions/upload-artifact@v4
with:
name: ios-ipa-${{ github.sha }}
path: iOS-SwiftUI-Code/build/ipa/*.ipa
retention-days: 30
- name: Upload iOS App Artifact (Debug)
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
uses: actions/upload-artifact@v4
with:
name: ios-app-debug-${{ github.sha }}
path: iOS-SwiftUI-Code/build/**/*.app
retention-days: 7
- name: Get IPA filename
id: ipa_name
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
IPA_NAME="UUVPN-iOS-${{ github.ref_name }}.ipa"
echo "ipa_name=$IPA_NAME" >> $GITHUB_OUTPUT
- name: Rename IPA for release
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
cd iOS-SwiftUI-Code/build/ipa
find . -name "*.ipa" -type f -exec mv {} "${{ steps.ipa_name.outputs.ipa_name }}" \;
# ==================== 发布到 GitHub Releases ====================
release:
name: Create GitHub Release
needs: [build-android, build-ios]
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download Android APK
uses: actions/download-artifact@v4
with:
name: android-apk-${{ github.sha }}
path: artifacts/android
- name: Download iOS IPA
uses: actions/download-artifact@v4
with:
name: ios-ipa-${{ github.sha }}
path: artifacts/ios
- name: Get version from tag
id: get_version
run: |
VERSION=${{ github.ref_name }}
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Create Release Notes
id: release_notes
run: |
cat > release_notes.md << EOF
# UUVPN ${{ steps.get_version.outputs.version }}
## 🎉 新版本发布
### 📱 Android 版本
- 支持 Android 5.0+ (推荐 Android 7.0+)
- 支持 armeabi-v7a, arm64-v8a, x86, x86_64 架构
- 基于 CLASH (mihomo) 核心
### 🍎 iOS 版本
- 支持 iOS 15.0+
- 基于 SINGBOX 核心
- 支持 iPhone 和 iPad
## 📥 下载说明
### Android
下载 APK 文件并安装,首次安装需要授予必要权限。
### iOS
IPA 文件需要通过 TestFlight 或第三方工具安装。
## 🔄 更新内容
请查看 [Commits](https://github.com/${{ github.repository }}/commits/${{ github.ref_name }}) 了解详细更新内容。
## 📝 问题反馈
如遇到问题,请在 [Issues](https://github.com/${{ github.repository }}/issues) 中反馈。
EOF
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref_name }}
name: UUVPN ${{ steps.get_version.outputs.version }}
body_path: release_notes.md
draft: false
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
files: |
artifacts/android/*.apk
artifacts/ios/*.ipa
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ==================== 上传到 TestFlight (iOS) ====================
upload-testflight:
name: Upload to TestFlight
needs: [build-ios]
runs-on: macos-latest
if: ${{ startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, 'alpha') }}
steps:
- name: Download iOS IPA
uses: actions/download-artifact@v4
with:
name: ios-ipa-${{ github.sha }}
path: artifacts/ios
- name: Upload to TestFlight
uses: apple-actions/upload-testflight-build@v1
with:
app-path: artifacts/ios/*.ipa
issuer-id: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
api-key-id: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
api-private-key: ${{ secrets.APP_STORE_CONNECT_API_PRIVATE_KEY }}
# ==================== 清理旧构建产物 ====================
cleanup:
name: Cleanup old artifacts
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' }}
steps:
- name: Delete old artifacts
uses: c-hive/gha-remove-artifacts@v1
with:
age: '30 days'
skip-recent: 5
# ==================== 通知 ====================
notify:
name: Send Notification
needs: [build-android, build-ios]
runs-on: ubuntu-latest
if: ${{ always() && github.event_name == 'push' }}
steps:
- name: Send Telegram Notification
uses: appleboy/telegram-action@master
if: ${{ secrets.TELEGRAM_BOT_TOKEN != '' }}
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
format: markdown
message: |
*UUVPN Build Notification*
📦 **Repository**: ${{ github.repository }}
🌿 **Branch**: ${{ github.ref_name }}
🔄 **Commit**: ${{ github.sha }}
✅ **Status**:
- Android: ${{ needs.build-android.result }}
- iOS: ${{ needs.build-ios.result }}
👤 **Author**: ${{ github.actor }}
💬 **Message**: ${{ github.event.head_commit.message }}
[View Build](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
+199
View File
@@ -0,0 +1,199 @@
# UUVPN GitHub Secrets 配置脚本 (PowerShell)
# 用于快速配置 GitHub Actions 所需的 Secrets
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "UUVPN GitHub Secrets 配置工具" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# 检查是否安装了 GitHub CLI
if (-not (Get-Command gh -ErrorAction SilentlyContinue)) {
Write-Host "❌ 错误: 未安装 GitHub CLI" -ForegroundColor Red
Write-Host "请先安装 GitHub CLI: https://cli.github.com/"
exit 1
}
# 检查是否已登录 GitHub
try {
$authStatus = gh auth status 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Host "❌ 错误: 未登录 GitHub CLI" -ForegroundColor Red
Write-Host "请先运行: gh auth login"
exit 1
}
} catch {
Write-Host "❌ 错误: 未登录 GitHub CLI" -ForegroundColor Red
Write-Host "请先运行: gh auth login"
exit 1
}
# 获取仓库信息
try {
$remoteUrl = git remote get-url origin
if ($remoteUrl -match "github\.com[:/](.+?)\.git") {
$repo = $matches[1]
} else {
Write-Host "❌ 错误: 无法获取仓库信息" -ForegroundColor Red
Write-Host "请确保在仓库目录中运行此脚本"
exit 1
}
} catch {
Write-Host "❌ 错误: 无法获取仓库信息" -ForegroundColor Red
Write-Host "请确保在仓库目录中运行此脚本"
exit 1
}
Write-Host "✅ 当前仓库: $repo" -ForegroundColor Green
Write-Host ""
# 配置 Android Secrets
Write-Host "📱 配置 Android Secrets" -ForegroundColor Yellow
Write-Host "----------------------------------------"
$configAndroid = Read-Host "是否配置 Android 签名密钥? (y/n)"
if ($configAndroid -eq "y") {
$keystorePath = Read-Host "密钥库文件路径 (默认: release.keystore)"
if ([string]::IsNullOrWhiteSpace($keystorePath)) {
$keystorePath = "release.keystore"
}
if (-not (Test-Path $keystorePath)) {
Write-Host "❌ 错误: 密钥库文件不存在: $keystorePath" -ForegroundColor Red
Write-Host "请先创建密钥库:"
Write-Host "keytool -genkey -v -keystore release.keystore -alias uuvpn -keyalg RSA -keysize 2048 -validity 10000"
exit 1
}
$keystorePassword = Read-Host "密钥库密码" -AsSecureString
$keystorePasswordPlain = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($keystorePassword)
)
$keyAlias = Read-Host "密钥别名 (默认: uuvpn)"
if ([string]::IsNullOrWhiteSpace($keyAlias)) {
$keyAlias = "uuvpn"
}
$keyPassword = Read-Host "密钥密码" -AsSecureString
$keyPasswordPlain = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($keyPassword)
)
# Base64 编码密钥库
$keystoreBytes = [IO.File]::ReadAllBytes($keystorePath)
$keystoreBase64 = [Convert]::ToBase64String($keystoreBytes)
Write-Host "正在设置 Android Secrets..." -ForegroundColor Cyan
$keystoreBase64 | gh secret set ANDROID_KEYSTORE_BASE64 --repo $repo
$keystorePasswordPlain | gh secret set ANDROID_KEYSTORE_PASSWORD --repo $repo
$keyAlias | gh secret set ANDROID_KEY_ALIAS --repo $repo
$keyPasswordPlain | gh secret set ANDROID_KEY_PASSWORD --repo $repo
Write-Host "✅ Android Secrets 配置完成" -ForegroundColor Green
}
Write-Host ""
# 配置 iOS Secrets
Write-Host "🍎 配置 iOS Secrets" -ForegroundColor Yellow
Write-Host "----------------------------------------"
$configIOS = Read-Host "是否配置 iOS 签名证书? (y/n)"
if ($configIOS -eq "y") {
$certPath = Read-Host "证书文件路径 (.p12)"
if (-not (Test-Path $certPath)) {
Write-Host "❌ 错误: 证书文件不存在: $certPath" -ForegroundColor Red
exit 1
}
$certPassword = Read-Host "证书密码" -AsSecureString
$certPasswordPlain = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($certPassword)
)
$teamId = Read-Host "Team ID"
$signingIdentity = Read-Host "签名身份 (如: Apple Distribution: Your Name (TEAM_ID))"
$profilePath = Read-Host "Provisioning Profile 文件路径 (.mobileprovision)"
if (-not (Test-Path $profilePath)) {
Write-Host "❌ 错误: Provisioning Profile 文件不存在: $profilePath" -ForegroundColor Red
exit 1
}
# Base64 编码
$certBytes = [IO.File]::ReadAllBytes($certPath)
$certBase64 = [Convert]::ToBase64String($certBytes)
$profileBytes = [IO.File]::ReadAllBytes($profilePath)
$profileBase64 = [Convert]::ToBase64String($profileBytes)
Write-Host "正在设置 iOS Secrets..." -ForegroundColor Cyan
$certBase64 | gh secret set IOS_CERTIFICATES_P12 --repo $repo
$certPasswordPlain | gh secret set IOS_CERTIFICATES_PASSWORD --repo $repo
$teamId | gh secret set IOS_TEAM_ID --repo $repo
$signingIdentity | gh secret set IOS_SIGNING_IDENTITY --repo $repo
$profileBase64 | gh secret set IOS_PROVISIONING_PROFILE --repo $repo
Write-Host "✅ iOS Secrets 配置完成" -ForegroundColor Green
}
Write-Host ""
# 配置 App Store Connect Secrets
Write-Host "🚀 配置 App Store Connect Secrets" -ForegroundColor Yellow
Write-Host "----------------------------------------"
$configASC = Read-Host "是否配置 App Store Connect API? (y/n)"
if ($configASC -eq "y") {
$issuerId = Read-Host "Issuer ID"
$apiKeyId = Read-Host "API Key ID"
$p8Path = Read-Host "API Private Key 文件路径 (.p8)"
if (-not (Test-Path $p8Path)) {
Write-Host "❌ 错误: API Private Key 文件不存在: $p8Path" -ForegroundColor Red
exit 1
}
# 读取私钥内容
$apiKey = Get-Content $p8Path -Raw
Write-Host "正在设置 App Store Connect Secrets..." -ForegroundColor Cyan
$issuerId | gh secret set APP_STORE_CONNECT_ISSUER_ID --repo $repo
$apiKeyId | gh secret set APP_STORE_CONNECT_API_KEY_ID --repo $repo
$apiKey | gh secret set APP_STORE_CONNECT_API_PRIVATE_KEY --repo $repo
Write-Host "✅ App Store Connect Secrets 配置完成" -ForegroundColor Green
}
Write-Host ""
# 配置通知 Secrets
Write-Host "📢 配置通知 Secrets" -ForegroundColor Yellow
Write-Host "----------------------------------------"
$configTelegram = Read-Host "是否配置 Telegram 通知? (y/n)"
if ($configTelegram -eq "y") {
$botToken = Read-Host "Bot Token"
$chatId = Read-Host "Chat ID"
Write-Host "正在设置 Telegram Secrets..." -ForegroundColor Cyan
$botToken | gh secret set TELEGRAM_BOT_TOKEN --repo $repo
$chatId | gh secret set TELEGRAM_CHAT_ID --repo $repo
Write-Host "✅ Telegram Secrets 配置完成" -ForegroundColor Green
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "✅ 配置完成!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "当前配置的 Secrets:"
gh secret list --repo $repo
Write-Host ""
Write-Host "下一步:" -ForegroundColor Yellow
Write-Host "1. 推送代码到仓库触发构建"
Write-Host "2. 查看构建状态: https://github.com/$repo/actions"
Write-Host ""
+171
View File
@@ -0,0 +1,171 @@
#!/bin/bash
# UUVPN GitHub Secrets 配置脚本
# 用于快速配置 GitHub Actions 所需的 Secrets
set -e
echo "========================================"
echo "UUVPN GitHub Secrets 配置工具"
echo "========================================"
echo ""
# 检查是否安装了 GitHub CLI
if ! command -v gh &> /dev/null; then
echo "❌ 错误: 未安装 GitHub CLI"
echo "请先安装 GitHub CLI: https://cli.github.com/"
exit 1
fi
# 检查是否已登录 GitHub
if ! gh auth status &> /dev/null; then
echo "❌ 错误: 未登录 GitHub CLI"
echo "请先运行: gh auth login"
exit 1
fi
# 获取仓库信息
REPO=$(git remote get-url origin | sed -E 's|.*github\.com[:/](.*)\.git|\1|')
if [ -z "$REPO" ]; then
echo "❌ 错误: 无法获取仓库信息"
echo "请确保在仓库目录中运行此脚本"
exit 1
fi
echo "✅ 当前仓库: $REPO"
echo ""
# 配置 Android Secrets
echo "📱 配置 Android Secrets"
echo "----------------------------------------"
read -p "是否配置 Android 签名密钥? (y/n): " config_android
if [ "$config_android" = "y" ]; then
read -p "密钥库文件路径 (默认: release.keystore): " keystore_path
keystore_path=${keystore_path:-"release.keystore"}
if [ ! -f "$keystore_path" ]; then
echo "❌ 错误: 密钥库文件不存在: $keystore_path"
echo "请先创建密钥库:"
echo "keytool -genkey -v -keystore release.keystore -alias uuvpn -keyalg RSA -keysize 2048 -validity 10000"
exit 1
fi
read -sp "密钥库密码: " keystore_password
echo ""
read -p "密钥别名 (默认: uuvpn): " key_alias
key_alias=${key_alias:-"uuvpn"}
read -sp "密钥密码: " key_password
echo ""
# Base64 编码密钥库
keystore_base64=$(base64 -i "$keystore_path")
echo "正在设置 Android Secrets..."
gh secret set ANDROID_KEYSTORE_BASE64 --repo "$REPO" --body "$keystore_base64"
gh secret set ANDROID_KEYSTORE_PASSWORD --repo "$REPO" --body "$keystore_password"
gh secret set ANDROID_KEY_ALIAS --repo "$REPO" --body "$key_alias"
gh secret set ANDROID_KEY_PASSWORD --repo "$REPO" --body "$key_password"
echo "✅ Android Secrets 配置完成"
fi
echo ""
# 配置 iOS Secrets
echo "🍎 配置 iOS Secrets"
echo "----------------------------------------"
read -p "是否配置 iOS 签名证书? (y/n): " config_ios
if [ "$config_ios" = "y" ]; then
read -p "证书文件路径 (.p12): " cert_path
if [ ! -f "$cert_path" ]; then
echo "❌ 错误: 证书文件不存在: $cert_path"
exit 1
fi
read -sp "证书密码: " cert_password
echo ""
read -p "Team ID: " team_id
read -p "签名身份 (如: Apple Distribution: Your Name (TEAM_ID)): " signing_identity
read -p "Provisioning Profile 文件路径 (.mobileprovision): " profile_path
if [ ! -f "$profile_path" ]; then
echo "❌ 错误: Provisioning Profile 文件不存在: $profile_path"
exit 1
fi
# Base64 编码
cert_base64=$(base64 -i "$cert_path")
profile_base64=$(base64 -i "$profile_path")
echo "正在设置 iOS Secrets..."
gh secret set IOS_CERTIFICATES_P12 --repo "$REPO" --body "$cert_base64"
gh secret set IOS_CERTIFICATES_PASSWORD --repo "$REPO" --body "$cert_password"
gh secret set IOS_TEAM_ID --repo "$REPO" --body "$team_id"
gh secret set IOS_SIGNING_IDENTITY --repo "$REPO" --body "$signing_identity"
gh secret set IOS_PROVISIONING_PROFILE --repo "$REPO" --body "$profile_base64"
echo "✅ iOS Secrets 配置完成"
fi
echo ""
# 配置 App Store Connect Secrets
echo "🚀 配置 App Store Connect Secrets"
echo "----------------------------------------"
read -p "是否配置 App Store Connect API? (y/n): " config_asc
if [ "$config_asc" = "y" ]; then
read -p "Issuer ID: " issuer_id
read -p "API Key ID: " api_key_id
read -p "API Private Key 文件路径 (.p8): " p8_path
if [ ! -f "$p8_path" ]; then
echo "❌ 错误: API Private Key 文件不存在: $p8_path"
exit 1
fi
# 读取私钥内容
api_private_key=$(cat "$p8_path")
echo "正在设置 App Store Connect Secrets..."
gh secret set APP_STORE_CONNECT_ISSUER_ID --repo "$REPO" --body "$issuer_id"
gh secret set APP_STORE_CONNECT_API_KEY_ID --repo "$REPO" --body "$api_key_id"
gh secret set APP_STORE_CONNECT_API_PRIVATE_KEY --repo "$REPO" --body "$api_private_key"
echo "✅ App Store Connect Secrets 配置完成"
fi
echo ""
# 配置通知 Secrets
echo "📢 配置通知 Secrets"
echo "----------------------------------------"
read -p "是否配置 Telegram 通知? (y/n): " config_telegram
if [ "$config_telegram" = "y" ]; then
read -p "Bot Token: " bot_token
read -p "Chat ID: " chat_id
echo "正在设置 Telegram Secrets..."
gh secret set TELEGRAM_BOT_TOKEN --repo "$REPO" --body "$bot_token"
gh secret set TELEGRAM_CHAT_ID --repo "$REPO" --body "$chat_id"
echo "✅ Telegram Secrets 配置完成"
fi
echo ""
echo "========================================"
echo "✅ 配置完成!"
echo "========================================"
echo ""
echo "当前配置的 Secrets:"
gh secret list --repo "$REPO"
echo ""
echo "下一步:"
echo "1. 推送代码到仓库触发构建"
echo "2. 查看构建状态: https://github.com/$REPO/actions"
echo ""