Add CI/CD configuration and API documentation
This commit is contained in:
@@ -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.
|
||||
@@ -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)
|
||||
|
||||
---
|
||||
|
||||
**配置检查完成! 🎉**
|
||||
@@ -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)
|
||||
- [ ] 已推送代码触发构建
|
||||
- [ ] 构建成功
|
||||
- [ ] 可以下载构建产物
|
||||
|
||||
---
|
||||
|
||||
**祝你构建顺利! 🎉**
|
||||
@@ -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 后,只需推送代码或创建标签,即可自动完成构建和发布!
|
||||
@@ -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 }})
|
||||
@@ -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 ""
|
||||
@@ -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 ""
|
||||
Reference in New Issue
Block a user