docs: 添加 GitHub Actions 构建文档并锁定 libcore 版本
- 添加完整的 GitHub Actions 构建指南文档 - BUILD_GUIDE.md: Android 详细构建指南 - MULTIPLATFORM_GUIDE.md: 多平台构建指南 - HOW_TO_BUILD.md: 分步操作教程 - QUICKSTART.md: 3步快速开始指南 - INDEX.md: 文档总览索引 - README.md: 基础说明 - 创建 docs/ 目录存放项目文档 - 锁定 libcore 子模块到 f993a57 (v3.1.7) - 防止在线编译时使用最新版本 - 确保构建稳定性和一致性
This commit is contained in:
parent
2b8d34086a
commit
d02eed3bd8
311
.github/workflows/BUILD_GUIDE.md
vendored
Normal file
311
.github/workflows/BUILD_GUIDE.md
vendored
Normal file
@ -0,0 +1,311 @@
|
||||
# 📖 GitHub Actions 构建完全指南
|
||||
|
||||
## 🎯 功能概述
|
||||
|
||||
本 workflow 支持:
|
||||
|
||||
✅ **自动编译 libcore.aar** - sing-box 核心库
|
||||
✅ **Release 构建** - 默认生成正式版 APK
|
||||
✅ **可配置 API 域名** - 支持自定义后端域名
|
||||
✅ **可配置 OSS 地址** - 支持自定义配置文件 CDN
|
||||
✅ **分架构打包** - 生成 arm64-v8a / armeabi-v7a / x86_64 版本
|
||||
✅ **自动创建 Release** - 推送标签自动发布
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
### 方法一:手动触发(推荐,支持自定义配置)
|
||||
|
||||
1. **打开 Actions 页面**
|
||||
- 进入 GitHub 仓库
|
||||
- 点击顶部 **Actions** 标签
|
||||
|
||||
2. **选择 Workflow**
|
||||
- 左侧选择 **Build Android APK**
|
||||
- 右侧点击 **Run workflow** 下拉框
|
||||
|
||||
3. **配置参数**
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
|-----|------|--------|
|
||||
| **构建类型** | debug 或 release | `release` |
|
||||
| **API 域名** | 后端 API 服务器域名 | `api.maodag.top` |
|
||||
| **OSS 地址 1** | 配置文件 CDN 地址(香港) | `https://ppp2.oss-cn-hongkong.aliyuncs.com/bear1.txt` |
|
||||
| **OSS 地址 2** | 配置文件 CDN 地址(东京) | `https://xgp3.oss-ap-northeast-1.aliyuncs.com/bear1.txt` |
|
||||
| **OSS 地址 3** | 配置文件 CDN 地址(首尔) | `https://xpp4.oss-ap-northeast-2.aliyuncs.com/bear1.txt` |
|
||||
| **OSS 地址 4** | 配置文件 CDN 地址(新加坡) | `https://xpp5.oss-ap-southeast-1.aliyuncs.com/bear1.txt` |
|
||||
|
||||
4. **开始构建**
|
||||
- 点击绿色 **Run workflow** 按钮
|
||||
- 等待约 30 分钟完成
|
||||
|
||||
5. **下载 APK**
|
||||
- 构建完成后,在运行记录页面找到 **Artifacts** 区域
|
||||
- 下载对应架构的 APK
|
||||
|
||||
---
|
||||
|
||||
### 方法二:推送代码自动构建(使用默认配置)
|
||||
|
||||
```bash
|
||||
# 提交代码
|
||||
git add .
|
||||
git commit -m "feat: 新功能"
|
||||
|
||||
# 推送到 main 分支
|
||||
git push origin main
|
||||
```
|
||||
|
||||
**注意:** 自动触发的构建使用默认配置(`api.maodag.top` 和默认 OSS 地址)
|
||||
|
||||
---
|
||||
|
||||
### 方法三:创建 Release 版本
|
||||
|
||||
```bash
|
||||
# 1. 打标签(必须以 v 开头)
|
||||
git tag v1.0.0
|
||||
|
||||
# 2. 推送标签
|
||||
git push origin v1.0.0
|
||||
|
||||
# 3. 自动触发构建并创建 Release
|
||||
# 访问 https://github.com/你的用户名/LighthouseApp/releases 查看
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 构建产物
|
||||
|
||||
### APK 命名规则
|
||||
|
||||
```
|
||||
BearVPN-{架构}-{类型}-{日期}-{提交哈希}.apk
|
||||
```
|
||||
|
||||
**示例:**
|
||||
```
|
||||
BearVPN-arm64-v8a-release-20251027-abc1234.apk
|
||||
BearVPN-armeabi-v7a-release-20251027-abc1234.apk
|
||||
BearVPN-x86_64-release-20251027-abc1234.apk
|
||||
```
|
||||
|
||||
### 架构说明
|
||||
|
||||
| 架构 | 适用设备 | 推荐度 |
|
||||
|------|---------|-------|
|
||||
| **arm64-v8a** | 2017年后的现代手机 | ⭐⭐⭐⭐⭐ |
|
||||
| **armeabi-v7a** | 2012-2017年的老旧手机 | ⭐⭐ |
|
||||
| **x86_64** | Android 模拟器 | ⭐⭐⭐ |
|
||||
|
||||
**大多数用户应下载 `arm64-v8a` 版本**
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置示例
|
||||
|
||||
### 示例 1:修改 API 域名
|
||||
|
||||
如果你的后端部署在 `api.example.com`:
|
||||
|
||||
1. 手动触发 workflow
|
||||
2. 将 **API 域名** 改为 `api.example.com`
|
||||
3. OSS 地址保持默认
|
||||
4. 点击 Run workflow
|
||||
|
||||
### 示例 2:使用自己的 CDN
|
||||
|
||||
如果你有自己的配置文件 CDN:
|
||||
|
||||
1. 手动触发 workflow
|
||||
2. API 域名保持默认
|
||||
3. 修改 **OSS 地址 1-4** 为你的 CDN 地址,例如:
|
||||
- OSS 地址 1: `https://cdn1.example.com/config.txt`
|
||||
- OSS 地址 2: `https://cdn2.example.com/config.txt`
|
||||
- OSS 地址 3: `https://cdn3.example.com/config.txt`
|
||||
- OSS 地址 4: `https://cdn4.example.com/config.txt`
|
||||
4. 点击 Run workflow
|
||||
|
||||
### 示例 3:完全自定义配置
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.mycompany.com
|
||||
OSS 地址 1: https://config.mycdn.com/v1/nodes.txt
|
||||
OSS 地址 2: https://backup1.mycdn.com/v1/nodes.txt
|
||||
OSS 地址 3: https://backup2.mycdn.com/v1/nodes.txt
|
||||
OSS 地址 4: https://backup3.mycdn.com/v1/nodes.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间
|
||||
|
||||
| 阶段 | 时间 |
|
||||
|-----|------|
|
||||
| 编译 libcore.aar | 10-15 分钟 |
|
||||
| 编译 Flutter APK | 15-20 分钟 |
|
||||
| **总计** | **约 30 分钟** |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 查看构建日志
|
||||
|
||||
1. 打开 Actions 页面
|
||||
2. 点击对应的运行记录
|
||||
3. 点击具体的 job(如 "编译 Android APK")
|
||||
4. 展开步骤查看详细日志
|
||||
|
||||
**关键步骤:**
|
||||
- `⚙️ 配置 API 域名和 OSS 地址` - 查看配置是否正确替换
|
||||
- `🔨 构建 APK` - 查看编译过程
|
||||
- `📦 重命名 APK 文件` - 查看生成的文件名和 MD5
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: 如何验证配置是否生效?
|
||||
|
||||
**A:** 查看 `⚙️ 配置 API 域名和 OSS 地址` 步骤的日志:
|
||||
|
||||
```
|
||||
🔧 配置构建参数:
|
||||
API 域名: api.example.com
|
||||
OSS 地址 1: https://cdn1.example.com/config.txt
|
||||
...
|
||||
|
||||
✅ 配置替换完成
|
||||
|
||||
📄 查看修改后的配置:
|
||||
static List<String> kr_baseDomains = ["api.example.com","api.example.com"];
|
||||
static String kr_currentDomain = "api.example.com";
|
||||
```
|
||||
|
||||
如果看到你设置的域名,说明配置成功。
|
||||
|
||||
---
|
||||
|
||||
### Q2: Release 构建和 Debug 构建有什么区别?
|
||||
|
||||
| 特性 | Debug | Release |
|
||||
|-----|-------|---------|
|
||||
| **文件大小** | 较大 | 较小(优化后) |
|
||||
| **性能** | 较慢 | 快 |
|
||||
| **调试信息** | 包含 | 移除 |
|
||||
| **代码混淆** | 无 | 有 |
|
||||
| **适用场景** | 开发测试 | 正式发布 |
|
||||
|
||||
**推荐:** 生产环境使用 **release** 构建
|
||||
|
||||
---
|
||||
|
||||
### Q3: 如何使用环境变量配置(不想每次手动输入)?
|
||||
|
||||
在仓库 **Settings → Secrets and variables → Actions → Variables** 添加:
|
||||
|
||||
| 变量名 | 值 |
|
||||
|-------|---|
|
||||
| `DEFAULT_API_DOMAIN` | `api.example.com` |
|
||||
| `DEFAULT_OSS_URL_1` | `https://cdn1.example.com/config.txt` |
|
||||
| `DEFAULT_OSS_URL_2` | `https://cdn2.example.com/config.txt` |
|
||||
| `DEFAULT_OSS_URL_3` | `https://cdn3.example.com/config.txt` |
|
||||
| `DEFAULT_OSS_URL_4` | `https://cdn4.example.com/config.txt` |
|
||||
|
||||
然后修改 workflow 文件,将默认值改为:
|
||||
|
||||
```yaml
|
||||
default: ${{ vars.DEFAULT_API_DOMAIN || 'api.maodag.top' }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Q4: 构建失败 - "libcore.aar not found"
|
||||
|
||||
**原因:** libcore 编译失败
|
||||
|
||||
**解决:**
|
||||
1. 检查 `build-libcore` job 的日志
|
||||
2. 确认 Go 环境和 gomobile 安装成功
|
||||
3. 确认 libcore 子模块已正确初始化
|
||||
|
||||
---
|
||||
|
||||
### Q5: 如何配置签名(Release 构建必需)?
|
||||
|
||||
详见主文档 `.github/workflows/README.md` 的签名配置章节。
|
||||
|
||||
---
|
||||
|
||||
## 💡 高级技巧
|
||||
|
||||
### 技巧 1:同时构建多个版本
|
||||
|
||||
修改 `build-apk` job:
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
build_type: [debug, release]
|
||||
api_domain: ['api.maodag.top', 'api.example.com']
|
||||
```
|
||||
|
||||
这样会生成 4 个 APK(2种类型 × 2个域名)
|
||||
|
||||
---
|
||||
|
||||
### 技巧 2:添加构建完成通知
|
||||
|
||||
在 workflow 最后添加:
|
||||
|
||||
```yaml
|
||||
- name: 📢 发送 Telegram 通知
|
||||
if: success()
|
||||
run: |
|
||||
curl -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||||
-d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \
|
||||
-d text="✅ BearVPN 构建成功!下载: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||
```
|
||||
|
||||
需要先配置 `TELEGRAM_BOT_TOKEN` 和 `TELEGRAM_CHAT_ID` Secrets。
|
||||
|
||||
---
|
||||
|
||||
### 技巧 3:缓存加速构建
|
||||
|
||||
workflow 已配置 Go 和 Flutter 缓存,首次构建约 30 分钟,后续构建可缩短至 15-20 分钟。
|
||||
|
||||
---
|
||||
|
||||
## 📊 构建状态徽章
|
||||
|
||||
在 README.md 中添加:
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
效果:
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关文件
|
||||
|
||||
- **主 Workflow:** `.github/workflows/build-android-apk.yml`
|
||||
- **配置文件:** `lib/app/common/app_config.dart`
|
||||
- **libcore 源码:** `libcore/` 子模块
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
- 查看 [GitHub Actions 文档](https://docs.github.com/actions)
|
||||
- 查看构建日志排查问题
|
||||
- 提交 Issue 到仓库
|
||||
|
||||
---
|
||||
|
||||
**生成时间:** 2025-10-27
|
||||
**作者:** Claude Code
|
||||
**版本:** 1.0.0
|
||||
366
.github/workflows/HOW_TO_BUILD.md
vendored
Normal file
366
.github/workflows/HOW_TO_BUILD.md
vendored
Normal file
@ -0,0 +1,366 @@
|
||||
# 🎯 如何在 GitHub 上构建你的应用
|
||||
|
||||
## 📋 前提条件
|
||||
|
||||
✅ 已将配置推送到 GitHub
|
||||
✅ 有 GitHub 账号访问权限
|
||||
|
||||
---
|
||||
|
||||
## 🚀 方法一:手动触发构建(推荐新手)
|
||||
|
||||
### 步骤 1: 访问 GitHub Actions 页面
|
||||
|
||||
1. 打开浏览器,访问你的仓库:
|
||||
```
|
||||
https://github.com/你的用户名/LighthouseApp
|
||||
```
|
||||
|
||||
2. 点击顶部导航栏的 **Actions** 标签
|
||||
```
|
||||
Code Issues Pull requests Actions Projects Wiki Security Insights
|
||||
↑ 点这里
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 2: 选择 Workflow
|
||||
|
||||
在左侧栏看到可用的 workflows:
|
||||
|
||||
```
|
||||
All workflows
|
||||
├── Build Android APK ← 仅构建 Android
|
||||
├── Build Multi-Platform ← 构建所有平台 ⭐推荐
|
||||
└── Build Clash Core
|
||||
```
|
||||
|
||||
**选择建议:**
|
||||
- 🟢 **首次测试:** 选择 **Build Android APK**(快速)
|
||||
- 🔵 **正式发布:** 选择 **Build Multi-Platform**(全平台)
|
||||
|
||||
---
|
||||
|
||||
### 步骤 3: 运行 Workflow
|
||||
|
||||
1. 点击选择的 workflow 名称
|
||||
|
||||
2. 右侧出现 **"Run workflow"** 下拉按钮
|
||||
```
|
||||
[Run workflow ▼]
|
||||
```
|
||||
|
||||
3. 点击下拉按钮,展开配置面板
|
||||
|
||||
---
|
||||
|
||||
### 步骤 4: 配置参数
|
||||
|
||||
#### 如果选择 "Build Android APK":
|
||||
|
||||
```yaml
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Run workflow │
|
||||
├─────────────────────────────────────────┤
|
||||
│ Use workflow from │
|
||||
│ Branch: main [▼] │
|
||||
│ │
|
||||
│ 构建类型 │
|
||||
│ ○ debug │
|
||||
│ ● release │
|
||||
│ │
|
||||
│ API 域名 │
|
||||
│ [api.maodag.top________________] │
|
||||
│ │
|
||||
│ OSS 配置地址 1 │
|
||||
│ [https://ppp2.oss-cn-hongkong...] │
|
||||
│ │
|
||||
│ OSS 配置地址 2 │
|
||||
│ [https://xgp3.oss-ap-northeast-1...] │
|
||||
│ │
|
||||
│ OSS 配置地址 3 │
|
||||
│ [https://xpp4.oss-ap-northeast-2...] │
|
||||
│ │
|
||||
│ OSS 配置地址 4 │
|
||||
│ [https://xpp5.oss-ap-southeast-1...] │
|
||||
│ │
|
||||
│ [Cancel] [Run workflow] │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**配置说明:**
|
||||
- **构建类型:** 选择 `release`(生产环境)
|
||||
- **API 域名:** 填写你的后端域名(默认 `api.maodag.top`)
|
||||
- **OSS 地址:** 保持默认或填写你的 CDN 地址
|
||||
|
||||
#### 如果选择 "Build Multi-Platform":
|
||||
|
||||
额外多一个参数:
|
||||
```yaml
|
||||
│ 构建平台 │
|
||||
│ [android,windows,macos,linux______] │
|
||||
```
|
||||
|
||||
**选项:**
|
||||
- `android` - 仅 Android
|
||||
- `windows` - 仅 Windows
|
||||
- `macos` - 仅 macOS
|
||||
- `linux` - 仅 Linux
|
||||
- `android,windows` - Android + Windows
|
||||
- `android,windows,macos,linux` - 全部平台 ⭐
|
||||
|
||||
---
|
||||
|
||||
### 步骤 5: 开始构建
|
||||
|
||||
1. 检查所有参数是否正确
|
||||
|
||||
2. 点击绿色的 **"Run workflow"** 按钮
|
||||
|
||||
3. 页面刷新,顶部出现黄色进度条:
|
||||
```
|
||||
⚠️ Build Android APK #1
|
||||
Queued - This workflow is in queue waiting to run
|
||||
```
|
||||
|
||||
4. 几秒后变为蓝色(运行中):
|
||||
```
|
||||
🔵 Build Android APK #1
|
||||
In progress - This workflow is currently running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 6: 监控构建进度
|
||||
|
||||
1. 点击运行记录(蓝色行)
|
||||
|
||||
2. 看到构建阶段:
|
||||
```
|
||||
编译 libcore.aar 🔵 Running (15分钟)
|
||||
编译 Android APK ⏸️ Pending
|
||||
```
|
||||
|
||||
3. 可以展开查看实时日志:
|
||||
```
|
||||
▼ 编译 libcore.aar
|
||||
▼ 📦 编译 libcore.aar
|
||||
🚀 开始编译 libcore...
|
||||
[gomobile] installing...
|
||||
✅ libcore.aar 生成成功
|
||||
```
|
||||
|
||||
4. 等待所有阶段完成(约 30-85 分钟)
|
||||
|
||||
---
|
||||
|
||||
### 步骤 7: 下载构建产物
|
||||
|
||||
构建成功后:
|
||||
|
||||
1. 向下滚动到 **Artifacts** 区域
|
||||
```
|
||||
📦 Artifacts
|
||||
|
||||
Produced during runtime
|
||||
|
||||
Name Size Expires
|
||||
apk-arm64-v8a-release 42.5 MB in 30 days [Download]
|
||||
apk-armeabi-v7a-release 38.2 MB in 30 days [Download]
|
||||
apk-x86_64-release 45.1 MB in 30 days [Download]
|
||||
```
|
||||
|
||||
2. 点击 **[Download]** 下载对应文件
|
||||
|
||||
3. 下载的是 ZIP 文件,解压后得到 APK:
|
||||
```
|
||||
apk-arm64-v8a-release.zip
|
||||
└── BearVPN-android-arm64-v8a-release-20251027-abc1234.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ 方法二:推送标签自动构建
|
||||
|
||||
这种方式会自动构建并创建 GitHub Release。
|
||||
|
||||
### 步骤 1: 在本地打标签
|
||||
|
||||
```bash
|
||||
cd /Users/mac/Project/Dart/LighthouseApp
|
||||
|
||||
# 创建标签(版本号必须以 v 开头)
|
||||
git tag v1.0.0
|
||||
|
||||
# 查看标签
|
||||
git tag
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 2: 推送标签到 GitHub
|
||||
|
||||
```bash
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
**输出:**
|
||||
```
|
||||
Enumerating objects: 1, done.
|
||||
Counting objects: 100% (1/1), done.
|
||||
Writing objects: 100% (1/1), 160 bytes | 160.00 KiB/s, done.
|
||||
Total 1 (delta 0), reused 0 (delta 0)
|
||||
To github.com:你的用户名/LighthouseApp.git
|
||||
* [new tag] v1.0.0 -> v1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 3: 自动触发构建
|
||||
|
||||
1. 推送标签后,GitHub 自动检测到标签
|
||||
2. 触发 **Build Multi-Platform** workflow
|
||||
3. 使用默认配置构建所有平台
|
||||
|
||||
---
|
||||
|
||||
### 步骤 4: 查看构建进度
|
||||
|
||||
1. 访问 Actions 页面
|
||||
2. 看到自动创建的构建任务:
|
||||
```
|
||||
🔵 Build Multi-Platform
|
||||
v1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 步骤 5: 下载 Release
|
||||
|
||||
构建成功后:
|
||||
|
||||
1. 访问 **Releases** 页面:
|
||||
```
|
||||
https://github.com/你的用户名/LighthouseApp/releases
|
||||
```
|
||||
|
||||
2. 看到新创建的 Release:
|
||||
```
|
||||
📦 v1.0.0
|
||||
|
||||
Latest Pre-release
|
||||
|
||||
🎉 BearVPN 多平台版本发布
|
||||
|
||||
Assets (7)
|
||||
├── BearVPN-android-arm64-v8a-release-*.apk 42.5 MB
|
||||
├── BearVPN-android-armeabi-v7a-release-*.apk 38.2 MB
|
||||
├── BearVPN-android-x86_64-release-*.apk 45.1 MB
|
||||
├── BearVPN-windows-x64-release-*.zip 52.3 MB
|
||||
├── BearVPN-macos-release-*.zip 48.7 MB
|
||||
├── BearVPN-linux-x64-release-*.tar.gz 45.9 MB
|
||||
└── Source code (zip)
|
||||
```
|
||||
|
||||
3. 直接下载需要的文件
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间参考
|
||||
|
||||
| Workflow | 平台 | 时间 |
|
||||
|---------|------|------|
|
||||
| Build Android APK | Android | 30 分钟 |
|
||||
| Build Multi-Platform | Android | 35 分钟 |
|
||||
| Build Multi-Platform | Windows | 30 分钟 |
|
||||
| Build Multi-Platform | macOS | 35 分钟 |
|
||||
| Build Multi-Platform | Linux | 30 分钟 |
|
||||
| Build Multi-Platform | 全部平台 | **60-85 分钟** |
|
||||
|
||||
**提示:** 平台是并行构建的,不是累加时间。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 推荐流程
|
||||
|
||||
### 首次测试(验证流程)
|
||||
|
||||
```
|
||||
1. 选择 "Build Android APK"
|
||||
2. 使用默认配置
|
||||
3. 运行构建
|
||||
4. 等待 30 分钟
|
||||
5. 下载 arm64-v8a APK
|
||||
6. 安装测试
|
||||
```
|
||||
|
||||
### 正式发布(生产环境)
|
||||
|
||||
```
|
||||
1. 确保代码已测试
|
||||
2. 本地打标签: git tag v1.0.0
|
||||
3. 推送标签: git push origin v1.0.0
|
||||
4. 等待 60-85 分钟
|
||||
5. 在 Releases 页面下载所有平台
|
||||
6. 分发给用户
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: 找不到 "Run workflow" 按钮
|
||||
|
||||
**原因:** 可能还在查看历史运行记录
|
||||
|
||||
**解决:**
|
||||
1. 点击左侧的 workflow 名称
|
||||
2. 确保在 workflow 主页面
|
||||
3. 右侧会出现 "Run workflow" 按钮
|
||||
|
||||
---
|
||||
|
||||
### Q2: 构建失败
|
||||
|
||||
**排查步骤:**
|
||||
1. 点击失败的运行记录
|
||||
2. 展开红色的步骤
|
||||
3. 查看错误日志
|
||||
4. 常见错误:
|
||||
- libcore 编译失败 → 检查 Go 环境
|
||||
- APK 构建失败 → 检查 Flutter 依赖
|
||||
|
||||
---
|
||||
|
||||
### Q3: Artifacts 下载后是空的
|
||||
|
||||
**原因:** 构建可能失败
|
||||
|
||||
**解决:**
|
||||
1. 检查构建日志
|
||||
2. 确保所有步骤都是绿色 ✅
|
||||
3. 重新运行构建
|
||||
|
||||
---
|
||||
|
||||
### Q4: 如何修改 API 域名
|
||||
|
||||
**方法 1:** 手动触发时修改参数
|
||||
|
||||
**方法 2:** 修改代码中的默认值
|
||||
```dart
|
||||
// lib/app/common/app_config.dart
|
||||
static String kr_currentDomain = "api.example.com";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
- **查看详细文档:** `.github/workflows/INDEX.md`
|
||||
- **快速开始:** `.github/workflows/QUICKSTART.md`
|
||||
- **问题反馈:** GitHub Issues
|
||||
|
||||
---
|
||||
|
||||
**准备好了吗?立即开始构建!** 🚀
|
||||
318
.github/workflows/INDEX.md
vendored
Normal file
318
.github/workflows/INDEX.md
vendored
Normal file
@ -0,0 +1,318 @@
|
||||
# 📚 GitHub Actions 构建系统总览
|
||||
|
||||
## 🎯 快速导航
|
||||
|
||||
| 文档 | 用途 | 适合人群 |
|
||||
|-----|------|---------|
|
||||
| **[QUICKSTART.md](./QUICKSTART.md)** | 3步快速开始 | 新手 |
|
||||
| **[README.md](./README.md)** | 基础说明 | 所有人 |
|
||||
| **[BUILD_GUIDE.md](./BUILD_GUIDE.md)** | Android 详细指南 | Android 开发者 |
|
||||
| **[MULTIPLATFORM_GUIDE.md](./MULTIPLATFORM_GUIDE.md)** | 多平台构建指南 | 全平台开发者 |
|
||||
|
||||
---
|
||||
|
||||
## 📋 可用的 Workflows
|
||||
|
||||
### 1. `build-android-apk.yml` - Android 专用构建
|
||||
|
||||
**功能:**
|
||||
- ✅ 编译 libcore.aar
|
||||
- ✅ 构建 Android APK (arm64/armv7/x86_64)
|
||||
- ✅ 配置 API 域名和 OSS 地址
|
||||
- ✅ Release 构建
|
||||
|
||||
**触发条件:**
|
||||
- 推送到 main/develop 分支
|
||||
- 创建 v* 标签
|
||||
- 手动触发
|
||||
|
||||
**文档:** [BUILD_GUIDE.md](./BUILD_GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
### 2. `build-multiplatform.yml` - 多平台构建 ⭐推荐
|
||||
|
||||
**功能:**
|
||||
- ✅ Android APK
|
||||
- ✅ Windows 可执行文件
|
||||
- ✅ macOS 应用
|
||||
- ✅ Linux 可执行文件
|
||||
- ✅ 可选择构建平台
|
||||
- ✅ 统一配置管理
|
||||
|
||||
**触发条件:**
|
||||
- 推送到 main/develop 分支
|
||||
- 创建 v* 标签
|
||||
- 手动触发
|
||||
|
||||
**文档:** [MULTIPLATFORM_GUIDE.md](./MULTIPLATFORM_GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
### 3. `build-clash-core.yml` - Clash 核心编译
|
||||
|
||||
**功能:**
|
||||
- 编译 Clash Meta 核心
|
||||
- 支持多架构 (arm64/armv7/x86_64)
|
||||
|
||||
**触发条件:**
|
||||
- core/ 目录变更
|
||||
- 手动触发
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用建议
|
||||
|
||||
### 场景 1: 日常开发(仅 Android)
|
||||
|
||||
**使用:** `build-android-apk.yml`
|
||||
```bash
|
||||
# 推送代码自动触发
|
||||
git push origin main
|
||||
```
|
||||
|
||||
**时间:** 约 30 分钟
|
||||
**产物:** 3 个 Android APK
|
||||
|
||||
---
|
||||
|
||||
### 场景 2: 正式发布(所有平台)
|
||||
|
||||
**使用:** `build-multiplatform.yml`
|
||||
```bash
|
||||
# 1. 打标签
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
|
||||
# 2. 自动构建所有平台并创建 Release
|
||||
```
|
||||
|
||||
**时间:** 约 60-85 分钟(并行)
|
||||
**产物:** Android + Windows + macOS + Linux
|
||||
|
||||
---
|
||||
|
||||
### 场景 3: 测试特定平台
|
||||
|
||||
**使用:** `build-multiplatform.yml` 手动触发
|
||||
```yaml
|
||||
构建平台: android,windows # 只构建这两个
|
||||
```
|
||||
|
||||
**时间:** 约 35 分钟
|
||||
**产物:** 指定平台
|
||||
|
||||
---
|
||||
|
||||
## 📦 构建产物对比
|
||||
|
||||
### Android 专用构建
|
||||
|
||||
```
|
||||
BearVPN-android-arm64-v8a-release-20251027-abc1234.apk
|
||||
BearVPN-android-armeabi-v7a-release-20251027-abc1234.apk
|
||||
BearVPN-android-x86_64-release-20251027-abc1234.apk
|
||||
```
|
||||
|
||||
### 多平台构建
|
||||
|
||||
```
|
||||
# Android
|
||||
BearVPN-android-arm64-v8a-release-20251027-abc1234.apk
|
||||
BearVPN-android-armeabi-v7a-release-20251027-abc1234.apk
|
||||
BearVPN-android-x86_64-release-20251027-abc1234.apk
|
||||
|
||||
# Windows
|
||||
BearVPN-windows-x64-release-20251027-abc1234.zip
|
||||
|
||||
# macOS
|
||||
BearVPN-macos-release-20251027-abc1234.zip
|
||||
|
||||
# Linux
|
||||
BearVPN-linux-x64-release-20251027-abc1234.tar.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 配置参数说明
|
||||
|
||||
### 所有 Workflow 通用参数
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|-----|-------|------|
|
||||
| **构建类型** | `release` | debug 或 release |
|
||||
| **API 域名** | `api.maodag.top` | 后端服务器地址 |
|
||||
| **OSS 地址 1** | 香港 CDN | 配置文件源 |
|
||||
| **OSS 地址 2** | 东京 CDN | 备用配置源 |
|
||||
| **OSS 地址 3** | 首尔 CDN | 备用配置源 |
|
||||
| **OSS 地址 4** | 新加坡 CDN | 备用配置源 |
|
||||
|
||||
### 多平台专用参数
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|-----|-------|------|
|
||||
| **构建平台** | `android,windows,macos,linux` | 选择构建的平台 |
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间对比
|
||||
|
||||
| Workflow | 单平台 | 全平台 |
|
||||
|---------|-------|-------|
|
||||
| **Android 专用** | 30分钟 | - |
|
||||
| **多平台** | 30-40分钟 | 60-85分钟 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 选择 Workflow 的建议
|
||||
|
||||
### 选择 `build-android-apk.yml` 如果:
|
||||
|
||||
- ✅ 只需要 Android 版本
|
||||
- ✅ 快速迭代开发
|
||||
- ✅ CI/CD 自动触发
|
||||
|
||||
### 选择 `build-multiplatform.yml` 如果:
|
||||
|
||||
- ✅ 需要桌面版本
|
||||
- ✅ 正式版本发布
|
||||
- ✅ 需要灵活选择平台
|
||||
|
||||
---
|
||||
|
||||
## 🔧 环境配置
|
||||
|
||||
### 必需的 Secrets(用于 Release 签名)
|
||||
|
||||
**Android:**
|
||||
```
|
||||
KEYSTORE_BASE64
|
||||
KEYSTORE_PASSWORD
|
||||
KEY_ALIAS
|
||||
KEY_PASSWORD
|
||||
```
|
||||
|
||||
**macOS:**
|
||||
```
|
||||
MACOS_CERTIFICATE_BASE64
|
||||
MACOS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```
|
||||
WINDOWS_CERTIFICATE_BASE64
|
||||
WINDOWS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
**说明:** 如果不配置签名,可以使用 debug 构建。
|
||||
|
||||
---
|
||||
|
||||
## 📊 构建流程图
|
||||
|
||||
### Android 专用
|
||||
|
||||
```
|
||||
Checkout 代码
|
||||
↓
|
||||
编译 libcore.aar (15min)
|
||||
↓
|
||||
配置 API/OSS
|
||||
↓
|
||||
构建 APK (20min)
|
||||
↓
|
||||
上传产物
|
||||
```
|
||||
|
||||
### 多平台
|
||||
|
||||
```
|
||||
Checkout 代码
|
||||
↓
|
||||
编译 libcore.aar (15min)
|
||||
↓
|
||||
├─→ Android (20min) ─┐
|
||||
├─→ Windows (15min) ─┤
|
||||
├─→ macOS (20min) ─┼─→ 创建 Release
|
||||
└─→ Linux (15min) ─┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 故障排查
|
||||
|
||||
### 问题 1: libcore 编译失败
|
||||
|
||||
**检查:**
|
||||
1. Go 环境是否正常
|
||||
2. gomobile 是否安装
|
||||
3. 网络连接(下载依赖)
|
||||
|
||||
**日志位置:** `build-libcore` job
|
||||
|
||||
---
|
||||
|
||||
### 问题 2: Android 构建失败
|
||||
|
||||
**常见原因:**
|
||||
- libcore.aar 未生成
|
||||
- Gradle 依赖问题
|
||||
- 签名配置错误
|
||||
|
||||
**解决:** 查看 `build-android` job 日志
|
||||
|
||||
---
|
||||
|
||||
### 问题 3: macOS 构建失败
|
||||
|
||||
**常见原因:**
|
||||
- 签名证书未配置
|
||||
- Xcode 版本不兼容
|
||||
|
||||
**解决:**
|
||||
- 使用 debug 构建
|
||||
- 或配置签名证书
|
||||
|
||||
---
|
||||
|
||||
## 💡 高级用法
|
||||
|
||||
### 1. 定时构建
|
||||
|
||||
添加到 workflow:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # 每天UTC 2:00
|
||||
```
|
||||
|
||||
### 2. PR 自动构建
|
||||
|
||||
已配置:推送 PR 到 main 分支自动触发
|
||||
|
||||
### 3. 构建通知
|
||||
|
||||
可集成 Telegram/Slack/钉钉通知
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
- **查看文档:** 本目录下的 Markdown 文件
|
||||
- **查看日志:** GitHub Actions 页面
|
||||
- **提交问题:** Issues 页面
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
- [GitHub Actions 文档](https://docs.github.com/actions)
|
||||
- [Flutter CI/CD](https://docs.flutter.dev/deployment/cd)
|
||||
- [sing-box 文档](https://sing-box.sagernet.org/)
|
||||
|
||||
---
|
||||
|
||||
**版本:** 1.0.0
|
||||
**更新:** 2025-10-27
|
||||
**作者:** Claude Code
|
||||
407
.github/workflows/MULTIPLATFORM_GUIDE.md
vendored
Normal file
407
.github/workflows/MULTIPLATFORM_GUIDE.md
vendored
Normal file
@ -0,0 +1,407 @@
|
||||
# 🌐 多平台构建完全指南
|
||||
|
||||
## 📋 支持的平台
|
||||
|
||||
✅ **Android** - arm64-v8a / armeabi-v7a / x86_64
|
||||
✅ **Windows** - x64
|
||||
✅ **macOS** - Universal (Intel + Apple Silicon)
|
||||
✅ **Linux** - x64
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 方法 1: 构建所有平台(推荐)
|
||||
|
||||
1. 打开 GitHub Actions 页面
|
||||
2. 选择 **Build Multi-Platform**
|
||||
3. 点击 **Run workflow**
|
||||
4. 配置参数:
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.maodag.top
|
||||
OSS 地址 1-4: 使用默认值
|
||||
构建平台: android,windows,macos,linux # 构建所有平台
|
||||
```
|
||||
|
||||
5. 点击 **Run workflow** 开始
|
||||
|
||||
---
|
||||
|
||||
### 方法 2: 仅构建指定平台
|
||||
|
||||
**场景:** 只需要 Android 和 Windows 版本
|
||||
|
||||
```yaml
|
||||
构建平台: android,windows # 只构建这两个平台
|
||||
```
|
||||
|
||||
**可选值:**
|
||||
- `android` - 仅 Android
|
||||
- `windows` - 仅 Windows
|
||||
- `macos` - 仅 macOS
|
||||
- `linux` - 仅 Linux
|
||||
- `android,windows` - Android + Windows
|
||||
- `android,windows,macos,linux` - 全部平台
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间估算
|
||||
|
||||
| 平台 | 时间 | 说明 |
|
||||
|-----|------|-----|
|
||||
| **libcore** | 10-15分钟 | Android 依赖 |
|
||||
| **Android** | 15-20分钟 | 3个架构APK |
|
||||
| **Windows** | 10-15分钟 | x64可执行文件 |
|
||||
| **macOS** | 15-20分钟 | Universal应用 |
|
||||
| **Linux** | 10-15分钟 | x64可执行文件 |
|
||||
| **总计(全平台)** | **60-85分钟** | 并行构建 |
|
||||
|
||||
---
|
||||
|
||||
## 📦 构建产物
|
||||
|
||||
### Android
|
||||
|
||||
```
|
||||
BearVPN-android-arm64-v8a-release-20251027-abc1234.apk (推荐)
|
||||
BearVPN-android-armeabi-v7a-release-20251027-abc1234.apk (老设备)
|
||||
BearVPN-android-x86_64-release-20251027-abc1234.apk (模拟器)
|
||||
```
|
||||
|
||||
**安装:** 直接点击APK安装
|
||||
|
||||
---
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
BearVPN-windows-x64-release-20251027-abc1234.zip
|
||||
```
|
||||
|
||||
**内容结构:**
|
||||
```
|
||||
BearVPN.exe # 主程序
|
||||
flutter_windows.dll # Flutter运行时
|
||||
data/ # 资源文件
|
||||
```
|
||||
|
||||
**运行:**
|
||||
1. 解压 ZIP 文件
|
||||
2. 双击 `BearVPN.exe` 运行
|
||||
3. 如提示缺少依赖,安装 [VC++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
|
||||
---
|
||||
|
||||
### macOS
|
||||
|
||||
```
|
||||
BearVPN-macos-release-20251027-abc1234.zip
|
||||
```
|
||||
|
||||
**内容:**
|
||||
```
|
||||
BearVPN.app # 应用程序包(Universal)
|
||||
```
|
||||
|
||||
**安装:**
|
||||
1. 解压 ZIP 文件
|
||||
2. 将 `BearVPN.app` 拖到 **应用程序** 文件夹
|
||||
3. 首次运行右键点击 → 打开(绕过 Gatekeeper)
|
||||
|
||||
**支持架构:**
|
||||
- Intel (x86_64)
|
||||
- Apple Silicon (arm64)
|
||||
|
||||
---
|
||||
|
||||
### Linux
|
||||
|
||||
```
|
||||
BearVPN-linux-x64-release-20251027-abc1234.tar.gz
|
||||
```
|
||||
|
||||
**内容结构:**
|
||||
```
|
||||
bearvpn # 可执行文件
|
||||
lib/ # 共享库
|
||||
data/ # 资源文件
|
||||
```
|
||||
|
||||
**运行:**
|
||||
```bash
|
||||
# 1. 解压
|
||||
tar -xzf BearVPN-linux-x64-release-*.tar.gz
|
||||
cd bundle
|
||||
|
||||
# 2. 添加执行权限
|
||||
chmod +x bearvpn
|
||||
|
||||
# 3. 运行
|
||||
./bearvpn
|
||||
```
|
||||
|
||||
**依赖要求:**
|
||||
- GTK+ 3
|
||||
- libstdc++12
|
||||
|
||||
**安装依赖(Ubuntu/Debian):**
|
||||
```bash
|
||||
sudo apt-get install libgtk-3-0 libstdc++6
|
||||
```
|
||||
|
||||
**安装依赖(Fedora/RHEL):**
|
||||
```bash
|
||||
sudo dnf install gtk3 libstdc++
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置说明
|
||||
|
||||
### 所有平台通用配置
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|-----|-------|------|
|
||||
| **构建类型** | `release` | debug 或 release |
|
||||
| **API 域名** | `api.maodag.top` | 后端服务器 |
|
||||
| **OSS 地址 1** | 香港 CDN | 配置文件源 |
|
||||
| **OSS 地址 2** | 东京 CDN | 备用源 |
|
||||
| **OSS 地址 3** | 首尔 CDN | 备用源 |
|
||||
| **OSS 地址 4** | 新加坡 CDN | 备用源 |
|
||||
| **构建平台** | `android,windows,macos,linux` | 选择平台 |
|
||||
|
||||
---
|
||||
|
||||
## 📥 下载构建产物
|
||||
|
||||
### 从 Actions 页面下载
|
||||
|
||||
1. 打开运行记录
|
||||
2. 滚动到 **Artifacts** 区域
|
||||
3. 下载对应平台:
|
||||
- `android-apk` - Android APK (所有架构)
|
||||
- `windows-x64` - Windows 可执行程序
|
||||
- `macos-app` - macOS 应用
|
||||
- `linux-x64` - Linux 可执行程序
|
||||
|
||||
### 从 Releases 下载(推送标签时)
|
||||
|
||||
1. 访问 Releases 页面
|
||||
2. 选择版本
|
||||
3. 在 Assets 中下载对应平台文件
|
||||
|
||||
---
|
||||
|
||||
## 🎯 使用场景
|
||||
|
||||
### 场景 1: 开发测试(仅 Android)
|
||||
|
||||
```yaml
|
||||
构建类型: debug
|
||||
构建平台: android
|
||||
API 域名: api.test.com
|
||||
```
|
||||
|
||||
**优点:** 快速,约20分钟
|
||||
|
||||
---
|
||||
|
||||
### 场景 2: 正式发布(全平台)
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
构建平台: android,windows,macos,linux
|
||||
API 域名: api.maodag.top
|
||||
```
|
||||
|
||||
**优点:** 一次构建,覆盖所有用户
|
||||
|
||||
---
|
||||
|
||||
### 场景 3: 仅桌面平台
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
构建平台: windows,macos,linux
|
||||
```
|
||||
|
||||
**用途:** 桌面版更新
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: Windows 构建失败 - "7z command not found"
|
||||
|
||||
**原因:** Windows runner 默认有 7z
|
||||
|
||||
**解决:** 检查构建日志,可能是其他错误
|
||||
|
||||
---
|
||||
|
||||
### Q2: macOS 构建失败 - "Code signing required"
|
||||
|
||||
**原因:** Release 构建需要签名
|
||||
|
||||
**解决方案:**
|
||||
|
||||
**方法 1:** 使用 debug 构建(测试用)
|
||||
|
||||
**方法 2:** 配置签名证书(生产用)
|
||||
```yaml
|
||||
# 在 Secrets 中添加
|
||||
MACOS_CERTIFICATE_BASE64
|
||||
MACOS_CERTIFICATE_PASSWORD
|
||||
MACOS_KEYCHAIN_PASSWORD
|
||||
PROVISIONING_PROFILE_BASE64
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Q3: Linux 运行时提示缺少库
|
||||
|
||||
**错误:**
|
||||
```
|
||||
error while loading shared libraries: libgtk-3.so.0
|
||||
```
|
||||
|
||||
**解决:**
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install libgtk-3-0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Q4: 如何只更新某个平台?
|
||||
|
||||
**方法 1:** 手动触发指定平台
|
||||
```yaml
|
||||
构建平台: android # 只构建 Android
|
||||
```
|
||||
|
||||
**方法 2:** 创建平台专用 workflow(推荐)
|
||||
|
||||
---
|
||||
|
||||
### Q5: 构建时间太长怎么办?
|
||||
|
||||
**优化方案:**
|
||||
|
||||
1. **仅构建需要的平台**
|
||||
```yaml
|
||||
构建平台: android # 而不是全部
|
||||
```
|
||||
|
||||
2. **使用缓存**(已配置)
|
||||
- Flutter SDK 缓存
|
||||
- Gradle 缓存
|
||||
- Go modules 缓存
|
||||
|
||||
3. **分批构建**
|
||||
- 白天构建 Android/Windows
|
||||
- 晚上构建 macOS/Linux
|
||||
|
||||
---
|
||||
|
||||
## 💡 高级用法
|
||||
|
||||
### 技巧 1: 矩阵构建多个配置
|
||||
|
||||
修改 workflow:
|
||||
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
api_domain: ['api.prod.com', 'api.test.com']
|
||||
platform: ['android', 'windows', 'macos', 'linux']
|
||||
```
|
||||
|
||||
**效果:** 生成 8 个版本(2域名 × 4平台)
|
||||
|
||||
---
|
||||
|
||||
### 技巧 2: 定时自动构建
|
||||
|
||||
添加到 workflow:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # 每天凌晨2点(UTC)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 技巧 3: 构建完成通知
|
||||
|
||||
添加 Telegram 通知:
|
||||
|
||||
```yaml
|
||||
- name: 📢 通知
|
||||
run: |
|
||||
curl -X POST "https://api.telegram.org/bot${{ secrets.TG_BOT_TOKEN }}/sendMessage" \
|
||||
-d chat_id=${{ secrets.TG_CHAT_ID }} \
|
||||
-d text="✅ 多平台构建完成!"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 构建并行示意图
|
||||
|
||||
```
|
||||
libcore (15min)
|
||||
↓
|
||||
├─→ Android (20min) ─┐
|
||||
├─→ Windows (15min) ─┤
|
||||
├─→ macOS (20min) ─┼─→ Release (2min)
|
||||
└─→ Linux (15min) ─┘
|
||||
|
||||
总时间: 约 35-40分钟(并行)
|
||||
如果串行: 约 85分钟
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 安全建议
|
||||
|
||||
### Release 版本签名
|
||||
|
||||
**Android:**
|
||||
```yaml
|
||||
# Secrets 配置
|
||||
KEYSTORE_BASE64
|
||||
KEYSTORE_PASSWORD
|
||||
KEY_ALIAS
|
||||
KEY_PASSWORD
|
||||
```
|
||||
|
||||
**macOS:**
|
||||
```yaml
|
||||
# Secrets 配置
|
||||
MACOS_CERTIFICATE_BASE64
|
||||
MACOS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```yaml
|
||||
# Secrets 配置
|
||||
WINDOWS_CERTIFICATE_BASE64
|
||||
WINDOWS_CERTIFICATE_PASSWORD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
- 查看 [GitHub Actions 文档](https://docs.github.com/actions)
|
||||
- 查看 [Flutter 桌面支持](https://docs.flutter.dev/desktop)
|
||||
- 提交 Issue
|
||||
|
||||
---
|
||||
|
||||
**版本:** 1.0.0
|
||||
**更新:** 2025-10-27
|
||||
**作者:** Claude Code
|
||||
78
.github/workflows/QUICKSTART.md
vendored
Normal file
78
.github/workflows/QUICKSTART.md
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
# 🚀 GitHub Actions 快速开始
|
||||
|
||||
## 📋 3 步开始使用
|
||||
|
||||
### 步骤 1: 推送配置文件
|
||||
|
||||
```bash
|
||||
cd /Users/mac/Project/Dart/LighthouseApp
|
||||
|
||||
git add .github/workflows/
|
||||
git commit -m "feat: 添加 GitHub Actions 自动构建配置"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### 步骤 2: 手动触发构建
|
||||
|
||||
1. 打开 GitHub 仓库页面
|
||||
2. 点击 **Actions** 标签
|
||||
3. 左侧选择 **Build Android APK**
|
||||
4. 右侧点击 **Run workflow** 下拉按钮
|
||||
5. 配置参数(可以使用默认值):
|
||||
|
||||
```
|
||||
构建类型: release
|
||||
API 域名: api.maodag.top
|
||||
OSS 地址 1-4: 使用默认值
|
||||
```
|
||||
|
||||
6. 点击绿色 **Run workflow** 按钮
|
||||
|
||||
### 步骤 3: 下载 APK
|
||||
|
||||
- 等待约 30 分钟
|
||||
- 在构建记录页面找到 **Artifacts**
|
||||
- 下载 `apk-arm64-v8a-release`(推荐)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 自定义配置示例
|
||||
|
||||
### 场景 1: 更换 API 域名
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.example.com ← 修改这里
|
||||
OSS 地址: 保持默认
|
||||
```
|
||||
|
||||
### 场景 2: 使用自己的 CDN
|
||||
|
||||
```yaml
|
||||
构建类型: release
|
||||
API 域名: api.maodag.top
|
||||
OSS 地址 1: https://your-cdn.com/config1.txt ← 修改这里
|
||||
OSS 地址 2: https://your-cdn.com/config2.txt ← 修改这里
|
||||
OSS 地址 3: https://your-cdn.com/config3.txt ← 修改这里
|
||||
OSS 地址 4: https://your-cdn.com/config4.txt ← 修改这里
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 详细文档
|
||||
|
||||
- **完整指南:** [BUILD_GUIDE.md](./BUILD_GUIDE.md)
|
||||
- **基础说明:** [README.md](./README.md)
|
||||
|
||||
---
|
||||
|
||||
## ✅ 核心功能
|
||||
|
||||
✅ **Release 构建** - 生产环境优化版本
|
||||
✅ **可配置域名** - 支持自定义 API 和 CDN
|
||||
✅ **分架构打包** - arm64/armv7/x86_64
|
||||
✅ **自动 Release** - 推送标签自动发布
|
||||
|
||||
---
|
||||
|
||||
**需要帮助?** 查看 [BUILD_GUIDE.md](./BUILD_GUIDE.md)
|
||||
90
.github/workflows/README.md
vendored
Normal file
90
.github/workflows/README.md
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
# GitHub Actions 构建说明
|
||||
|
||||
## 📋 工作流概览
|
||||
|
||||
### `build-android-apk.yml` - Android APK 自动构建
|
||||
|
||||
**触发条件:**
|
||||
- ✅ 推送到 `main` 或 `develop` 分支
|
||||
- ✅ 打 `v*` 标签时自动创建 Release
|
||||
- ✅ 手动触发(Actions 页面点击 "Run workflow")
|
||||
|
||||
**构建产物:**
|
||||
- `libcore.aar` - sing-box 核心库
|
||||
- `BearVPN-arm64-v8a-*.apk` - 64位 ARM 版本(推荐)
|
||||
- `BearVPN-armeabi-v7a-*.apk` - 32位 ARM 版本
|
||||
- `BearVPN-x86_64-*.apk` - 模拟器版本
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
### 方法一:推送代码自动构建
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: 新功能"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### 方法二:手动触发
|
||||
|
||||
1. 打开仓库 **Actions** 页面
|
||||
2. 点击 **Build Android APK**
|
||||
3. 点击 **Run workflow**
|
||||
|
||||
### 方法三:创建 Release
|
||||
|
||||
```bash
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 下载构建产物
|
||||
|
||||
- **Actions 页面:** 点击运行记录 → Artifacts 区域下载
|
||||
- **Releases 页面:** 选择版本 → Assets 下载
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置 Release 签名(可选)
|
||||
|
||||
1. 生成密钥:
|
||||
```bash
|
||||
keytool -genkey -v -keystore release.keystore -alias bearvpn -keyalg RSA -keysize 2048 -validity 10000
|
||||
```
|
||||
|
||||
2. 转换为 Base64:
|
||||
```bash
|
||||
base64 release.keystore > keystore.base64.txt
|
||||
```
|
||||
|
||||
3. 在 GitHub 仓库 **Settings → Secrets** 添加:
|
||||
- `KEYSTORE_BASE64`
|
||||
- `KEYSTORE_PASSWORD`
|
||||
- `KEY_ALIAS`
|
||||
- `KEY_PASSWORD`
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 构建时间
|
||||
|
||||
- libcore.aar: 10-15 分钟
|
||||
- Flutter APK: 15-20 分钟
|
||||
- **总计: 约 30 分钟**
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
**Q: 构建失败 "libcore.aar not found"**
|
||||
A: 检查 libcore 子模块是否正确初始化
|
||||
|
||||
**Q: Release 未创建**
|
||||
A: 标签必须以 `v` 开头,如 `v1.0.0`
|
||||
|
||||
---
|
||||
|
||||
生成时间: 2025-10-27
|
||||
255
docs/CLASH_ARCHITECTURE.md
Normal file
255
docs/CLASH_ARCHITECTURE.md
Normal file
@ -0,0 +1,255 @@
|
||||
# Clash Meta 核心架构文档
|
||||
|
||||
## 架构概览
|
||||
|
||||
LighthouseApp 使用 Clash Meta (Mihomo) 作为核心代理引擎,替代原有的 sing-box 实现。
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Flutter Application │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Dart Layer │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ KRClashImp (lib/app/services/clash_imp/) │ │
|
||||
│ │ • kr_clash_imp.dart - 核心封装 │ │
|
||||
│ │ • clash_ffi.dart - FFI 绑定 │ │
|
||||
│ │ • clash_config_generator - YAML 配置生成 │ │
|
||||
│ │ • clash_service_handler - 服务处理器 │ │
|
||||
│ └──────────────────┬───────────────────────────────────┘ │
|
||||
│ │ dart:ffi │
|
||||
├─────────────────────┼───────────────────────────────────────┤
|
||||
│ Android Native │ │
|
||||
│ ┌──────────────────▼───────────────────────────────────┐ │
|
||||
│ │ ClashService (Kotlin) │ │
|
||||
│ │ • VPNService.kt - VPN 服务入口 │ │
|
||||
│ │ • ClashService.kt - Clash 服务管理 │ │
|
||||
│ │ • Service Isolate - 后台 Dart 运行时 │ │
|
||||
│ └──────────────────┬───────────────────────────────────┘ │
|
||||
│ │ JNI │
|
||||
│ ┌──────────────────▼───────────────────────────────────┐ │
|
||||
│ │ libclash.so (Go + C) │ │
|
||||
│ │ • quickStart() - 启动核心 │ │
|
||||
│ │ • getAndroidVpnOptions() - 获取 VPN 配置 │ │
|
||||
│ │ • startTUN() - 启动 TUN 设备 │ │
|
||||
│ │ • getTraffic() - 流量统计 │ │
|
||||
│ └──────────────────┬───────────────────────────────────┘ │
|
||||
│ │ │
|
||||
├─────────────────────┼───────────────────────────────────────┤
|
||||
│ Go Core │ │
|
||||
│ ┌──────────────────▼───────────────────────────────────┐ │
|
||||
│ │ Clash.Meta (Mihomo) │ │
|
||||
│ │ • TUN 设备管理 │ │
|
||||
│ │ • 路由策略 (bypass-LAN) │ │
|
||||
│ │ • 代理协议支持 (SS/Trojan/VMess/...) │ │
|
||||
│ │ • DNS 解析 │ │
|
||||
│ │ • 流量统计 │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 核心组件
|
||||
|
||||
### 1. Dart FFI 层 (`kr_clash_imp.dart`)
|
||||
|
||||
**职责:**
|
||||
- 提供与 Go 核心的 FFI 通信接口
|
||||
- 管理核心生命周期 (启动/停止)
|
||||
- 配置文件生成和管理
|
||||
- 并发安全的初始化机制
|
||||
|
||||
**关键方法:**
|
||||
- `start()` - 启动 Clash 核心
|
||||
- `stop()` - 停止核心
|
||||
- `getAndroidVpnOptions()` - 获取 VPN 路由配置 (关键!)
|
||||
- `startTun()` - 启动 TUN 设备
|
||||
|
||||
**并发安全设计:**
|
||||
```dart
|
||||
// 使用 Completer 实现初始化锁
|
||||
Completer<void>? _initLock;
|
||||
|
||||
Future<void> _ensureInitialized() async {
|
||||
if (_initialized) return;
|
||||
if (_initLock != null) {
|
||||
await _initLock!.future; // 等待其他初始化完成
|
||||
return;
|
||||
}
|
||||
// 执行初始化...
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Android Service 层 (`ClashService.kt`)
|
||||
|
||||
**职责:**
|
||||
- 管理 VPN 服务生命周期
|
||||
- 创建 Service Isolate (后台 Dart 运行时)
|
||||
- 处理系统 VPN 权限
|
||||
- 注册底层网络回调 (修复模拟器兼容性)
|
||||
|
||||
**Service Isolate 架构:**
|
||||
```kotlin
|
||||
// 创建独立的 FlutterEngine 用于后台服务
|
||||
serviceEngine = FlutterEngine(Application.application)
|
||||
|
||||
// 执行 Dart Service 入口点
|
||||
val entrypoint = DartExecutor.DartEntrypoint(
|
||||
FlutterInjector.instance().flutterLoader().findAppBundlePath(),
|
||||
"_clashService" // 在 lib/main.dart 中定义
|
||||
)
|
||||
serviceEngine?.dartExecutor?.executeDartEntrypoint(entrypoint)
|
||||
```
|
||||
|
||||
### 3. Go 核心层 (`core/`)
|
||||
|
||||
**目录结构:**
|
||||
```
|
||||
core/
|
||||
├── Clash.Meta/ # Git 子模块,Mihomo 核心
|
||||
├── go.mod # Go 依赖管理
|
||||
├── lib_android.go # Android JNI 桥接
|
||||
├── action.go # 核心操作接口
|
||||
└── hub.go # HTTP API 服务器
|
||||
```
|
||||
|
||||
**关键桥接函数:**
|
||||
```go
|
||||
//export quickStart
|
||||
func quickStart(initParams, params, stateParams *C.char, port C.longlong)
|
||||
|
||||
//export getAndroidVpnOptions
|
||||
func getAndroidVpnOptions() *C.char // 返回详细路由配置!
|
||||
|
||||
//export startTUN
|
||||
func startTUN(fd C.int, callback unsafe.Pointer) C.int
|
||||
```
|
||||
|
||||
## 数据流
|
||||
|
||||
### 启动流程
|
||||
|
||||
```
|
||||
1. Flutter UI (用户点击连接)
|
||||
│
|
||||
├──> KRClashImp.start()
|
||||
│ ├─ 生成 Clash 配置 YAML
|
||||
│ ├─ 调用 FFI: quickStart()
|
||||
│ └─ 等待启动回调
|
||||
│
|
||||
├──> libclash.so: quickStart()
|
||||
│ ├─ 初始化 Clash Meta 核心
|
||||
│ ├─ 解析配置文件
|
||||
│ └─ 启动监听器
|
||||
│
|
||||
├──> ClashService.kt
|
||||
│ ├─ 调用 VpnService.prepare()
|
||||
│ ├─ 获取 VPN 权限
|
||||
│ └─ 建立 TUN 接口
|
||||
│
|
||||
├──> KRClashImp.getAndroidVpnOptions() ⭐ 关键!
|
||||
│ └─ 获取 35+ CIDR 路由列表
|
||||
│
|
||||
└──> VPNService.kt: 配置 VPN Builder
|
||||
├─ addAddress("172.19.0.1/30")
|
||||
├─ addRoute("0.0.0.0/1")
|
||||
├─ addRoute("128.0.0.0/1")
|
||||
├─ addRoute("10.0.0.0/8") # bypass-LAN
|
||||
└─ 启动 TUN 设备
|
||||
```
|
||||
|
||||
### 流量统计流程
|
||||
|
||||
```
|
||||
1. UI 定时器 (每秒)
|
||||
│
|
||||
├──> KRClashImp.getTraffic()
|
||||
│ └─ FFI 调用
|
||||
│
|
||||
├──> libclash.so: getTraffic()
|
||||
│ └─ Clash Meta 内部统计
|
||||
│
|
||||
└──> 返回 JSON
|
||||
{
|
||||
"upload": 1234567,
|
||||
"download": 7654321
|
||||
}
|
||||
```
|
||||
|
||||
## 关键设计决策
|
||||
|
||||
### 为什么使用 Clash Meta 替代 sing-box?
|
||||
|
||||
| 问题 | sing-box | Clash Meta |
|
||||
|------|----------|------------|
|
||||
| **Android VPN 路由** | 简单路由 (3-5条) | 详细路由 (35+条 CIDR) |
|
||||
| **bypass-LAN 支持** | ❌ 不支持 | ✅ 完整支持 |
|
||||
| **PermissionMonitor error 22** | ⚠️ 频繁出现 | ✅ 已解决 |
|
||||
| **模拟器兼容性** | ⚠️ 兼容性问题 | ✅ 完美兼容 |
|
||||
|
||||
### 并发安全保证
|
||||
|
||||
**问题:** Go 运行时初始化不是线程安全的,多个 Dart 方法并发调用 `_ensureInitialized()` 可能导致崩溃。
|
||||
|
||||
**解决方案:** 使用 `Completer` 实现初始化锁:
|
||||
```dart
|
||||
// 场景 1: 第一次调用
|
||||
Thread A: _ensureInitialized() → 创建 _initLock → 执行初始化 → complete()
|
||||
|
||||
// 场景 2: 并发调用
|
||||
Thread B: _ensureInitialized() → 发现 _initLock != null → await _initLock.future ✅
|
||||
|
||||
// 场景 3: 初始化失败重试
|
||||
Thread C: _ensureInitialized() → 异常 → _initLock = null → 允许重试 ✅
|
||||
```
|
||||
|
||||
## 配置文件
|
||||
|
||||
### Clash 配置生成 (`clash_config_generator.dart`)
|
||||
|
||||
```yaml
|
||||
# 生成的 clash_config.yaml 示例
|
||||
mixed-port: 51213
|
||||
allow-lan: false
|
||||
|
||||
tun:
|
||||
enable: true
|
||||
stack: system
|
||||
auto-route: true
|
||||
auto-detect-interface: true
|
||||
dns-hijack:
|
||||
- any:53
|
||||
route-address: # ⭐ 关键! 35+ 详细路由
|
||||
- 0.0.0.0/1
|
||||
- 128.0.0.0/1
|
||||
# ... bypass-LAN CIDRs
|
||||
route-exclude-address:
|
||||
- 10.0.0.0/8 # 绕过局域网
|
||||
- 172.16.0.0/12
|
||||
- 192.168.0.0/16
|
||||
|
||||
proxies:
|
||||
- name: "Server-1"
|
||||
type: ss
|
||||
server: example.com
|
||||
port: 8388
|
||||
# ...
|
||||
|
||||
proxy-groups:
|
||||
- name: "PROXY"
|
||||
type: select
|
||||
proxies:
|
||||
- Server-1
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
参考 [CLASH_TROUBLESHOOTING.md](./CLASH_TROUBLESHOOTING.md)
|
||||
|
||||
## 构建指南
|
||||
|
||||
参考 [CLASH_BUILD_GUIDE.md](./CLASH_BUILD_GUIDE.md)
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Clash Meta 官方文档](https://wiki.metacubex.one/)
|
||||
- [Mihomo GitHub](https://github.com/MetaCubeX/mihomo)
|
||||
- [Xboard-Mihomo 参考实现](https://github.com/chen08209/Xboard-Mihomo)
|
||||
345
docs/CLASH_BUILD_GUIDE.md
Normal file
345
docs/CLASH_BUILD_GUIDE.md
Normal file
@ -0,0 +1,345 @@
|
||||
# Clash Meta 核心编译指南
|
||||
|
||||
## 环境准备
|
||||
|
||||
### 1. 安装必要工具
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
brew install go
|
||||
brew install android-ndk # 或从 Android Studio 安装
|
||||
|
||||
# 验证
|
||||
go version # 需要 go 1.20+
|
||||
```
|
||||
|
||||
### 2. 配置环境变量
|
||||
|
||||
```bash
|
||||
# 添加到 ~/.zshrc 或 ~/.bash_profile
|
||||
export ANDROID_HOME="$HOME/Library/Android/sdk"
|
||||
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/29.0.14033849" # 根据实际版本调整
|
||||
export PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin:$PATH"
|
||||
|
||||
# 应用配置
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
## 编译步骤
|
||||
|
||||
### 方法 1: 使用项目脚本 (推荐)
|
||||
|
||||
```bash
|
||||
cd /Users/mac/Project/Dart/LighthouseApp/core
|
||||
|
||||
# 编译 ARM64 版本
|
||||
make android-arm64
|
||||
|
||||
# 编译所有架构
|
||||
make android-all # arm64-v8a, armeabi-v7a, x86, x86_64
|
||||
```
|
||||
|
||||
### 方法 2: 手动编译
|
||||
|
||||
#### 编译 ARM64 (arm64-v8a)
|
||||
|
||||
```bash
|
||||
cd /Users/mac/Project/Dart/LighthouseApp/core
|
||||
|
||||
# 1. 初始化 Go 模块
|
||||
go mod download
|
||||
git submodule update --init --recursive
|
||||
|
||||
# 2. 设置交叉编译环境
|
||||
export CGO_ENABLED=1
|
||||
export GOOS=android
|
||||
export GOARCH=arm64
|
||||
export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android29-clang"
|
||||
|
||||
# 3. 编译为共享库
|
||||
go build -buildmode=c-shared \
|
||||
-ldflags="-s -w" \
|
||||
-trimpath \
|
||||
-o ../android/app/src/main/jniLibs/arm64-v8a/libclash.so \
|
||||
.
|
||||
|
||||
# 4. 验证编译结果
|
||||
ls -lh ../android/app/src/main/jniLibs/arm64-v8a/libclash.so
|
||||
nm -D ../android/app/src/main/jniLibs/arm64-v8a/libclash.so | grep quickStart
|
||||
```
|
||||
|
||||
#### 编译 ARMv7 (armeabi-v7a)
|
||||
|
||||
```bash
|
||||
export GOARCH=arm
|
||||
export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi29-clang"
|
||||
|
||||
go build -buildmode=c-shared \
|
||||
-ldflags="-s -w" \
|
||||
-trimpath \
|
||||
-o ../android/app/src/main/jniLibs/armeabi-v7a/libclash.so \
|
||||
.
|
||||
```
|
||||
|
||||
#### 编译 x86_64
|
||||
|
||||
```bash
|
||||
export GOARCH=amd64
|
||||
export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/x86_64-linux-android29-clang"
|
||||
|
||||
go build -buildmode=c-shared \
|
||||
-ldflags="-s -w" \
|
||||
-trimpath \
|
||||
-o ../android/app/src/main/jniLibs/x86_64/libclash.so \
|
||||
.
|
||||
```
|
||||
|
||||
## 编译优化
|
||||
|
||||
### 减小文件体积
|
||||
|
||||
```bash
|
||||
# 使用 -ldflags 优化
|
||||
go build -buildmode=c-shared \
|
||||
-ldflags="-s -w -X 'github.com/metacubex/mihomo/constant.Version=1.0.0'" \
|
||||
-trimpath \
|
||||
-o libclash.so \
|
||||
.
|
||||
|
||||
# -s: 去除符号表
|
||||
# -w: 去除 DWARF 调试信息
|
||||
# -trimpath: 移除文件系统路径
|
||||
```
|
||||
|
||||
### UPX 压缩 (可选)
|
||||
|
||||
```bash
|
||||
# 安装 UPX
|
||||
brew install upx
|
||||
|
||||
# 压缩 SO 文件 (可减少 30-50% 体积)
|
||||
upx --best --lzma libclash.so
|
||||
|
||||
# ⚠️ 注意: UPX 压缩可能导致某些设备加载失败,仅在测试环境使用
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 问题 1: `undefined reference to 'xxx'`
|
||||
|
||||
**原因:** NDK 版本不匹配或缺少依赖
|
||||
|
||||
**解决:**
|
||||
```bash
|
||||
# 检查 NDK 版本
|
||||
ls $ANDROID_HOME/ndk/
|
||||
|
||||
# 使用推荐版本 (r25c / 25.2.9519653 或更高)
|
||||
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/25.2.9519653"
|
||||
```
|
||||
|
||||
### 问题 2: `clang: command not found`
|
||||
|
||||
**原因:** CC 环境变量路径错误
|
||||
|
||||
**解决:**
|
||||
```bash
|
||||
# macOS (Apple Silicon)
|
||||
export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-aarch64/bin/aarch64-linux-android29-clang"
|
||||
|
||||
# macOS (Intel)
|
||||
export CC="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android29-clang"
|
||||
```
|
||||
|
||||
### 问题 3: 编译后文件过大 (>50MB)
|
||||
|
||||
**原因:** 未启用优化参数
|
||||
|
||||
**解决:**
|
||||
```bash
|
||||
# 确保使用 -ldflags="-s -w"
|
||||
go build -buildmode=c-shared \
|
||||
-ldflags="-s -w" \
|
||||
-trimpath \
|
||||
-o libclash.so \
|
||||
.
|
||||
|
||||
# 预期大小: 25-30MB (ARM64)
|
||||
```
|
||||
|
||||
### 问题 4: `go: github.com/metacubex/mihomo: module not found`
|
||||
|
||||
**原因:** 子模块未初始化
|
||||
|
||||
**解决:**
|
||||
```bash
|
||||
cd core
|
||||
git submodule update --init --recursive
|
||||
go mod download
|
||||
```
|
||||
|
||||
## 验证编译结果
|
||||
|
||||
### 1. 检查导出函数
|
||||
|
||||
```bash
|
||||
nm -D libclash.so | grep -E "(quickStart|getAndroidVpnOptions|startTUN)"
|
||||
|
||||
# 预期输出:
|
||||
# 0000000000e23960 T getAndroidVpnOptions
|
||||
# 0000000000e237b0 T quickStart
|
||||
# 0000000000e23820 T startTUN
|
||||
```
|
||||
|
||||
### 2. 检查架构
|
||||
|
||||
```bash
|
||||
file libclash.so
|
||||
|
||||
# ARM64 预期输出:
|
||||
# libclash.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked
|
||||
```
|
||||
|
||||
### 3. 测试加载
|
||||
|
||||
```bash
|
||||
# 在 Android 设备上测试
|
||||
adb push libclash.so /data/local/tmp/
|
||||
adb shell "cd /data/local/tmp && LD_LIBRARY_PATH=. /system/bin/true" # 测试加载
|
||||
```
|
||||
|
||||
## 持续集成 (CI/CD)
|
||||
|
||||
### GitHub Actions 示例
|
||||
|
||||
```yaml
|
||||
# .github/workflows/build-clash-core.yml
|
||||
name: Build Clash Core
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'core/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [arm64, arm, amd64]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Setup Android NDK
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: r25c
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd core
|
||||
make android-${{ matrix.arch }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: libclash-${{ matrix.arch }}
|
||||
path: android/app/src/main/jniLibs/**/libclash.so
|
||||
```
|
||||
|
||||
## 更新核心版本
|
||||
|
||||
### 更新 Clash.Meta 子模块
|
||||
|
||||
```bash
|
||||
cd core/Clash.Meta
|
||||
|
||||
# 更新到最新版本
|
||||
git fetch origin
|
||||
git checkout Alpha # 或其他分支
|
||||
git pull
|
||||
|
||||
cd ..
|
||||
git add Clash.Meta
|
||||
git commit -m "chore: update Clash.Meta to latest"
|
||||
|
||||
# 重新编译
|
||||
make clean
|
||||
make android-arm64
|
||||
```
|
||||
|
||||
### 查看版本信息
|
||||
|
||||
```bash
|
||||
# 查看当前 Clash.Meta 版本
|
||||
cd core/Clash.Meta
|
||||
git log -1 --oneline
|
||||
|
||||
# 查看依赖版本
|
||||
cd ..
|
||||
go list -m github.com/metacubex/mihomo
|
||||
```
|
||||
|
||||
## 调试编译问题
|
||||
|
||||
### 启用详细日志
|
||||
|
||||
```bash
|
||||
# 查看详细编译过程
|
||||
go build -v -x -buildmode=c-shared -o libclash.so .
|
||||
|
||||
# -v: 显示正在编译的包
|
||||
# -x: 显示执行的命令
|
||||
```
|
||||
|
||||
### 检查依赖
|
||||
|
||||
```bash
|
||||
# 列出所有依赖
|
||||
go list -m all
|
||||
|
||||
# 检查特定依赖
|
||||
go mod why github.com/metacubex/mihomo
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 编译时优化
|
||||
|
||||
```bash
|
||||
# 启用所有优化
|
||||
go build -buildmode=c-shared \
|
||||
-ldflags="-s -w -extldflags=-Wl,-z,now" \
|
||||
-trimpath \
|
||||
-tags="with_gvisor,with_quic" \
|
||||
-o libclash.so \
|
||||
.
|
||||
```
|
||||
|
||||
### Profile 引导优化 (PGO)
|
||||
|
||||
```bash
|
||||
# 1. 生成性能剖析文件
|
||||
go test -cpuprofile=cpu.prof ./...
|
||||
|
||||
# 2. 使用剖析文件编译
|
||||
go build -buildmode=c-shared \
|
||||
-pgo=cpu.prof \
|
||||
-o libclash.so \
|
||||
.
|
||||
```
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Android NDK 官方文档](https://developer.android.com/ndk)
|
||||
- [Go 交叉编译指南](https://go.dev/doc/install/source#environment)
|
||||
- [Clash Meta 编译指南](https://wiki.metacubex.one/dev/)
|
||||
441
docs/CLASH_TROUBLESHOOTING.md
Normal file
441
docs/CLASH_TROUBLESHOOTING.md
Normal file
@ -0,0 +1,441 @@
|
||||
# Clash Meta 故障排查指南
|
||||
|
||||
## 常见运行时问题
|
||||
|
||||
### 问题 1: VPN 连接失败,日志显示 "PermissionMonitor error 22 (EINVAL)"
|
||||
|
||||
**症状:**
|
||||
```
|
||||
E/VPNService: PermissionMonitor error 22 (EINVAL)
|
||||
E/Clash: TUN 设备启动失败
|
||||
```
|
||||
|
||||
**原因:**
|
||||
- VPN Builder 配置的路由规则无效
|
||||
- 缺少 bypass-LAN 路由配置
|
||||
- 路由 CIDR 格式错误
|
||||
|
||||
**解决方案:**
|
||||
|
||||
1. 检查 `getAndroidVpnOptions()` 返回的路由列表:
|
||||
```dart
|
||||
final options = await KRClashImp().getAndroidVpnOptions();
|
||||
print('路由数量: ${options?['routeAddress']?.length}');
|
||||
print('路由列表: ${options?['routeAddress']}');
|
||||
```
|
||||
|
||||
2. 确认配置包含完整的 bypass-LAN 路由:
|
||||
```yaml
|
||||
# clash_config.yaml
|
||||
tun:
|
||||
route-exclude-address:
|
||||
- 10.0.0.0/8
|
||||
- 100.64.0.0/10
|
||||
- 127.0.0.0/8
|
||||
- 169.254.0.0/16
|
||||
- 172.16.0.0/12
|
||||
- 192.0.0.0/24
|
||||
- 192.0.2.0/24
|
||||
- 192.88.99.0/24
|
||||
- 192.168.0.0/16
|
||||
- 198.18.0.0/15
|
||||
- 198.51.100.0/24
|
||||
- 203.0.113.0/24
|
||||
- 224.0.0.0/3
|
||||
- fc00::/7
|
||||
- fe80::/10
|
||||
- ff00::/8
|
||||
```
|
||||
|
||||
3. 验证 VPN Builder 配置:
|
||||
```kotlin
|
||||
// VPNService.kt
|
||||
builder
|
||||
.addAddress("172.19.0.1/30")
|
||||
.addRoute("0.0.0.0/1") // ✅ 拆分默认路由
|
||||
.addRoute("128.0.0.0/1") // ✅ 避免 0.0.0.0/0
|
||||
.addRoute("10.0.0.0/8") // ✅ bypass-LAN
|
||||
// ...
|
||||
```
|
||||
|
||||
**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:192`
|
||||
|
||||
---
|
||||
|
||||
### 问题 2: FFI 初始化崩溃 "Go runtime already initialized"
|
||||
|
||||
**症状:**
|
||||
```
|
||||
F/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR)
|
||||
E/Clash: Go runtime already initialized
|
||||
```
|
||||
|
||||
**原因:**
|
||||
- 多线程并发调用 `_ensureInitialized()`
|
||||
- Go 运行时被重复初始化
|
||||
|
||||
**解决方案:**
|
||||
|
||||
已在 `kr_clash_imp.dart` 中修复,使用 `Completer` 实现并发安全:
|
||||
```dart
|
||||
Future<void> _ensureInitialized() async {
|
||||
if (_initialized) return;
|
||||
if (_initLock != null) {
|
||||
await _initLock!.future; // ✅ 等待其他初始化完成
|
||||
return;
|
||||
}
|
||||
_initLock = Completer<void>();
|
||||
// ... 执行初始化
|
||||
}
|
||||
```
|
||||
|
||||
**验证修复:**
|
||||
```dart
|
||||
// 并发测试
|
||||
await Future.wait([
|
||||
KRClashImp().start(...),
|
||||
KRClashImp().getAndroidVpnOptions(),
|
||||
KRClashImp().getTraffic(),
|
||||
]);
|
||||
// ✅ 应该不会崩溃
|
||||
```
|
||||
|
||||
**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:43`
|
||||
|
||||
---
|
||||
|
||||
### 问题 3: 模拟器无法联网 "Network unreachable"
|
||||
|
||||
**症状:**
|
||||
```
|
||||
E/Clash: 网络不可达
|
||||
W/VPNService: 底层网络丢失
|
||||
```
|
||||
|
||||
**原因:**
|
||||
- 模拟器需要显式设置底层网络
|
||||
- 缺少 `setUnderlyingNetworks()` 调用
|
||||
|
||||
**解决方案:**
|
||||
|
||||
已在 `VPNService.kt` 中实现:
|
||||
```kotlin
|
||||
// Android P+ 需要设置底层网络
|
||||
private val defaultNetworkCallback by lazy {
|
||||
object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
setUnderlyingNetworks(arrayOf(network)) // ✅ 关键!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册回调
|
||||
connectivityManager.registerDefaultNetworkCallback(defaultNetworkCallback)
|
||||
```
|
||||
|
||||
**验证修复:**
|
||||
```bash
|
||||
# 在 MuMu 模拟器测试
|
||||
adb logcat | grep "底层网络"
|
||||
# 应该看到: "底层网络可用: NetworkIdentity{...}"
|
||||
```
|
||||
|
||||
**参考:** `android/.../bg/VPNService.kt:32-66`
|
||||
|
||||
---
|
||||
|
||||
### 问题 4: 配置文件解析失败 "invalid YAML"
|
||||
|
||||
**症状:**
|
||||
```
|
||||
E/Clash: 启动失败: yaml: unmarshal errors:
|
||||
line 10: cannot unmarshal !!str `8388` into int
|
||||
```
|
||||
|
||||
**原因:**
|
||||
- YAML 类型不匹配 (字符串 vs 整数)
|
||||
- 配置格式错误
|
||||
|
||||
**解决方案:**
|
||||
|
||||
检查 `ClashConfigGenerator.generate()`:
|
||||
```dart
|
||||
proxies:
|
||||
- name: "Server-1"
|
||||
type: ss
|
||||
server: "example.com"
|
||||
port: 8388 # ✅ 整数,不要引号
|
||||
password: "password" # ✅ 字符串,使用引号
|
||||
cipher: "aes-256-gcm"
|
||||
```
|
||||
|
||||
**调试方法:**
|
||||
```dart
|
||||
// 打印生成的配置
|
||||
final config = ClashConfigGenerator.generate(...);
|
||||
print('配置预览:\n$config');
|
||||
|
||||
// 保存到文件手动检查
|
||||
File('/tmp/clash_debug.yaml').writeAsStringSync(config);
|
||||
```
|
||||
|
||||
**参考:** `lib/app/services/clash_imp/clash_config_generator.dart`
|
||||
|
||||
---
|
||||
|
||||
### 问题 5: "quickStart timeout" 启动超时
|
||||
|
||||
**症状:**
|
||||
```
|
||||
W/Clash: 启动超时 (10秒)
|
||||
E/Clash: quickStart 未收到回调
|
||||
```
|
||||
|
||||
**原因:**
|
||||
- Go 核心启动耗时过长
|
||||
- ReceivePort 未正确监听
|
||||
- 回调被阻塞
|
||||
|
||||
**解决方案:**
|
||||
|
||||
1. 增加超时时间:
|
||||
```dart
|
||||
_isRunning = await completer.future.timeout(
|
||||
const Duration(seconds: 20), // ✅ 增加到 20 秒
|
||||
onTimeout: () {
|
||||
print('⚠️ 启动超时');
|
||||
return false;
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
2. 检查 Go 核心日志:
|
||||
```kotlin
|
||||
// ClashService.kt - 添加日志回调
|
||||
tempMethodChannel.setMethodCallHandler { call, result ->
|
||||
if (call.method == "log") {
|
||||
Log.d(TAG, "Go 核心日志: ${call.arguments}")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. 使用 Service Isolate 避免阻塞:
|
||||
```kotlin
|
||||
// ClashService.kt:102 - 已实现
|
||||
serviceEngine?.dartExecutor?.executeDartEntrypoint(entrypoint)
|
||||
```
|
||||
|
||||
**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:145`
|
||||
|
||||
---
|
||||
|
||||
### 问题 6: 流量统计不更新
|
||||
|
||||
**症状:**
|
||||
```
|
||||
I/Clash: 流量统计: {"upload": 0, "download": 0} # 始终为 0
|
||||
```
|
||||
|
||||
**原因:**
|
||||
- TUN 设备未正确启动
|
||||
- 流量未通过代理
|
||||
|
||||
**解决方案:**
|
||||
|
||||
1. 确认 TUN 启动成功:
|
||||
```dart
|
||||
final tunStarted = await KRClashImp().startTun(fd, protectCallback);
|
||||
print('TUN 启动状态: $tunStarted'); // 应该为 true
|
||||
```
|
||||
|
||||
2. 检查路由配置:
|
||||
```bash
|
||||
# 在设备上检查路由表
|
||||
adb shell "ip route show table all | grep tun"
|
||||
```
|
||||
|
||||
3. 测试代理连接:
|
||||
```bash
|
||||
# 使用 curl 测试
|
||||
adb shell "curl -v http://www.google.com"
|
||||
# 应该看到代理日志
|
||||
```
|
||||
|
||||
**参考:** `lib/app/services/clash_imp/kr_clash_imp.dart:261`
|
||||
|
||||
---
|
||||
|
||||
## 日志分析
|
||||
|
||||
### 启用详细日志
|
||||
|
||||
```dart
|
||||
// lib/app/services/clash_imp/kr_clash_imp.dart
|
||||
// 添加更详细的日志
|
||||
print('📨 [Clash] 收到消息: ${jsonEncode(message)}');
|
||||
print('📋 [Clash] 配置完整内容:\n$config');
|
||||
```
|
||||
|
||||
### Android Logcat 过滤
|
||||
|
||||
```bash
|
||||
# 只看 Clash 相关日志
|
||||
adb logcat -s "A/Clash" "E/Clash" "W/Clash"
|
||||
|
||||
# 实时监控 FFI 调用
|
||||
adb logcat | grep -E "(ClashFFI|quickStart|getAndroidVpnOptions)"
|
||||
|
||||
# 保存日志到文件
|
||||
adb logcat -d > clash_debug.log
|
||||
```
|
||||
|
||||
### Dart Observatory 调试
|
||||
|
||||
```bash
|
||||
# 启用 Dart Observatory
|
||||
flutter run --observatory-port=8181
|
||||
|
||||
# 在浏览器打开
|
||||
open http://localhost:8181
|
||||
|
||||
# 查看 Isolate 状态
|
||||
# - Main Isolate (UI)
|
||||
# - Service Isolate (Clash 后台)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能问题
|
||||
|
||||
### 内存泄漏
|
||||
|
||||
**症状:**
|
||||
- 应用内存持续增长
|
||||
- 最终 OOM 崩溃
|
||||
|
||||
**排查:**
|
||||
```dart
|
||||
// 确保调用 dispose()
|
||||
@override
|
||||
void dispose() {
|
||||
KRClashImp().dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// 检查 ReceivePort 是否关闭
|
||||
receivePort.listen((message) {
|
||||
// ...
|
||||
receivePort.close(); // ✅ 必须关闭!
|
||||
});
|
||||
```
|
||||
|
||||
### CPU 占用过高
|
||||
|
||||
**症状:**
|
||||
- 设备发热
|
||||
- 电池消耗快
|
||||
|
||||
**排查:**
|
||||
```bash
|
||||
# 查看 CPU 占用
|
||||
adb shell "top -m 10"
|
||||
|
||||
# 使用 Profiler
|
||||
flutter run --profile
|
||||
# DevTools → CPU Profiler
|
||||
```
|
||||
|
||||
**优化:**
|
||||
```dart
|
||||
// 降低流量统计频率
|
||||
Timer.periodic(const Duration(seconds: 2), (timer) { // ✅ 2秒而非1秒
|
||||
final traffic = await KRClashImp().getTraffic();
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 崩溃分析
|
||||
|
||||
### 获取崩溃堆栈
|
||||
|
||||
```bash
|
||||
# Native 崩溃
|
||||
adb logcat -d | grep "backtrace"
|
||||
|
||||
# 使用 ndk-stack 解析
|
||||
adb logcat | ndk-stack -sym android/app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a
|
||||
```
|
||||
|
||||
### 常见崩溃模式
|
||||
|
||||
#### SIGSEGV (段错误)
|
||||
|
||||
**原因:** FFI 指针使用错误
|
||||
|
||||
**示例:**
|
||||
```dart
|
||||
// ❌ 错误: 释放后使用
|
||||
final ptr = 'hello'.toNativeUtf8();
|
||||
malloc.free(ptr);
|
||||
_ffi!.someFunction(ptr); // 崩溃!
|
||||
|
||||
// ✅ 正确: 使用后释放
|
||||
final ptr = 'hello'.toNativeUtf8();
|
||||
_ffi!.someFunction(ptr);
|
||||
malloc.free(ptr);
|
||||
```
|
||||
|
||||
#### SIGABRT (异常终止)
|
||||
|
||||
**原因:** Go panic 未恢复
|
||||
|
||||
**解决:** 在 Go 侧添加 recover:
|
||||
```go
|
||||
//export quickStart
|
||||
func quickStart(...) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println("Panic recovered:", r)
|
||||
}
|
||||
}()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取帮助
|
||||
|
||||
### 收集诊断信息
|
||||
|
||||
创建 Bug 报告时请包含:
|
||||
|
||||
1. **系统信息:**
|
||||
```bash
|
||||
adb shell "getprop ro.build.version.release" # Android 版本
|
||||
adb shell "getprop ro.product.cpu.abi" # CPU 架构
|
||||
```
|
||||
|
||||
2. **应用日志:**
|
||||
```bash
|
||||
adb logcat -d > full_log.txt
|
||||
```
|
||||
|
||||
3. **配置文件:**
|
||||
```dart
|
||||
// 脱敏后的 clash_config.yaml
|
||||
print(config.replaceAll(RegExp(r'password:.*'), 'password: ***'));
|
||||
```
|
||||
|
||||
4. **复现步骤:**
|
||||
- 详细操作流程
|
||||
- 预期结果 vs 实际结果
|
||||
- 复现概率
|
||||
|
||||
### 相关资源
|
||||
|
||||
- [GitHub Issues](https://github.com/your-repo/issues)
|
||||
- [Clash Meta Wiki](https://wiki.metacubex.one/)
|
||||
- [Flutter FFI 文档](https://dart.dev/guides/libraries/c-interop)
|
||||
269
docs/README.md
Normal file
269
docs/README.md
Normal file
@ -0,0 +1,269 @@
|
||||
# LighthouseApp 技术文档
|
||||
|
||||
欢迎查阅 LighthouseApp 技术文档。本目录包含项目的架构设计、开发指南和故障排查信息。
|
||||
|
||||
## 📚 文档导航
|
||||
|
||||
### Clash Meta 核心 (推荐阅读)
|
||||
|
||||
| 文档 | 说明 | 适用人群 |
|
||||
|------|------|----------|
|
||||
| [**架构文档**](./CLASH_ARCHITECTURE.md) | 完整架构设计、数据流、关键决策 | 所有开发者 |
|
||||
| [**编译指南**](./CLASH_BUILD_GUIDE.md) | 本地编译步骤、环境配置、优化方法 | 核心开发者 |
|
||||
| [**故障排查**](./CLASH_TROUBLESHOOTING.md) | 常见问题、日志分析、崩溃调试 | 测试/运维 |
|
||||
|
||||
### CI/CD 工作流
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [**GitHub Actions 说明**](../.github/workflows/README.md) | 自动化构建、发布流程 |
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 新开发者入门
|
||||
|
||||
1. **了解架构** (必读)
|
||||
- 阅读 [CLASH_ARCHITECTURE.md](./CLASH_ARCHITECTURE.md)
|
||||
- 理解 Dart → Android → Go 三层架构
|
||||
- 掌握 FFI 通信机制
|
||||
|
||||
2. **配置开发环境**
|
||||
- 按照 [CLASH_BUILD_GUIDE.md](./CLASH_BUILD_GUIDE.md) 配置环境
|
||||
- 编译第一个 Clash Core
|
||||
- 验证编译结果
|
||||
|
||||
3. **运行项目**
|
||||
```bash
|
||||
# 1. 获取代码
|
||||
git clone <repo-url>
|
||||
cd LighthouseApp
|
||||
|
||||
# 2. 初始化子模块
|
||||
git submodule update --init --recursive
|
||||
|
||||
# 3. 编译核心
|
||||
cd core
|
||||
make android-arm64
|
||||
|
||||
# 4. 运行 Flutter
|
||||
cd ..
|
||||
flutter pub get
|
||||
flutter run
|
||||
```
|
||||
|
||||
### 核心开发者
|
||||
|
||||
如果您需要修改 Clash Meta 核心:
|
||||
|
||||
1. **修改代码**
|
||||
```bash
|
||||
cd core
|
||||
vim lib_android.go # 或其他核心文件
|
||||
```
|
||||
|
||||
2. **本地测试**
|
||||
```bash
|
||||
make android-arm64
|
||||
flutter run
|
||||
```
|
||||
|
||||
3. **提交 PR**
|
||||
- CI/CD 会自动构建所有架构
|
||||
- 检查 Actions 页面的构建结果
|
||||
- 等待代码审查
|
||||
|
||||
## 🏗️ 架构速览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ LighthouseApp │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Flutter/Dart Layer │
|
||||
│ └─ lib/app/services/clash_imp/ │
|
||||
│ ├─ kr_clash_imp.dart (核心封装) │
|
||||
│ ├─ clash_ffi.dart (FFI 绑定) │
|
||||
│ └─ clash_config_generator (配置生成) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Android Native Layer │
|
||||
│ └─ android/app/src/main/kotlin/com/hiddify/hiddify/ │
|
||||
│ ├─ bg/VPNService.kt (VPN 服务) │
|
||||
│ └─ bg/ClashService.kt (Clash 服务) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Go Core Layer │
|
||||
│ └─ core/ │
|
||||
│ ├─ Clash.Meta/ (Git 子模块) │
|
||||
│ ├─ lib_android.go (JNI 桥接) │
|
||||
│ └─ libclash.so (编译产物) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
详细架构请参考 [CLASH_ARCHITECTURE.md](./CLASH_ARCHITECTURE.md)
|
||||
|
||||
## 🔧 常见任务
|
||||
|
||||
### 编译核心
|
||||
|
||||
```bash
|
||||
cd core
|
||||
|
||||
# 单个架构 (快速)
|
||||
make android-arm64
|
||||
|
||||
# 所有架构 (发布)
|
||||
make android-all
|
||||
|
||||
# 清理
|
||||
make clean
|
||||
|
||||
# 验证
|
||||
make verify
|
||||
```
|
||||
|
||||
### 更新 Clash.Meta
|
||||
|
||||
```bash
|
||||
cd core
|
||||
make update # 更新子模块到最新版本
|
||||
make android-arm64 # 重新编译
|
||||
```
|
||||
|
||||
### 调试问题
|
||||
|
||||
```bash
|
||||
# 查看 Android 日志
|
||||
adb logcat -s "A/Clash" "E/Clash"
|
||||
|
||||
# 查看编译详情
|
||||
cd core
|
||||
go build -v -x -buildmode=c-shared -o test.so .
|
||||
|
||||
# 验证 SO 文件
|
||||
nm -D libclash.so | grep quickStart
|
||||
```
|
||||
|
||||
## 📖 核心概念
|
||||
|
||||
### 1. FFI 并发安全
|
||||
|
||||
**问题:** Go 运行时初始化不是线程安全的
|
||||
|
||||
**解决:** 使用 `Completer` 实现初始化锁
|
||||
|
||||
```dart
|
||||
Future<void> _ensureInitialized() async {
|
||||
if (_initialized) return;
|
||||
if (_initLock != null) {
|
||||
await _initLock!.future; // ✅ 等待其他初始化
|
||||
return;
|
||||
}
|
||||
// ... 执行初始化
|
||||
}
|
||||
```
|
||||
|
||||
详见 [CLASH_ARCHITECTURE.md § 并发安全保证](./CLASH_ARCHITECTURE.md#并发安全保证)
|
||||
|
||||
### 2. Service Isolate 架构
|
||||
|
||||
**为什么需要?**
|
||||
- VPN 服务运行在后台
|
||||
- 主 Isolate 可能被销毁
|
||||
- 需要独立的 Dart 运行时
|
||||
|
||||
**实现:**
|
||||
```kotlin
|
||||
// ClashService.kt
|
||||
serviceEngine = FlutterEngine(Application.application)
|
||||
val entrypoint = DartExecutor.DartEntrypoint(..., "_clashService")
|
||||
serviceEngine?.dartExecutor?.executeDartEntrypoint(entrypoint)
|
||||
```
|
||||
|
||||
详见 [CLASH_ARCHITECTURE.md § Service Isolate 架构](./CLASH_ARCHITECTURE.md#2-android-service-层-clashservicekt)
|
||||
|
||||
### 3. Android VPN 路由配置
|
||||
|
||||
**关键:** `getAndroidVpnOptions()` 返回 35+ 详细 CIDR 路由
|
||||
|
||||
**为什么重要?**
|
||||
- 避免 PermissionMonitor error 22
|
||||
- 支持 bypass-LAN
|
||||
- 兼容模拟器
|
||||
|
||||
详见 [CLASH_TROUBLESHOOTING.md § 问题 1](./CLASH_TROUBLESHOOTING.md#问题-1-vpn-连接失败日志显示-permissionmonitor-error-22-einval)
|
||||
|
||||
## 🐛 遇到问题?
|
||||
|
||||
1. **查看故障排查文档**
|
||||
- [CLASH_TROUBLESHOOTING.md](./CLASH_TROUBLESHOOTING.md) 包含所有常见问题
|
||||
|
||||
2. **收集诊断信息**
|
||||
```bash
|
||||
# 系统信息
|
||||
adb shell "getprop ro.build.version.release"
|
||||
|
||||
# 应用日志
|
||||
adb logcat -d > full_log.txt
|
||||
|
||||
# 核心信息
|
||||
cd core
|
||||
make verify
|
||||
```
|
||||
|
||||
3. **提交 Issue**
|
||||
- 使用诊断信息模板
|
||||
- 包含复现步骤
|
||||
- 附上日志文件
|
||||
|
||||
## 🤝 贡献指南
|
||||
|
||||
### 代码规范
|
||||
|
||||
项目遵循以下原则:
|
||||
- **KISS** (Keep It Simple, Stupid) - 简单至上
|
||||
- **DRY** (Don't Repeat Yourself) - 杜绝重复
|
||||
- **SOLID** - 面向对象设计原则
|
||||
- **YAGNI** (You Aren't Gonna Need It) - 精益求精
|
||||
|
||||
### 提交流程
|
||||
|
||||
1. Fork 项目
|
||||
2. 创建特性分支 (`git checkout -b feature/amazing`)
|
||||
3. 提交更改 (`git commit -m 'feat: add amazing feature'`)
|
||||
4. 推送分支 (`git push origin feature/amazing`)
|
||||
5. 创建 Pull Request
|
||||
|
||||
### Commit 规范
|
||||
|
||||
使用 Conventional Commits:
|
||||
- `feat:` 新功能
|
||||
- `fix:` 修复 Bug
|
||||
- `docs:` 文档更新
|
||||
- `refactor:` 代码重构
|
||||
- `perf:` 性能优化
|
||||
- `test:` 测试相关
|
||||
- `chore:` 构建/工具链
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
- **GitHub Issues:** [提交问题](https://github.com/your-repo/issues)
|
||||
- **文档索引:** 您正在阅读!
|
||||
- **外部资源:**
|
||||
- [Clash Meta Wiki](https://wiki.metacubex.one/)
|
||||
- [Flutter FFI 文档](https://dart.dev/guides/libraries/c-interop)
|
||||
- [Android VPN 指南](https://developer.android.com/reference/android/net/VpnService)
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
| 日期 | 版本 | 更新内容 |
|
||||
|------|------|----------|
|
||||
| 2025-10-25 | 1.0.0 | 完成 Xboard-Mihomo 核心集成 |
|
||||
| 2025-10-25 | 1.0.0 | 修复 FFI 并发安全问题 |
|
||||
| 2025-10-25 | 1.0.0 | 添加完整技术文档 |
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目采用 [LICENSE](../LICENSE) 许可证。
|
||||
|
||||
---
|
||||
|
||||
**最后更新:** 2025-10-25
|
||||
**维护者:** LighthouseApp 开发团队
|
||||
318
docs/go修复.md
Normal file
318
docs/go修复.md
Normal file
@ -0,0 +1,318 @@
|
||||
# Android SELinux chown 权限问题修复方案
|
||||
|
||||
## 问题背景
|
||||
|
||||
在 Android 12+ 系统上,由于 SELinux 严格模式的权限限制,sing-box 核心库在启动时会因为 `chown` 操作被拒绝而失败。具体表现为以下三个错误:
|
||||
|
||||
1. **CommandServer 错误**: `chown: chown command.sock: operation not permitted`
|
||||
2. **Logger 错误**: `start logger: chown box.log: operation not permitted`
|
||||
3. **Clash Cache 错误**: `pre-start cache file: platform chown: chown clash.db: operation not permitted`
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 根本原因
|
||||
|
||||
sing-box (libbox) 在创建文件后会尝试修改文件所有权(`chown`操作),但在 Android 的 SELinux 环境下,应用无法修改外部存储目录中文件的所有权,导致启动失败。
|
||||
|
||||
### 涉及的文件
|
||||
|
||||
1. `command.sock` - CommandServer 的 Unix socket 文件
|
||||
2. `box.log` - sing-box 的日志文件
|
||||
3. `clash.db` - Clash API 的缓存数据库文件
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 方案概述
|
||||
|
||||
**核心思路**: 在配置层面禁用会触发 chown 操作的功能,或者修改底层代码跳过 chown 操作。
|
||||
|
||||
由于修改 sing-box 底层库较为复杂,建议采用配置修改方案。
|
||||
|
||||
---
|
||||
|
||||
## 具体修复步骤
|
||||
|
||||
### 修复 1: 禁用文件日志
|
||||
|
||||
**文件**: `libcore/config/hiddify_option.go`
|
||||
|
||||
**位置**: `DefaultHiddifyOptions()` 函数
|
||||
|
||||
**修改前**:
|
||||
```go
|
||||
LogLevel: "warn",
|
||||
// LogFile: "/dev/null",
|
||||
LogFile: "box.log",
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```go
|
||||
LogLevel: "warn",
|
||||
LogFile: "", // 禁用文件日志,避免 Android SELinux chown 权限问题
|
||||
// LogFile: "box.log",
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 将 `LogFile` 设置为空字符串,禁用文件日志输出
|
||||
- 日志将只输出到 stderr,可以通过 logcat 查看
|
||||
- 这不会影响日志功能,只是改变了输出目标
|
||||
|
||||
---
|
||||
|
||||
### 修复 2: 禁用 Clash API 缓存
|
||||
|
||||
**文件**: `libcore/config/config.go`
|
||||
|
||||
**位置**: `setClashAPI()` 函数
|
||||
|
||||
**修改前**:
|
||||
```go
|
||||
func setClashAPI(options *option.Options, opt *HiddifyOptions) {
|
||||
if opt.EnableClashApi {
|
||||
if opt.ClashApiSecret == "" {
|
||||
opt.ClashApiSecret = generateRandomString(16)
|
||||
}
|
||||
options.Experimental = &option.ExperimentalOptions{
|
||||
ClashAPI: &option.ClashAPIOptions{
|
||||
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", opt.ClashApiPort),
|
||||
Secret: opt.ClashApiSecret,
|
||||
},
|
||||
|
||||
CacheFile: &option.CacheFileOptions{
|
||||
Enabled: true,
|
||||
Path: "clash.db",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```go
|
||||
func setClashAPI(options *option.Options, opt *HiddifyOptions) {
|
||||
if opt.EnableClashApi {
|
||||
if opt.ClashApiSecret == "" {
|
||||
opt.ClashApiSecret = generateRandomString(16)
|
||||
}
|
||||
options.Experimental = &option.ExperimentalOptions{
|
||||
ClashAPI: &option.ClashAPIOptions{
|
||||
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", opt.ClashApiPort),
|
||||
Secret: opt.ClashApiSecret,
|
||||
},
|
||||
|
||||
CacheFile: &option.CacheFileOptions{
|
||||
Enabled: false, // 禁用缓存以避免 Android SELinux chown 权限问题
|
||||
Path: "", // 清空路径
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 将 `Enabled` 设置为 `false`,禁用 Clash API 缓存功能
|
||||
- 将 `Path` 设置为空字符串
|
||||
- Clash API 功能仍然可用,只是不会持久化节点选择等信息
|
||||
|
||||
---
|
||||
|
||||
### 修复 3: CommandServer 错误处理 (可选)
|
||||
|
||||
**说明**: CommandServer 主要用于命令行控制,对 Android VPN 功能不是必需的。
|
||||
|
||||
#### 方案 A: 在应用层捕获异常 (推荐)
|
||||
|
||||
**文件**: `android/app/src/main/kotlin/com/hiddify/hiddify/bg/BoxService.kt`
|
||||
|
||||
**位置**: `onStartCommand()` 函数
|
||||
|
||||
**修改**:
|
||||
```kotlin
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
Settings.startedByUser = true
|
||||
initialize()
|
||||
try {
|
||||
startCommandServer()
|
||||
} catch (e: Exception) {
|
||||
// CommandServer 启动失败不是致命错误
|
||||
// 在 Android 12+ SELinux 环境下,chown 操作可能被拒绝
|
||||
// 但这不影响 VPN 核心功能,因此记录警告但继续启动服务
|
||||
Log.w(TAG, "CommandServer failed to start (non-fatal): ${e.message}")
|
||||
}
|
||||
startService()
|
||||
}
|
||||
```
|
||||
|
||||
#### 方案 B: 完全禁用 CommandServer
|
||||
|
||||
如果不需要 CommandServer 功能,可以直接注释掉启动代码:
|
||||
```kotlin
|
||||
// startCommandServer() // 在 Android 上禁用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 验证修复
|
||||
|
||||
### 编译步骤
|
||||
|
||||
1. **使用 Docker 编译** (推荐):
|
||||
```bash
|
||||
cd libcore
|
||||
docker run --rm -v "$PWD:/workspace" -w /workspace golang:1.23 bash -c "bash docker-compile.sh"
|
||||
```
|
||||
|
||||
2. **或者本地编译**:
|
||||
```bash
|
||||
cd libcore
|
||||
make android
|
||||
```
|
||||
|
||||
### 部署编译好的库
|
||||
|
||||
编译完成后,有两种部署方式:
|
||||
|
||||
#### 方式A: 替换完整AAR (推荐生产环境)
|
||||
|
||||
```bash
|
||||
cd libcore
|
||||
# 替换AAR文件
|
||||
cp libcore.aar ../android/app/libs/
|
||||
|
||||
# 删除可能冲突的so文件
|
||||
rm -rf ../android/app/src/main/jniLibs/
|
||||
|
||||
# 重新编译Flutter项目
|
||||
cd ..
|
||||
flutter clean && flutter build apk
|
||||
```
|
||||
|
||||
**优点**: 支持所有架构,适合发布版本
|
||||
|
||||
#### 方式B: 只提取arm64 so文件 (推荐测试环境)
|
||||
|
||||
```bash
|
||||
cd libcore
|
||||
# 从AAR提取arm64的libbox.so
|
||||
unzip -j libcore.aar jni/arm64-v8a/libbox.so -d /tmp/
|
||||
mkdir -p ../android/app/src/main/jniLibs/arm64-v8a/
|
||||
cp /tmp/libbox.so ../android/app/src/main/jniLibs/arm64-v8a/
|
||||
|
||||
# 临时禁用AAR(避免冲突)
|
||||
mv ../android/app/libs/libcore.aar ../android/app/libs/libcore.aar.old
|
||||
|
||||
# 编译测试版本
|
||||
cd ..
|
||||
flutter clean && flutter build apk --debug --split-per-abi
|
||||
```
|
||||
|
||||
**优点**: 编译快速,APK体积小,适合开发调试
|
||||
|
||||
⚠️ **重要**: 两种方式不能同时使用,会产生冲突!请根据需求选择其一。
|
||||
|
||||
### 测试验证
|
||||
|
||||
1. 重新编译 Flutter 应用
|
||||
2. 在 Android 设备上安装并启动
|
||||
3. 查看 logcat 日志,确认没有 chown 相关错误
|
||||
4. 验证 VPN 能正常启动和代理流量
|
||||
|
||||
---
|
||||
|
||||
## 预期结果
|
||||
|
||||
修复后,应用启动日志应该显示:
|
||||
|
||||
```
|
||||
D/A/BoxService: base dir: /data/user/0/app.xxx.com/files
|
||||
D/A/BoxService: working dir: /storage/emulated/0/Android/data/app.xxx.com/files
|
||||
D/A/BoxService: temp dir: /data/user/0/app.xxx.com/cache
|
||||
W/A/BoxService: CommandServer failed to start (non-fatal): chown: chown command.sock: operation not permitted
|
||||
D/A/BoxService: starting service
|
||||
D/A/BoxService: 配置已修改: 禁用文件日志和Clash缓存
|
||||
D/A/EventHandler: new status: Started ✅ 成功启动!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 影响评估
|
||||
|
||||
### 功能影响
|
||||
|
||||
| 功能 | 修复前 | 修复后 | 影响 |
|
||||
|------|--------|--------|------|
|
||||
| VPN 代理 | ❌ 无法启动 | ✅ 正常工作 | 无影响 |
|
||||
| 日志记录 | 文件输出 | logcat 输出 | 日志仍可用,通过 logcat 查看 |
|
||||
| Clash API | 带缓存 | 无缓存 | 节点选择不持久化,重启后重置 |
|
||||
| CommandServer | ❌ 失败 | 跳过启动 | 命令行控制不可用(非必需) |
|
||||
|
||||
### 性能影响
|
||||
|
||||
- **无性能损失**: 禁用缓存和文件日志对性能无负面影响
|
||||
- **启动速度**: 可能略微加快(减少文件 I/O 操作)
|
||||
|
||||
---
|
||||
|
||||
## 替代方案 (高级)
|
||||
|
||||
如果需要保留完整功能,可以考虑以下方案:
|
||||
|
||||
### 方案 1: 修改 sing-box 源码
|
||||
|
||||
在 sing-box 底层库中跳过 Android 平台的 chown 操作:
|
||||
|
||||
```go
|
||||
// 在文件创建后的 chown 调用处添加平台判断
|
||||
if runtime.GOOS != "android" {
|
||||
if err := os.Chown(path, uid, gid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**优点**: 保留所有功能
|
||||
**缺点**: 需要修改 sing-box 上游代码,维护成本高
|
||||
|
||||
### 方案 2: 使用内部存储
|
||||
|
||||
将文件创建在 `/data/user/0/` 目录下而不是外部存储:
|
||||
|
||||
**优点**: 避免 SELinux 限制
|
||||
**缺点**: 空间受限,不适合大文件
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 禁用文件日志后如何查看日志?
|
||||
|
||||
**A**: 使用 adb logcat:
|
||||
```bash
|
||||
adb logcat | grep "A/BoxService\|singbox"
|
||||
```
|
||||
|
||||
### Q2: 禁用 Clash 缓存后有什么影响?
|
||||
|
||||
**A**: 每次启动 VPN 时,节点选择会重置为默认值,但不影响 VPN 的核心代理功能。
|
||||
|
||||
### Q3: 为什么 hiddify-app 可以正常运行?
|
||||
|
||||
**A**: hiddify-app 使用的 libcore 版本已经包含了这些修复,或者使用了不同的配置策略。
|
||||
|
||||
### Q4: 这个修复是否适用于所有 Android 版本?
|
||||
|
||||
**A**: 是的,这个修复对 Android 11 及以下版本也兼容,不会产生负面影响。
|
||||
|
||||
---
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Android SELinux 权限文档](https://source.android.com/docs/security/features/selinux)
|
||||
- [sing-box 配置文档](https://sing-box.sagernet.org/configuration/)
|
||||
- [Clash API 配置](https://sing-box.sagernet.org/configuration/experimental/clash-api/)
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
- **2025-10-27**: 初始版本,包含三个核心修复方案
|
||||
2
libcore
2
libcore
@ -1 +1 @@
|
||||
Subproject commit bfb026f06f8d9a70284cc585cb87f21ee3aa4d05
|
||||
Subproject commit f993a57755c37e08b02042037cbbf508c66c51f9
|
||||
Loading…
x
Reference in New Issue
Block a user