fix: 精简脚本

This commit is contained in:
speakeloudest 2026-01-09 06:52:55 -08:00
parent b90d451bcc
commit c9a6ad2046
42 changed files with 0 additions and 5649 deletions

View File

@ -1,343 +0,0 @@
# ✅ 旧数据清理修复总结
## 🎯 修复完成
**修复日期**: 2025-10-31
**修复对象**: 每次安装APP时个人中心显示旧邮箱账号 `calvin.duke@hotmail.com` 的问题
**修复状态**: ✅ **完成并通过验证**
---
## 📊 修复内容概览
本次修复包含**三层防护机制**,确保不会出现旧数据残留问题。
| 层级 | 文件 | 修复方法 | 优先级 |
|-----|------|--------|------|
| 1⃣ 应用启动层 | `kr_splash_controller.dart` | DEBUG模式自动清理 | 最高 |
| 2⃣ 数据验证层 | `app_run_data.dart` | Token合法性检查 | 高 |
| 3⃣ 打包预防层 | `clean_build_cache.sh` | 打包前清理脚本 | 中 |
---
## 🔧 详细修改清单
### 修改1: kr_splash_controller.dart
**新增文件导入** (第7, 10行):
```dart
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:kaer_with_panels/app/utils/kr_secure_storage.dart';
```
**修改onInit方法** (第50-55行):
```dart
// 🔧 修复1.0:新增 - DEBUG模式下清理旧数据
if (kDebugMode) {
KRLogUtil.kr_i('🧹 DEBUG模式准备清理旧本地存储数据', tag: 'SplashController');
_kr_clearOldLocalData();
}
```
**新增清理方法** (第396-415行):
```dart
/// 🔧 修复1.1清理旧的本地存储数据DEBUG模式专用
Future<void> _kr_clearOldLocalData() async {
// 清理USER_INFO和DEVICE_INFO
}
```
**影响**: ✅ 无编译错误, ✅ 无性能影响, ✅ 100%解决旧数据问题
---
### 修改2: app_run_data.dart
**新增文件导入** (第2行):
```dart
import 'dart:math' show min;
```
**新增Token验证方法** (第68-121行):
```dart
/// 🔧 修复2.1验证Token格式是否有效
bool _kr_isValidToken(String token) {
// 检查JWT格式: header.payload.signature
// 验证base64编码
// 验证JSON有效性
}
```
**修改初始化逻辑** (第294-315行):
```dart
// 🔧 修复2验证token有效性和账号信息完整性
if (kr_token != null && kr_token!.isNotEmpty && _kr_isValidToken(kr_token!)) {
if (kr_account.value != null && kr_account.value!.isNotEmpty) {
// ✅ 通过验证,恢复登录
} else {
// ❌ 账号为空,清理数据
}
} else {
// ❌ Token无效清理数据
}
```
**影响**: ✅ 无编译错误, ✅ 性能影响微乎其微(<1ms), 检测到任何异常数据立即清理
---
### 修改3: clean_build_cache.sh
**新增文件**: `scripts/clean_build_cache.sh`
**功能**:
- ✅ 清理macOS应用数据
- ✅ 清理Hive数据库文件
- ✅ 清理Flutter构建缓存
- ✅ 清理构建产物
**使用方法**:
```bash
cd scripts/
./clean_build_cache.sh
flutter pub get
./build_android.sh # 或其他平台脚本
```
---
### 修改4: DATA_CLEANUP_README.md
**新增文件**: `scripts/DATA_CLEANUP_README.md`
**内容**:
- 📋 详细的修复说明
- 🧪 测试验证方法
- 🔍 日志信息参考
- ⚠️ 注意事项和故障排查
---
## ✅ 代码验证结果
```
🧪 测试Token验证逻辑
✅ 测试1有效的JWT token - 通过
✅ 测试2格式错误 - 分段不足 - 正确拒绝
✅ 测试3格式错误 - 空payload - 正确拒绝
✅ 测试4格式错误 - 无效base64 - 正确拒绝
📝 代码分析: 0个错误, 0个与修复相关的警告
```
---
## 🔄 修复流程图
```
APP启动
onInit() 执行
if (kDebugMode)
├─ YES → 清理旧数据 ✅
└─ NO → 跳过清理 (生产环境)
初始化用户信息 kr_initializeUserInfo()
Token合法性检查 _kr_isValidToken()
├─ ✅ 有效 → 恢复登录
└─ ❌ 无效 → 自动清理 kr_loginOut()
进入主页
├─ 已登录: 显示账号
└─ 未登录: 显示未登录提示
```
---
## 📈 修复效果
### 修复前
- ❌ 显示旧邮箱账号 `calvin.duke@hotmail.com`
- ❌ 无法追踪数据来源
- ❌ 用户困惑
### 修复后
- ✅ 新安装时显示未登录
- ✅ 自动检测和清理异常数据
- ✅ 完整的日志追踪
- ✅ 用户体验改善
---
## 📊 性能影响
| 操作 | 耗时 | 影响 |
|-----|------|------|
| DEBUG清理 | ~10ms | 可忽略 |
| Token验证 | <1ms | 无影响 |
| 总体启动 | 无明显变化 | ✅ 无影响 |
---
## 🚀 部署步骤
### 步骤1: 验证代码
```bash
# 已完成 ✅
flutter analyze lib/app/modules/kr_splash/controllers/kr_splash_controller.dart
flutter analyze lib/app/common/app_run_data.dart
# 结果0个相关错误
```
### 步骤2: 打包前清理
```bash
cd scripts/
./clean_build_cache.sh
flutter pub get
```
### 步骤3: 构建APP
```bash
# Android
./build_android.sh
# iOS
./build_ios.sh
# macOS
./build_macos.sh
# Linux
./build_linux.sh
```
### 步骤4: 测试验证
1. 安装新构建的APP
2. 打开个人中心
3. 验证不显示旧账号
4. 查看日志确认清理信息
---
## 🔍 日志验证
### 成功清理的日志DEBUG模式
```
🧹 DEBUG模式准备清理旧本地存储数据
🧹 开始清理旧本地存储数据...
✅ 已清理USER_INFO
✅ 已清理DEVICE_INFO
✅ 旧本地存储数据已全部清理
```
### Token验证通过
```
✅ Token格式验证通过
✅ Token和账号验证通过设置登录状态为true
📊 恢复账号: user@example.com
```
### Token验证失败
```
❌ Token格式无效分段数不对 (2 != 3)
⚠️ Token验证失败或格式错误清理该条用户数据
```
---
## 📁 文件清单
### 修改的文件
- ✅ `lib/app/modules/kr_splash/controllers/kr_splash_controller.dart` (+22行)
- ✅ `lib/app/common/app_run_data.dart` (+98行)
### 新增的文件
- ✅ `scripts/clean_build_cache.sh` (新增)
- ✅ `scripts/DATA_CLEANUP_README.md` (新增)
- ✅ `FIX_DATA_CLEANUP_SUMMARY.md` (本文件)
### 总计变更
- 新增: 3个文件
- 修改: 2个文件
- 删除: 0个文件
- 总代码行数: +120行
---
## ⚡ 关键特性
### 🛡️ 多层防护
1. **应用启动层**: DEBUG模式自动清理
2. **数据验证层**: Token格式检查
3. **打包预防层**: 打包前清理脚本
### 🎯 精准定位
- ✅ 检测被污染的Token
- ✅ 检测空的账号信息
- ✅ 检测格式错误的数据
### 🔒 安全保障
- ✅ 生产环境不受影响仅DEBUG清理
- ✅ 用户有效数据不会被误删
- ✅ 完整的日志审计
### 📝 易于维护
- ✅ 清晰的代码注释
- ✅ 完整的文档说明
- ✅ 多种调试日志
---
## 📞 故障排查
### Q: 修复后还是显示旧账号?
A: 检查以下几点:
1. 是否完全卸载了旧APP
2. 是否运行了 `clean_build_cache.sh`
3. 查看启动日志是否有清理消息
### Q: 正常登录的用户数据会丢失吗?
A: **不会!** 只有以下情况才会清理:
- Token格式错误
- 账号信息为空
- JSON无法解析
### Q: 是否影响性能?
A: **影响微乎其微**
- DEBUG清理: ~10ms
- Token验证: <1ms
- 对用户无感知
---
## ✨ 总结
✅ **问题已彻底解决**
通过三层防护机制:
1. 应用启动自动清理 (DEBUG)
2. 数据恢复时验证
3. 打包前预防清理
确保不会再出现旧数据残留问题。
**修复完全向后兼容,不影响现有用户!**
---
## 📋 审核清单
- ✅ 代码修改完成
- ✅ 代码无语法错误
- ✅ 逻辑经过验证
- ✅ 文档已编写
- ✅ 清理脚本已测试
- ✅ 日志信息完整
- ✅ 向后兼容性检查
- ✅ 性能影响评估
**所有项目均已通过!** ✅

View File

@ -1,82 +0,0 @@
#!/bin/bash
# Android 多架构构建脚本
# 支持构建不同架构的 APK
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${GREEN}🚀 开始构建 Android APK...${NC}"
# 清理之前的构建
echo -e "${YELLOW}🧹 清理之前的构建...${NC}"
flutter clean
flutter pub get
# 构建发布版本 APK
echo -e "${YELLOW}🔨 构建 Android APK所有架构...${NC}"
flutter build apk --release
# 显示构建结果
echo -e "${GREEN}✅ Android APK 构建完成!${NC}"
echo ""
echo -e "${BLUE}📦 构建产物:${NC}"
echo ""
# Universal APK (包含所有架构)
if [ -f "build/app/outputs/flutter-apk/app-release.apk" ]; then
SIZE=$(du -h "build/app/outputs/flutter-apk/app-release.apk" | cut -f1)
echo -e "${GREEN}✓ Universal APK (所有架构): app-release.apk${NC}"
echo -e " 大小: $SIZE"
echo -e " 路径: build/app/outputs/flutter-apk/app-release.apk"
echo ""
fi
# 32位 ARM (armeabi-v7a)
if [ -f "build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk" ]; then
SIZE=$(du -h "build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk" | cut -f1)
echo -e "${GREEN}✓ 32位 ARM (armeabi-v7a): app-armeabi-v7a-release.apk${NC}"
echo -e " 大小: $SIZE"
echo -e " 路径: build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk"
echo ""
fi
# 64位 ARM (arm64-v8a)
if [ -f "build/app/outputs/flutter-apk/app-arm64-v8a-release.apk" ]; then
SIZE=$(du -h "build/app/outputs/flutter-apk/app-arm64-v8a-release.apk" | cut -f1)
echo -e "${GREEN}✓ 64位 ARM (arm64-v8a): app-arm64-v8a-release.apk${NC}"
echo -e " 大小: $SIZE"
echo -e " 路径: build/app/outputs/flutter-apk/app-arm64-v8a-release.apk"
echo ""
fi
# x86 (32位)
if [ -f "build/app/outputs/flutter-apk/app-x86-release.apk" ]; then
SIZE=$(du -h "build/app/outputs/flutter-apk/app-x86-release.apk" | cut -f1)
echo -e "${GREEN}✓ 32位 x86: app-x86-release.apk${NC}"
echo -e " 大小: $SIZE"
echo -e " 路径: build/app/outputs/flutter-apk/app-x86-release.apk"
echo ""
fi
# x86_64 (64位)
if [ -f "build/app/outputs/flutter-apk/app-x86_64-release.apk" ]; then
SIZE=$(du -h "build/app/outputs/flutter-apk/app-x86_64-release.apk" | cut -f1)
echo -e "${GREEN}✓ 64位 x86_64: app-x86_64-release.apk${NC}"
echo -e " 大小: $SIZE"
echo -e " 路径: build/app/outputs/flutter-apk/app-x86_64-release.apk"
echo ""
fi
echo -e "${BLUE}📝 说明:${NC}"
echo " • Universal APK: 适用于所有设备,但体积最大"
echo " • armeabi-v7a: 适用于 32位 ARM 设备(较旧的设备)"
echo " • arm64-v8a: 适用于 64位 ARM 设备(现代设备,推荐)"
echo ""
echo -e "${GREEN}🎉 构建完成!${NC}"

View File

@ -1,327 +0,0 @@
#!/bin/bash
# iOS 自动化构建脚本
# 支持开发版本和分发版本的构建
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查环境
check_environment() {
log_info "检查构建环境..."
# 检查 Flutter
if ! command -v flutter &> /dev/null; then
log_error "Flutter 未安装或不在 PATH 中"
exit 1
fi
# 检查 Xcode
if ! command -v xcodebuild &> /dev/null; then
log_error "Xcode 未安装或不在 PATH 中"
exit 1
fi
# 检查必要的环境变量
if [ -z "$APPLE_ID" ] || [ -z "$TEAM_ID" ] || [ -z "$BUNDLE_ID" ]; then
log_error "请先运行: source ios_signing_config.sh"
exit 1
fi
log_success "环境检查通过"
}
# 检查证书
check_certificates() {
log_info "检查开发者证书..."
# 检查开发证书
if ! security find-identity -v -p codesigning | grep -q "iPhone Developer\|Apple Development"; then
log_error "未找到有效的开发证书"
log_info "请确保已安装开发者证书"
exit 1
fi
log_success "找到有效的开发证书"
}
# 清理构建
clean_build() {
log_info "清理之前的构建..."
flutter clean
rm -rf build/ios
rm -rf ios/build
log_success "清理完成"
}
# 获取依赖
get_dependencies() {
log_info "获取 Flutter 依赖..."
flutter pub get
log_success "依赖获取完成"
}
# 构建 iOS 应用
build_ios_app() {
local build_type=$1
local configuration=$2
log_info "开始构建 iOS 应用 (${build_type})..."
# 设置构建参数
local build_args="--release"
if [ "$build_type" = "debug" ]; then
build_args="--debug"
fi
# 构建 Flutter 应用
flutter build ios $build_args --no-codesign
# 检查构建结果
local app_path="build/ios/iphoneos/Runner.app"
if [ ! -d "$app_path" ]; then
log_error "iOS 应用构建失败: $app_path 不存在"
exit 1
fi
log_success "iOS 应用构建完成: $app_path"
}
# 签名应用
sign_app() {
local app_path=$1
local identity=$2
local provisioning_profile=$3
log_info "开始签名应用..."
# 移除旧的签名
codesign --remove-signature "$app_path"
# 签名应用
codesign --force --sign "$identity" \
--entitlements ios/Runner/Runner.entitlements \
"$app_path"
# 验证签名
codesign --verify --verbose "$app_path"
if [ $? -eq 0 ]; then
log_success "应用签名成功"
else
log_error "应用签名失败"
exit 1
fi
}
# 创建 IPA 文件
create_ipa() {
local app_path=$1
local ipa_path=$2
log_info "创建 IPA 文件..."
# 创建 Payload 目录
local payload_dir="build/ios/Payload"
mkdir -p "$payload_dir"
# 复制应用
cp -R "$app_path" "$payload_dir/"
# 创建 IPA
cd build/ios
zip -r "${ipa_path##*/}" Payload/
cd ../..
# 清理 Payload 目录
rm -rf "$payload_dir"
if [ -f "$ipa_path" ]; then
log_success "IPA 文件创建成功: $ipa_path"
else
log_error "IPA 文件创建失败"
exit 1
fi
}
# 创建 DMG 文件
create_dmg() {
local ipa_path=$1
local dmg_path=$2
log_info "创建 DMG 文件..."
# 创建临时目录
local temp_dir="build/ios/temp_dmg"
mkdir -p "$temp_dir"
# 复制 IPA 到临时目录
cp "$ipa_path" "$temp_dir/"
# 创建 DMG
hdiutil create -srcfolder "$temp_dir" \
-volname "BearVPN iOS" \
-fs HFS+ \
-format UDZO \
-imagekey zlib-level=9 \
"$dmg_path"
# 清理临时目录
rm -rf "$temp_dir"
if [ -f "$dmg_path" ]; then
log_success "DMG 文件创建成功: $dmg_path"
else
log_error "DMG 文件创建失败"
exit 1
fi
}
# 验证构建结果
verify_build() {
local ipa_path=$1
local dmg_path=$2
log_info "验证构建结果..."
# 检查文件大小
local ipa_size=$(du -h "$ipa_path" | cut -f1)
local dmg_size=$(du -h "$dmg_path" | cut -f1)
log_info "IPA 大小: $ipa_size"
log_info "DMG 大小: $dmg_size"
# 验证 IPA 内容
unzip -l "$ipa_path" | grep -q "Payload/Runner.app"
if [ $? -eq 0 ]; then
log_success "IPA 内容验证通过"
else
log_error "IPA 内容验证失败"
exit 1
fi
}
# 显示构建结果
show_result() {
local ipa_path=$1
local dmg_path=$2
log_success "=========================================="
log_success "iOS 构建完成!"
log_success "=========================================="
log_info "应用名称: $APP_NAME"
log_info "版本: $VERSION"
log_info "Bundle ID: $BUNDLE_ID"
log_info "IPA 文件: $ipa_path"
log_info "DMG 文件: $dmg_path"
log_info "开发者: $SIGNING_IDENTITY"
log_success "=========================================="
log_info "现在可以安装到设备或上传到 App Store"
log_success "=========================================="
}
# 主函数
main() {
local build_type=${1:-"release"}
log_info "开始 iOS 构建流程..."
log_info "构建类型: $build_type"
log_info "=========================================="
check_environment
check_certificates
clean_build
get_dependencies
build_ios_app "$build_type"
# 设置路径
local app_path="build/ios/iphoneos/Runner.app"
local ipa_path="$IPA_PATH"
local dmg_path="$DMG_PATH"
# 创建输出目录
mkdir -p "$(dirname "$ipa_path")"
mkdir -p "$(dirname "$dmg_path")"
# 签名应用
sign_app "$app_path" "$SIGNING_IDENTITY" ""
# 创建 IPA
create_ipa "$app_path" "$ipa_path"
# 创建 DMG
create_dmg "$ipa_path" "$dmg_path"
# 验证结果
verify_build "$ipa_path" "$dmg_path"
# 显示结果
show_result "$ipa_path" "$dmg_path"
log_success "所有操作完成!"
}
# 显示帮助信息
show_help() {
echo "iOS 自动化构建脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " debug 构建调试版本"
echo " release 构建发布版本 (默认)"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 # 构建发布版本"
echo " $0 debug # 构建调试版本"
echo " $0 release # 构建发布版本"
echo ""
echo "注意: 请先运行 'source ios_signing_config.sh' 配置签名信息"
}
# 处理命令行参数
case "${1:-}" in
"help"|"-h"|"--help")
show_help
exit 0
;;
"debug"|"release")
main "$1"
;;
"")
main "release"
;;
*)
log_error "未知选项: $1"
show_help
exit 1
;;
esac

View File

@ -1,358 +0,0 @@
#!/bin/bash
# iOS App Store 构建和上传脚本
# 支持自动构建、签名、上传到 App Store Connect
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查环境
check_environment() {
log_info "检查 App Store 构建环境..."
# 检查必要的环境变量
if [ -z "$APPLE_ID" ] || [ -z "$APPLE_PASSWORD" ] || [ -z "$TEAM_ID" ]; then
log_error "请先运行: source ios_signing_config.sh"
exit 1
fi
# 检查 Xcode
if ! command -v xcodebuild &> /dev/null; then
log_error "Xcode 未安装或不在 PATH 中"
exit 1
fi
# 检查 xcrun altool
if ! command -v xcrun &> /dev/null; then
log_error "xcrun 不可用"
exit 1
fi
log_success "环境检查通过"
}
# 检查证书和配置文件
check_certificates_and_profiles() {
log_info "检查证书和配置文件..."
# 检查分发证书
if ! security find-identity -v -p codesigning | grep -q "iPhone Distribution\|Apple Distribution"; then
log_error "未找到有效的分发证书"
log_info "请确保已安装 Apple Distribution 证书"
exit 1
fi
# 检查配置文件
local profiles_dir="$HOME/Library/MobileDevice/Provisioning Profiles"
if [ ! -d "$profiles_dir" ]; then
log_error "配置文件目录不存在: $profiles_dir"
exit 1
fi
log_success "证书和配置文件检查通过"
}
# 清理构建
clean_build() {
log_info "清理之前的构建..."
flutter clean
rm -rf build/ios
rm -rf ios/build
log_success "清理完成"
}
# 获取依赖
get_dependencies() {
log_info "获取 Flutter 依赖..."
flutter pub get
log_success "依赖获取完成"
}
# 构建 iOS 应用
build_ios_app() {
log_info "开始构建 iOS 应用 (App Store)..."
# 构建 Flutter 应用
flutter build ios --release --no-codesign
# 检查构建结果
local app_path="build/ios/iphoneos/Runner.app"
if [ ! -d "$app_path" ]; then
log_error "iOS 应用构建失败: $app_path 不存在"
exit 1
fi
log_success "iOS 应用构建完成: $app_path"
}
# 使用 Xcode 构建和签名
build_with_xcode() {
log_info "使用 Xcode 构建和签名..."
# 进入 iOS 目录
cd ios
# 使用 xcodebuild 构建
xcodebuild -workspace Runner.xcworkspace \
-scheme Runner \
-configuration Release \
-destination generic/platform=iOS \
-archivePath ../build/ios/Runner.xcarchive \
archive
if [ $? -ne 0 ]; then
log_error "Xcode 构建失败"
exit 1
fi
# 返回项目根目录
cd ..
log_success "Xcode 构建完成"
}
# 导出 IPA
export_ipa() {
log_info "导出 IPA 文件..."
# 创建导出选项文件
local export_options_plist="ios/ExportOptions.plist"
cat > "$export_options_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>$TEAM_ID</string>
<key>uploadBitcode</key>
<false/>
<key>uploadSymbols</key>
<true/>
<key>compileBitcode</key>
<false/>
</dict>
</plist>
EOF
# 导出 IPA
xcodebuild -exportArchive \
-archivePath build/ios/Runner.xcarchive \
-exportPath build/ios/export \
-exportOptionsPlist "$export_options_plist"
if [ $? -ne 0 ]; then
log_error "IPA 导出失败"
exit 1
fi
# 移动 IPA 文件
local ipa_path="$IPA_PATH"
mkdir -p "$(dirname "$ipa_path")"
mv build/ios/export/Runner.ipa "$ipa_path"
log_success "IPA 文件导出成功: $ipa_path"
}
# 验证 IPA
validate_ipa() {
local ipa_path=$1
log_info "验证 IPA 文件..."
# 使用 xcrun altool 验证
xcrun altool --validate-app \
-f "$ipa_path" \
-t ios \
-u "$APPLE_ID" \
-p "$APPLE_PASSWORD"
if [ $? -eq 0 ]; then
log_success "IPA 验证通过"
else
log_error "IPA 验证失败"
exit 1
fi
}
# 上传到 App Store
upload_to_appstore() {
local ipa_path=$1
log_info "上传到 App Store Connect..."
# 使用 xcrun altool 上传
xcrun altool --upload-app \
-f "$ipa_path" \
-t ios \
-u "$APPLE_ID" \
-p "$APPLE_PASSWORD"
if [ $? -eq 0 ]; then
log_success "上传到 App Store Connect 成功"
else
log_error "上传到 App Store Connect 失败"
exit 1
fi
}
# 创建 DMG
create_dmg() {
local ipa_path=$1
local dmg_path=$2
log_info "创建 DMG 文件..."
# 创建临时目录
local temp_dir="build/ios/temp_dmg"
mkdir -p "$temp_dir"
# 复制 IPA 到临时目录
cp "$ipa_path" "$temp_dir/"
# 创建 DMG
hdiutil create -srcfolder "$temp_dir" \
-volname "BearVPN iOS App Store" \
-fs HFS+ \
-format UDZO \
-imagekey zlib-level=9 \
"$dmg_path"
# 清理临时目录
rm -rf "$temp_dir"
if [ -f "$dmg_path" ]; then
log_success "DMG 文件创建成功: $dmg_path"
else
log_error "DMG 文件创建失败"
exit 1
fi
}
# 显示构建结果
show_result() {
local ipa_path=$1
local dmg_path=$2
log_success "=========================================="
log_success "iOS App Store 构建完成!"
log_success "=========================================="
log_info "应用名称: $APP_NAME"
log_info "版本: $VERSION"
log_info "Bundle ID: $BUNDLE_ID"
log_info "IPA 文件: $ipa_path"
log_info "DMG 文件: $dmg_path"
log_info "开发者: $DISTRIBUTION_IDENTITY"
log_success "=========================================="
log_info "应用已上传到 App Store Connect"
log_info "请在 App Store Connect 中完成最终发布"
log_success "=========================================="
}
# 主函数
main() {
local upload=${1:-"true"}
log_info "开始 iOS App Store 构建流程..."
log_info "上传到 App Store: $upload"
log_info "=========================================="
check_environment
check_certificates_and_profiles
clean_build
get_dependencies
build_ios_app
build_with_xcode
export_ipa
# 设置路径
local ipa_path="$IPA_PATH"
local dmg_path="$DMG_PATH"
# 创建输出目录
mkdir -p "$(dirname "$dmg_path")"
# 验证 IPA
validate_ipa "$ipa_path"
# 上传到 App Store如果启用
if [ "$upload" = "true" ]; then
upload_to_appstore "$ipa_path"
else
log_info "跳过上传到 App Store"
fi
# 创建 DMG
create_dmg "$ipa_path" "$dmg_path"
# 显示结果
show_result "$ipa_path" "$dmg_path"
log_success "所有操作完成!"
}
# 显示帮助信息
show_help() {
echo "iOS App Store 构建和上传脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " upload 构建并上传到 App Store Connect (默认)"
echo " build 仅构建,不上传"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 # 构建并上传到 App Store"
echo " $0 upload # 构建并上传到 App Store"
echo " $0 build # 仅构建,不上传"
echo ""
echo "注意: 请先运行 'source ios_signing_config.sh' 配置签名信息"
}
# 处理命令行参数
case "${1:-}" in
"help"|"-h"|"--help")
show_help
exit 0
;;
"upload"|"build")
main "$1"
;;
"")
main "upload"
;;
*)
log_error "未知选项: $1"
show_help
exit 1
;;
esac

View File

@ -1,382 +0,0 @@
#!/bin/bash
# iOS 签名打包 DMG 脚本
# 专门用于创建签名的 iOS 应用 DMG 文件
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查环境
check_environment() {
log_info "检查构建环境..."
# 检查必要的环境变量
if [ -z "$APPLE_ID" ] || [ -z "$TEAM_ID" ] || [ -z "$BUNDLE_ID" ]; then
log_error "请先运行: source ios_signing_config.sh"
exit 1
fi
# 检查 Flutter
if ! command -v flutter &> /dev/null; then
log_error "Flutter 未安装或不在 PATH 中"
exit 1
fi
# 检查 Xcode
if ! command -v xcodebuild &> /dev/null; then
log_error "Xcode 未安装或不在 PATH 中"
exit 1
fi
log_success "环境检查通过"
}
# 检查证书
check_certificates() {
log_info "检查开发者证书..."
# 检查是否有可用的签名身份
local identities=$(security find-identity -v -p codesigning 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$identities" ]; then
log_error "未找到可用的开发者证书"
log_info "请确保已安装开发者证书"
log_info "您可以通过以下方式获取证书:"
log_info "1. 登录 https://developer.apple.com"
log_info "2. 进入 'Certificates, Identifiers & Profiles'"
log_info "3. 创建 'iOS Development' 证书"
log_info "4. 下载并双击安装证书"
exit 1
fi
# 显示可用的证书
log_info "找到以下可用证书:"
echo "$identities"
log_success "证书检查通过"
}
# 清理构建
clean_build() {
log_info "清理之前的构建..."
flutter clean
rm -rf build/ios
rm -rf ios/build
log_success "清理完成"
}
# 获取依赖
get_dependencies() {
log_info "获取 Flutter 依赖..."
flutter pub get
log_success "依赖获取完成"
}
# 构建 iOS 应用
build_ios_app() {
local build_type=${1:-"release"}
log_info "开始构建 iOS 应用 (${build_type})..."
# 设置构建参数
local build_args="--release"
if [ "$build_type" = "debug" ]; then
build_args="--debug"
fi
# 构建 Flutter 应用
flutter build ios $build_args --no-codesign
# 检查构建结果
local app_path="build/ios/iphoneos/Runner.app"
if [ ! -d "$app_path" ]; then
log_error "iOS 应用构建失败: $app_path 不存在"
exit 1
fi
log_success "iOS 应用构建完成: $app_path"
}
# 使用 Xcode 构建和签名
build_with_xcode() {
log_info "使用 Xcode 构建和签名..."
# 进入 iOS 目录
cd ios
# 使用 xcodebuild 构建
xcodebuild -workspace Runner.xcworkspace \
-scheme Runner \
-configuration Release \
-destination generic/platform=iOS \
-archivePath ../build/ios/Runner.xcarchive \
archive
if [ $? -ne 0 ]; then
log_error "Xcode 构建失败"
exit 1
fi
# 返回项目根目录
cd ..
log_success "Xcode 构建完成"
}
# 导出 IPA
export_ipa() {
log_info "导出 IPA 文件..."
# 创建导出选项文件
local export_options_plist="ios/ExportOptions.plist"
cat > "$export_options_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>development</string>
<key>teamID</key>
<string>$TEAM_ID</string>
<key>uploadBitcode</key>
<false/>
<key>uploadSymbols</key>
<true/>
<key>compileBitcode</key>
<false/>
</dict>
</plist>
EOF
# 导出 IPA
xcodebuild -exportArchive \
-archivePath build/ios/Runner.xcarchive \
-exportPath build/ios/export \
-exportOptionsPlist "$export_options_plist"
if [ $? -ne 0 ]; then
log_error "IPA 导出失败"
exit 1
fi
# 移动 IPA 文件
local ipa_path="$IPA_PATH"
mkdir -p "$(dirname "$ipa_path")"
mv build/ios/export/Runner.ipa "$ipa_path"
log_success "IPA 文件导出成功: $ipa_path"
}
# 创建 DMG 文件
create_dmg() {
local ipa_path=$1
local dmg_path=$2
log_info "创建 DMG 文件..."
# 创建临时目录
local temp_dir="build/ios/temp_dmg"
mkdir -p "$temp_dir"
# 复制 IPA 到临时目录
cp "$ipa_path" "$temp_dir/"
# 创建 DMG
hdiutil create -srcfolder "$temp_dir" \
-volname "BearVPN iOS" \
-fs HFS+ \
-format UDZO \
-imagekey zlib-level=9 \
"$dmg_path"
# 清理临时目录
rm -rf "$temp_dir"
if [ -f "$dmg_path" ]; then
log_success "DMG 文件创建成功: $dmg_path"
else
log_error "DMG 文件创建失败"
exit 1
fi
}
# 签名 DMG
sign_dmg() {
local dmg_path=$1
log_info "签名 DMG 文件..."
# 获取可用的签名身份
local signing_identity=$(security find-identity -v -p codesigning | grep "iPhone Developer\|Apple Development" | head -1 | cut -d'"' -f2)
if [ -z "$signing_identity" ]; then
log_warning "未找到可用的签名身份,跳过 DMG 签名"
return 0
fi
# 签名 DMG
codesign --force --sign "$signing_identity" "$dmg_path"
if [ $? -eq 0 ]; then
log_success "DMG 签名成功"
else
log_warning "DMG 签名失败,但继续执行"
fi
}
# 验证构建结果
verify_build() {
local ipa_path=$1
local dmg_path=$2
log_info "验证构建结果..."
# 检查文件大小
local ipa_size=$(du -h "$ipa_path" | cut -f1)
local dmg_size=$(du -h "$dmg_path" | cut -f1)
log_info "IPA 大小: $ipa_size"
log_info "DMG 大小: $dmg_size"
# 验证 IPA 内容
unzip -l "$ipa_path" | grep -q "Payload/Runner.app"
if [ $? -eq 0 ]; then
log_success "IPA 内容验证通过"
else
log_error "IPA 内容验证失败"
exit 1
fi
# 验证 DMG
hdiutil verify "$dmg_path" > /dev/null 2>&1
if [ $? -eq 0 ]; then
log_success "DMG 验证通过"
else
log_warning "DMG 验证失败,但文件可能仍然可用"
fi
}
# 显示构建结果
show_result() {
local ipa_path=$1
local dmg_path=$2
local build_type=$3
log_success "=========================================="
log_success "iOS DMG 构建完成!"
log_success "=========================================="
log_info "应用名称: $APP_NAME"
log_info "版本: $VERSION"
log_info "Bundle ID: $BUNDLE_ID"
log_info "构建类型: $build_type"
log_info "IPA 文件: $ipa_path"
log_info "DMG 文件: $dmg_path"
log_info "开发者: $SIGNING_IDENTITY"
log_success "=========================================="
log_info "现在可以分发 DMG 文件给用户"
log_info "用户可以通过 Xcode 或 Apple Configurator 安装 IPA"
log_success "=========================================="
}
# 主函数
main() {
local build_type=${1:-"release"}
log_info "开始 iOS DMG 构建流程..."
log_info "构建类型: $build_type"
log_info "=========================================="
check_environment
check_certificates
clean_build
get_dependencies
build_ios_app "$build_type"
build_with_xcode
export_ipa
# 设置路径
local ipa_path="$IPA_PATH"
local dmg_path="$DMG_PATH"
# 创建输出目录
mkdir -p "$(dirname "$ipa_path")"
mkdir -p "$(dirname "$dmg_path")"
# 创建 DMG
create_dmg "$ipa_path" "$dmg_path"
# 签名 DMG
sign_dmg "$dmg_path"
# 验证结果
verify_build "$ipa_path" "$dmg_path"
# 显示结果
show_result "$ipa_path" "$dmg_path" "$build_type"
log_success "所有操作完成!"
}
# 显示帮助信息
show_help() {
echo "iOS DMG 构建脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " debug 构建调试版本"
echo " release 构建发布版本 (默认)"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 # 构建发布版本"
echo " $0 debug # 构建调试版本"
echo " $0 release # 构建发布版本"
echo ""
echo "注意: 请先运行 'source ios_signing_config.sh' 配置签名信息"
}
# 处理命令行参数
case "${1:-}" in
"help"|"-h"|"--help")
show_help
exit 0
;;
"debug"|"release")
main "$1"
;;
"")
main "release"
;;
*)
log_error "未知选项: $1"
show_help
exit 1
;;
esac

View File

@ -1,252 +0,0 @@
#!/bin/bash
# 简化的 iOS 构建脚本(无签名版本)
# 用于快速测试和开发
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查环境
check_environment() {
log_info "检查构建环境..."
# 检查 Flutter
if ! command -v flutter &> /dev/null; then
log_error "Flutter 未安装或不在 PATH 中"
exit 1
fi
# 检查 Xcode
if ! command -v xcodebuild &> /dev/null; then
log_error "Xcode 未安装或不在 PATH 中"
exit 1
fi
log_success "环境检查通过"
}
# 清理构建
clean_build() {
log_info "清理之前的构建..."
flutter clean
rm -rf build/ios
rm -rf ios/build
log_success "清理完成"
}
# 获取依赖
get_dependencies() {
log_info "获取 Flutter 依赖..."
flutter pub get
log_success "依赖获取完成"
}
# 构建 iOS 应用
build_ios_app() {
local build_type=${1:-"debug"}
log_info "开始构建 iOS 应用 (${build_type})..."
# 设置构建参数
local build_args="--debug"
if [ "$build_type" = "release" ]; then
build_args="--release"
fi
# 构建 Flutter 应用
flutter build ios $build_args --no-codesign
# 检查构建结果
local app_path="build/ios/iphoneos/Runner.app"
if [ ! -d "$app_path" ]; then
log_error "iOS 应用构建失败: $app_path 不存在"
exit 1
fi
log_success "iOS 应用构建完成: $app_path"
}
# 创建 IPA 文件
create_ipa() {
local app_path=$1
local ipa_path=$2
log_info "创建 IPA 文件..."
# 创建 Payload 目录
local payload_dir="build/ios/Payload"
mkdir -p "$payload_dir"
# 复制应用
cp -R "$app_path" "$payload_dir/"
# 创建 IPA
cd build/ios
zip -r "${ipa_path##*/}" Payload/
cd ../..
# 清理 Payload 目录
rm -rf "$payload_dir"
if [ -f "$ipa_path" ]; then
log_success "IPA 文件创建成功: $ipa_path"
else
log_error "IPA 文件创建失败"
exit 1
fi
}
# 创建 DMG 文件
create_dmg() {
local ipa_path=$1
local dmg_path=$2
log_info "创建 DMG 文件..."
# 创建临时目录
local temp_dir="build/ios/temp_dmg"
mkdir -p "$temp_dir"
# 复制 IPA 到临时目录
cp "$ipa_path" "$temp_dir/"
# 创建 DMG
hdiutil create -srcfolder "$temp_dir" \
-volname "BearVPN iOS" \
-fs HFS+ \
-format UDZO \
-imagekey zlib-level=9 \
"$dmg_path"
# 清理临时目录
rm -rf "$temp_dir"
if [ -f "$dmg_path" ]; then
log_success "DMG 文件创建成功: $dmg_path"
else
log_error "DMG 文件创建失败"
exit 1
fi
}
# 显示构建结果
show_result() {
local ipa_path=$1
local dmg_path=$2
local build_type=$3
log_success "=========================================="
log_success "iOS 构建完成!"
log_success "=========================================="
log_info "构建类型: $build_type"
log_info "IPA 文件: $ipa_path"
log_info "DMG 文件: $dmg_path"
log_success "=========================================="
log_warning "注意: 此版本未签名,需要开发者证书才能安装到设备"
log_info "要创建签名版本,请使用: ./build_ios.sh"
log_success "=========================================="
}
# 主函数
main() {
local build_type=${1:-"debug"}
log_info "开始 iOS 简化构建流程..."
log_info "构建类型: $build_type"
log_info "=========================================="
check_environment
clean_build
get_dependencies
build_ios_app "$build_type"
# 设置路径
local app_path="build/ios/iphoneos/Runner.app"
local ipa_path="build/ios/BearVPN-${build_type}.ipa"
local dmg_path="build/ios/BearVPN-${build_type}-iOS.dmg"
# 创建输出目录
mkdir -p "$(dirname "$ipa_path")"
mkdir -p "$(dirname "$dmg_path")"
# 创建 IPA
create_ipa "$app_path" "$ipa_path"
# 创建 DMG
create_dmg "$ipa_path" "$dmg_path"
# 显示结果
show_result "$ipa_path" "$dmg_path" "$build_type"
log_success "所有操作完成!"
}
# 显示帮助信息
show_help() {
echo "iOS 简化构建脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " debug 构建调试版本 (默认)"
echo " release 构建发布版本"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 # 构建调试版本"
echo " $0 debug # 构建调试版本"
echo " $0 release # 构建发布版本"
echo ""
echo "注意: 此脚本创建未签名的版本,仅用于测试"
}
# 处理命令行参数
case "${1:-}" in
"help"|"-h"|"--help")
show_help
exit 0
;;
"debug"|"release")
main "$1"
;;
"")
main "debug"
;;
*)
log_error "未知选项: $1"
show_help
exit 1
;;
esac

View File

@ -1,175 +0,0 @@
#!/bin/bash
# macOS DMG 构建和签名脚本
# 需要配置以下环境变量:
# - APPLE_ID: 您的 Apple ID
# - APPLE_PASSWORD: App 专用密码
# - TEAM_ID: 您的开发者团队 ID
# - SIGNING_IDENTITY: 代码签名身份
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}🚀 开始构建 macOS DMG...${NC}"
# 检查必要的环境变量
if [ -z "$APPLE_ID" ]; then
echo -e "${RED}❌ 请设置 APPLE_ID 环境变量${NC}"
exit 1
fi
if [ -z "$APPLE_PASSWORD" ]; then
echo -e "${RED}❌ 请设置 APPLE_PASSWORD 环境变量App 专用密码)${NC}"
exit 1
fi
if [ -z "$TEAM_ID" ]; then
echo -e "${RED}❌ 请设置 TEAM_ID 环境变量${NC}"
exit 1
fi
# 设置默认签名身份(如果没有设置)
if [ -z "$SIGNING_IDENTITY" ]; then
SIGNING_IDENTITY="Developer ID Application: Your Name (${TEAM_ID})"
echo -e "${YELLOW}⚠️ 使用默认签名身份: ${SIGNING_IDENTITY}${NC}"
fi
# 清理之前的构建
echo -e "${YELLOW}🧹 清理之前的构建...${NC}"
flutter clean
rm -rf build/macos/Build/Products/Release/kaer_with_panels.app
rm -rf build/macos/Build/Products/Release/kaer_with_panels.dmg
# 构建 Flutter macOS 应用
echo -e "${YELLOW}🔨 构建 Flutter macOS 应用...${NC}"
flutter build macos --release
# 检查应用是否构建成功
APP_PATH="build/macos/Build/Products/Release/BearVPN.app"
if [ ! -d "$APP_PATH" ]; then
echo -e "${RED}❌ 应用构建失败: $APP_PATH 不存在${NC}"
exit 1
fi
echo -e "${GREEN}✅ 应用构建成功: $APP_PATH${NC}"
# 代码签名
echo -e "${YELLOW}🔐 开始代码签名...${NC}"
# 签名应用
echo -e "${YELLOW}📝 签名应用...${NC}"
codesign --force --deep --sign "$SIGNING_IDENTITY" \
--options runtime \
--timestamp \
--entitlements macos/Runner/Runner.entitlements \
"$APP_PATH"
# 验证签名
echo -e "${YELLOW}🔍 验证应用签名...${NC}"
codesign --verify --verbose "$APP_PATH"
spctl --assess --verbose "$APP_PATH"
echo -e "${GREEN}✅ 应用签名成功${NC}"
# 创建 DMG
echo -e "${YELLOW}📦 创建 DMG 安装包...${NC}"
DMG_PATH="build/macos/Build/Products/Release/BearVPN.dmg"
TEMP_DMG="build/macos/Build/Products/Release/temp.dmg"
# 创建临时 DMG
hdiutil create -srcfolder "$APP_PATH" -volname "Kaer VPN" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW -size 200m "$TEMP_DMG"
# 挂载临时 DMG
MOUNT_POINT=$(hdiutil attach -readwrite -noverify -noautoopen "$TEMP_DMG" | egrep '^/dev/' | sed 1q | awk '{print $3}')
# 等待挂载完成
sleep 2
# 设置 DMG 属性
echo -e "${YELLOW}🎨 设置 DMG 属性...${NC}"
# 创建应用程序链接
ln -s /Applications "$MOUNT_POINT/Applications"
# 设置 DMG 背景和图标(可选)
# cp dmg_background.png "$MOUNT_POINT/.background/"
# cp app_icon.icns "$MOUNT_POINT/.VolumeIcon.icns"
# 设置窗口属性
osascript <<EOF
tell application "Finder"
tell disk "Kaer VPN"
open
set current view of container window to icon view
set toolbar visible of container window to false
set statusbar visible of container window to false
set the bounds of container window to {400, 100, 900, 450}
set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 128
set background picture of theViewOptions to file ".background:dmg_background.png"
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
set position of item "BearVPN.app" of container window to {150, 200}
set position of item "Applications" of container window to {350, 200}
close
open
update without registering applications
delay 2
end tell
end tell
EOF
# 卸载 DMG
hdiutil detach "$MOUNT_POINT"
# 转换为只读 DMG
hdiutil convert "$TEMP_DMG" -format UDZO -imagekey zlib-level=9 -o "$DMG_PATH"
# 清理临时文件
rm "$TEMP_DMG"
echo -e "${GREEN}✅ DMG 创建成功: $DMG_PATH${NC}"
# 签名 DMG
echo -e "${YELLOW}🔐 签名 DMG...${NC}"
INSTALLER_IDENTITY="Developer ID Installer: Your Name (${TEAM_ID})"
codesign --sign "$INSTALLER_IDENTITY" "$DMG_PATH"
# 验证 DMG 签名
codesign --verify --verbose "$DMG_PATH"
echo -e "${GREEN}✅ DMG 签名成功${NC}"
# 公证 DMG
echo -e "${YELLOW}📋 开始公证 DMG...${NC}"
# 上传到 Apple 进行公证
xcrun notarytool submit "$DMG_PATH" \
--apple-id "$APPLE_ID" \
--password "$APPLE_PASSWORD" \
--team-id "$TEAM_ID" \
--wait
echo -e "${GREEN}✅ DMG 公证成功${NC}"
# 装订公证票据
echo -e "${YELLOW}📎 装订公证票据...${NC}"
xcrun stapler staple "$DMG_PATH"
# 验证最终 DMG
echo -e "${YELLOW}🔍 验证最终 DMG...${NC}"
spctl --assess --verbose "$DMG_PATH"
echo -e "${GREEN}🎉 DMG 构建完成!${NC}"
echo -e "${GREEN}📁 文件位置: $DMG_PATH${NC}"
echo -e "${GREEN}📏 文件大小: $(du -h "$DMG_PATH" | cut -f1)${NC}"
# 显示 DMG 信息
echo -e "${YELLOW}📊 DMG 信息:${NC}"
hdiutil imageinfo "$DMG_PATH"

View File

@ -1,108 +0,0 @@
#!/bin/bash
# 简化的 macOS DMG 构建脚本(无签名版本)
# 注意:此版本需要用户在安装时手动允许
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}🚀 开始构建 macOS DMG简化版本...${NC}"
# 清理之前的构建
echo -e "${YELLOW}🧹 清理之前的构建...${NC}"
flutter clean
# 构建 Flutter macOS 应用
echo -e "${YELLOW}🔨 构建 Flutter macOS 应用...${NC}"
flutter build macos --release
# 检查应用是否构建成功
APP_PATH="build/macos/Build/Products/Release/BearVPN.app"
if [ ! -d "$APP_PATH" ]; then
echo -e "${RED}❌ 应用构建失败: $APP_PATH 不存在${NC}"
exit 1
fi
echo -e "${GREEN}✅ 应用构建成功: $APP_PATH${NC}"
# 创建 DMG
echo -e "${YELLOW}📦 创建 DMG 安装包...${NC}"
DMG_PATH="build/macos/Build/Products/Release/BearVPN.dmg"
TEMP_DMG="build/macos/Build/Products/Release/temp.dmg"
# 创建临时 DMG
hdiutil create -srcfolder "$APP_PATH" -volname "Kaer VPN" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW -size 200m "$TEMP_DMG"
# 挂载临时 DMG
echo -e "${YELLOW}📂 挂载临时 DMG...${NC}"
MOUNT_OUTPUT=$(hdiutil attach -readwrite -noverify -noautoopen "$TEMP_DMG")
MOUNT_POINT=$(echo "$MOUNT_OUTPUT" | grep "/Volumes" | awk '{print $3}')
if [ -z "$MOUNT_POINT" ]; then
echo -e "${RED}❌ 无法挂载 DMG${NC}"
exit 1
fi
echo -e "${GREEN}✅ DMG 已挂载到: $MOUNT_POINT${NC}"
# 等待挂载完成
sleep 3
# 设置 DMG 属性
echo -e "${YELLOW}🎨 设置 DMG 属性...${NC}"
# 创建应用程序链接
ln -s /Applications "$MOUNT_POINT/Applications"
# 设置窗口属性
echo -e "${YELLOW}🖼️ 设置窗口属性...${NC}"
osascript <<EOF
tell application "Finder"
tell disk "Kaer VPN"
open
set current view of container window to icon view
set toolbar visible of container window to false
set statusbar visible of container window to false
set the bounds of container window to {400, 100, 900, 450}
set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 128
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
set position of item "BearVPN.app" of container window to {150, 200}
set position of item "Applications" of container window to {350, 200}
close
open
update without registering applications
delay 2
end tell
end tell
EOF
# 卸载 DMG
echo -e "${YELLOW}📤 卸载 DMG...${NC}"
hdiutil detach "$MOUNT_POINT" -force
# 转换为只读 DMG
hdiutil convert "$TEMP_DMG" -format UDZO -imagekey zlib-level=9 -o "$DMG_PATH"
# 清理临时文件
rm "$TEMP_DMG"
echo -e "${GREEN}✅ DMG 创建成功: $DMG_PATH${NC}"
# 显示 DMG 信息
echo -e "${YELLOW}📊 DMG 信息:${NC}"
hdiutil imageinfo "$DMG_PATH"
echo -e "${GREEN}🎉 DMG 构建完成!${NC}"
echo -e "${GREEN}📁 文件位置: $DMG_PATH${NC}"
echo -e "${GREEN}📏 文件大小: $(du -h "$DMG_PATH" | cut -f1)${NC}"
echo -e "${YELLOW}⚠️ 注意:此 DMG 未签名,用户安装时需要在安全隐私设置中手动允许${NC}"
echo -e "${YELLOW}💡 要避免手动允许,请使用 build_macos_dmg.sh 脚本进行签名和公证${NC}"

View File

@ -1,138 +0,0 @@
#!/bin/bash
# 检查公证状态的脚本
# 作者: AI Assistant
set -e
# 配置变量
APPLE_ID="kieran@newlifeephrata.us"
TEAM_ID="3UR892FAP3"
PASSWORD="gtvp-izmw-cubf-yxfe"
SUBMISSION_ID=""
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查历史提交记录
check_history() {
log_info "检查历史提交记录..."
xcrun notarytool history \
--apple-id "$APPLE_ID" \
--password "$PASSWORD" \
--team-id "$TEAM_ID"
}
# 检查特定提交状态
check_submission() {
if [ -z "$SUBMISSION_ID" ]; then
log_error "请提供提交 ID"
log_info "使用方法: $0 <submission_id>"
exit 1
fi
log_info "检查提交状态: $SUBMISSION_ID"
xcrun notarytool info "$SUBMISSION_ID" \
--apple-id "$APPLE_ID" \
--password "$PASSWORD" \
--team-id "$TEAM_ID"
}
# 检查日志
check_log() {
if [ -z "$SUBMISSION_ID" ]; then
log_error "请提供提交 ID"
exit 1
fi
log_info "获取提交日志: $SUBMISSION_ID"
xcrun notarytool log "$SUBMISSION_ID" \
--apple-id "$APPLE_ID" \
--password "$PASSWORD" \
--team-id "$TEAM_ID"
}
# 实时监控
monitor_status() {
log_info "开始实时监控公证状态..."
while true; do
echo "=========================================="
echo "时间: $(date)"
echo "=========================================="
# 检查历史记录
check_history
echo "=========================================="
echo "等待 30 秒后刷新..."
sleep 30
done
}
# 显示帮助
show_help() {
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " history - 查看历史提交记录"
echo " info <submission_id> - 查看特定提交状态"
echo " log <submission_id> - 查看提交日志"
echo " monitor - 实时监控状态"
echo " help - 显示此帮助"
echo ""
echo "示例:"
echo " $0 history"
echo " $0 info 12345678-1234-1234-1234-123456789012"
echo " $0 log 12345678-1234-1234-1234-123456789012"
echo " $0 monitor"
}
# 主函数
main() {
case "${1:-help}" in
"history")
check_history
;;
"info")
SUBMISSION_ID="$2"
check_submission
;;
"log")
SUBMISSION_ID="$2"
check_log
;;
"monitor")
monitor_status
;;
"help"|*)
show_help
;;
esac
}
# 运行主函数
main "$@"

View File

@ -1,237 +0,0 @@
#!/bin/bash
# 完成公证流程脚本
# 作者: AI Assistant
set -e
# 配置变量
APPLE_ID="kieran@newlifeephrata.us"
PASSWORD="gtvp-izmw-cubf-yxfe"
TEAM_ID="3UR892FAP3"
DMG_FILE="build/macos/Build/Products/Release/BearVPN-1.0.0-macOS-Signed.dmg"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查提交状态
check_status() {
local submission_id="$1"
log_info "检查提交状态: $submission_id"
local status=$(xcrun notarytool info "$submission_id" \
--apple-id "$APPLE_ID" \
--password "$PASSWORD" \
--team-id "$TEAM_ID" \
--output-format json | jq -r '.status')
echo "$status"
}
# 等待完成
wait_for_completion() {
local submission_id="$1"
log_info "等待公证完成..."
while true; do
local status=$(check_status "$submission_id")
case "$status" in
"Accepted")
log_success "公证成功!"
return 0
;;
"Invalid")
log_error "公证失败!"
show_log "$submission_id"
return 1
;;
"In Progress")
log_info "状态: 进行中... ($(date))"
sleep 30
;;
*)
log_warning "未知状态: $status"
sleep 30
;;
esac
done
}
# 显示日志
show_log() {
local submission_id="$1"
log_info "获取公证日志..."
xcrun notarytool log "$submission_id" \
--apple-id "$APPLE_ID" \
--password "$PASSWORD" \
--team-id "$TEAM_ID"
}
# 装订公证
staple_notarization() {
log_info "装订公证到 DMG..."
if [ ! -f "$DMG_FILE" ]; then
log_error "DMG 文件不存在: $DMG_FILE"
return 1
fi
xcrun stapler staple "$DMG_FILE"
if [ $? -eq 0 ]; then
log_success "装订成功!"
return 0
else
log_error "装订失败!"
return 1
fi
}
# 验证最终结果
verify_result() {
log_info "验证最终结果..."
# 检查装订状态
xcrun stapler validate "$DMG_FILE"
if [ $? -eq 0 ]; then
log_success "DMG 已成功装订公证!"
log_info "现在可以在其他 Mac 上正常打开了"
else
log_error "DMG 装订验证失败!"
fi
}
# 自动完成流程
auto_complete() {
local submission_id="$1"
log_info "开始自动完成流程..."
# 等待完成
if wait_for_completion "$submission_id"; then
# 装订公证
if staple_notarization; then
# 验证结果
verify_result
log_success "整个流程完成!"
else
log_error "装订失败"
return 1
fi
else
log_error "公证失败"
return 1
fi
}
# 手动完成流程
manual_complete() {
local submission_id="$1"
log_info "手动完成流程..."
# 检查当前状态
local status=$(check_status "$submission_id")
log_info "当前状态: $status"
case "$status" in
"Accepted")
log_success "公证已完成,开始装订..."
staple_notarization
verify_result
;;
"In Progress")
log_warning "公证仍在进行中,请稍后再试"
;;
"Invalid")
log_error "公证失败,请查看日志"
show_log "$submission_id"
;;
*)
log_warning "未知状态: $status"
;;
esac
}
# 显示帮助
show_help() {
echo "用法: $0 [选项] <submission_id>"
echo ""
echo "选项:"
echo " auto - 自动等待并完成"
echo " manual - 手动检查并完成"
echo " status - 仅检查状态"
echo " log - 查看日志"
echo " staple - 仅装订公证"
echo " verify - 验证结果"
echo ""
echo "示例:"
echo " $0 auto b7414dba-adb5-4e0a-9535-ae51815736c4"
echo " $0 manual b7414dba-adb5-4e0a-9535-ae51815736c4"
echo " $0 status b7414dba-adb5-4e0a-9535-ae51815736c4"
}
# 主函数
main() {
local action="${1:-help}"
local submission_id="$2"
if [ -z "$submission_id" ] && [ "$action" != "help" ]; then
log_error "请提供提交 ID"
show_help
exit 1
fi
case "$action" in
"auto")
auto_complete "$submission_id"
;;
"manual")
manual_complete "$submission_id"
;;
"status")
check_status "$submission_id"
;;
"log")
show_log "$submission_id"
;;
"staple")
staple_notarization
;;
"verify")
verify_result
;;
"help"|*)
show_help
;;
esac
}
# 运行主函数
main "$@"

View File

@ -1,149 +0,0 @@
#!/bin/bash
# BearVPN macOS DMG 打包脚本
# 作者: AI Assistant
# 日期: $(date)
set -e
# 配置变量
APP_NAME="BearVPN"
APP_VERSION="1.0.0"
DMG_NAME="${APP_NAME}-${APP_VERSION}-macOS"
APP_PATH="build/macos/Build/Products/Release/${APP_NAME}.app"
DMG_PATH="build/macos/Build/Products/Release/${DMG_NAME}.dmg"
TEMP_DMG_PATH="build/macos/Build/Products/Release/temp_${DMG_NAME}.dmg"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查应用是否存在
check_app() {
log_info "检查应用文件..."
if [ ! -d "$APP_PATH" ]; then
log_error "应用文件不存在: $APP_PATH"
log_info "请先运行: flutter build macos --release"
exit 1
fi
log_success "应用文件检查通过"
}
# 清理旧的 DMG 文件
cleanup() {
log_info "清理旧的 DMG 文件..."
rm -f "$DMG_PATH" "$TEMP_DMG_PATH"
log_success "清理完成"
}
# 创建 DMG
create_dmg() {
log_info "开始创建 DMG 文件..."
# 使用 create-dmg 创建 DMG
create-dmg \
--volname "$APP_NAME" \
--volicon "macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--icon "$APP_NAME.app" 175 190 \
--hide-extension "$APP_NAME.app" \
--app-drop-link 425 190 \
--no-internet-enable \
"$DMG_PATH" \
"$APP_PATH"
if [ $? -eq 0 ]; then
log_success "DMG 文件创建成功: $DMG_PATH"
else
log_error "DMG 文件创建失败"
exit 1
fi
}
# 验证 DMG
verify_dmg() {
log_info "验证 DMG 文件..."
# 检查文件大小
DMG_SIZE=$(du -h "$DMG_PATH" | cut -f1)
log_info "DMG 文件大小: $DMG_SIZE"
# 检查文件类型
FILE_TYPE=$(file "$DMG_PATH")
log_info "文件类型: $FILE_TYPE"
# 尝试挂载 DMG 验证
log_info "验证 DMG 内容..."
MOUNT_POINT=$(hdiutil attach "$DMG_PATH" -nobrowse | grep -E '^/dev/' | sed 1q | awk '{print $3}')
if [ -n "$MOUNT_POINT" ]; then
log_success "DMG 挂载成功: $MOUNT_POINT"
# 检查应用是否在 DMG 中
if [ -d "$MOUNT_POINT/$APP_NAME.app" ]; then
log_success "应用文件在 DMG 中验证成功"
else
log_error "应用文件在 DMG 中未找到"
fi
# 卸载 DMG
hdiutil detach "$MOUNT_POINT" -quiet
log_info "DMG 已卸载"
else
log_error "DMG 挂载失败"
exit 1
fi
}
# 显示结果
show_result() {
log_success "=========================================="
log_success "DMG 打包完成!"
log_success "=========================================="
log_info "应用名称: $APP_NAME"
log_info "版本: $APP_VERSION"
log_info "DMG 文件: $DMG_PATH"
log_info "文件大小: $(du -h "$DMG_PATH" | cut -f1)"
log_success "=========================================="
log_info "你可以将 DMG 文件分发给用户安装"
log_info "用户双击 DMG 文件,然后将应用拖拽到 Applications 文件夹即可"
}
# 主函数
main() {
log_info "开始 BearVPN macOS DMG 打包流程..."
log_info "=========================================="
check_app
cleanup
create_dmg
verify_dmg
show_result
log_success "所有操作完成!"
}
# 运行主函数
main "$@"

View File

@ -1,179 +0,0 @@
#!/bin/bash
# 创建包含安装脚本的 DMG
# 此脚本会创建一个包含 BearVPN.app 和安装脚本的 DMG
set -e
# 配置变量
APP_NAME="BearVPN"
APP_VERSION="1.0.0"
DMG_NAME="${APP_NAME}-${APP_VERSION}-macOS-Signed"
APP_PATH="build/macos/Build/Products/Release/${APP_NAME}.app"
DMG_PATH="build/macos/Build/Products/Release/${DMG_NAME}.dmg"
TEMP_DIR="/tmp/BearVPN_DMG"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 清理临时目录
cleanup_temp() {
log_info "清理临时目录..."
rm -rf "$TEMP_DIR"
mkdir -p "$TEMP_DIR"
}
# 准备 DMG 内容
prepare_dmg_content() {
log_info "准备 DMG 内容..."
# 复制应用
cp -R "$APP_PATH" "$TEMP_DIR/"
# 复制安装脚本
cp "install_bearvpn.sh" "$TEMP_DIR/"
chmod +x "$TEMP_DIR/install_bearvpn.sh"
# 创建 README 文件
cat > "$TEMP_DIR/README.txt" << 'EOF'
🐻 BearVPN 安装说明
==================
欢迎使用 BearVPN
📱 安装方法:
1. 双击 "BearVPN.app" 直接安装
2. 或运行 "install_bearvpn.sh" 脚本进行自动安装
⚠️ 如果应用无法打开:
1. 右键点击 BearVPN.app → "打开"
2. 在系统偏好设置 → 安全性与隐私 → 允许从以下位置下载的应用 → 选择 "任何来源"
3. 或运行sudo spctl --master-disable
🔧 技术支持:
如有问题,请联系技术支持团队
感谢使用 BearVPN
EOF
# 创建 Applications 链接
ln -s /Applications "$TEMP_DIR/Applications"
log_success "DMG 内容准备完成"
}
# 创建 DMG
create_dmg() {
log_info "开始创建 DMG..."
# 删除旧的 DMG
rm -f "$DMG_PATH"
# 使用 create-dmg 创建 DMG
create-dmg \
--volname "$APP_NAME" \
--volicon "macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png" \
--window-pos 200 120 \
--window-size 700 500 \
--icon-size 100 \
--icon "$APP_NAME.app" 100 200 \
--icon "install_bearvpn.sh" 300 200 \
--icon "README.txt" 500 200 \
--icon "Applications" 100 350 \
--hide-extension "$APP_NAME.app" \
--no-internet-enable \
"$DMG_PATH" \
"$TEMP_DIR"
if [ $? -eq 0 ]; then
log_success "DMG 文件创建成功: $DMG_PATH"
else
log_error "DMG 文件创建失败"
exit 1
fi
}
# 签名 DMG
sign_dmg() {
log_info "开始签名 DMG 文件..."
DEVELOPER_ID="Developer ID Application: Civil Rights Corps (3UR892FAP3)"
# 签名 DMG
codesign --force --sign "$DEVELOPER_ID" "$DMG_PATH"
if [ $? -eq 0 ]; then
log_success "DMG 签名成功"
else
log_error "DMG 签名失败"
exit 1
fi
# 验证 DMG 签名
log_info "验证 DMG 签名..."
codesign --verify --verbose "$DMG_PATH"
if [ $? -eq 0 ]; then
log_success "DMG 签名验证通过"
else
log_error "DMG 签名验证失败"
exit 1
fi
}
# 显示结果
show_result() {
log_success "=========================================="
log_success "包含安装脚本的 DMG 创建完成!"
log_success "=========================================="
log_info "DMG 路径: $DMG_PATH"
log_info "DMG 大小: $(du -h "$DMG_PATH" | cut -f1)"
log_info "包含内容:"
log_info " - BearVPN.app (应用)"
log_info " - install_bearvpn.sh (安装脚本)"
log_info " - README.txt (说明文档)"
log_info " - Applications (快捷方式)"
log_success "=========================================="
log_info "用户可以通过以下方式安装:"
log_info "1. 直接拖拽 BearVPN.app 到 Applications"
log_info "2. 运行 install_bearvpn.sh 脚本"
log_success "=========================================="
}
# 主函数
main() {
log_info "开始创建包含安装脚本的 DMG..."
log_info "=========================================="
cleanup_temp
prepare_dmg_content
create_dmg
sign_dmg
show_result
log_success "所有操作完成!"
}
# 运行主函数
main "$@"

View File

@ -1,174 +0,0 @@
#!/bin/bash
# BearVPN 连接调试脚本
# 用于调试 macOS 平台下的节点连接超时问题
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查网络连接
check_network() {
log_info "检查网络连接..."
# 检查基本网络连接
if ping -c 3 8.8.8.8 > /dev/null 2>&1; then
log_success "基本网络连接正常"
else
log_error "基本网络连接失败"
return 1
fi
# 检查 DNS 解析
if nslookup google.com > /dev/null 2>&1; then
log_success "DNS 解析正常"
else
log_error "DNS 解析失败"
return 1
fi
}
# 检查代理设置
check_proxy() {
log_info "检查系统代理设置..."
# 检查 HTTP 代理
if [ -n "$http_proxy" ] || [ -n "$HTTP_PROXY" ]; then
log_warning "检测到 HTTP 代理设置: $http_proxy$HTTP_PROXY"
else
log_info "未检测到 HTTP 代理设置"
fi
# 检查 HTTPS 代理
if [ -n "$https_proxy" ] || [ -n "$HTTPS_PROXY" ]; then
log_warning "检测到 HTTPS 代理设置: $https_proxy$HTTPS_PROXY"
else
log_info "未检测到 HTTPS 代理设置"
fi
}
# 检查防火墙
check_firewall() {
log_info "检查防火墙状态..."
# 检查 macOS 防火墙
local firewall_status=$(sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate 2>/dev/null || echo "unknown")
log_info "防火墙状态: $firewall_status"
if [ "$firewall_status" = "enabled" ]; then
log_warning "防火墙已启用,可能影响连接"
fi
}
# 测试常见端口连接
test_ports() {
log_info "测试常见端口连接..."
local ports=(80 443 8080 8443)
local hosts=("google.com" "cloudflare.com" "github.com")
for host in "${hosts[@]}"; do
for port in "${ports[@]}"; do
if timeout 5 bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null; then
log_success "$host:$port 连接正常"
else
log_warning "$host:$port 连接失败或超时"
fi
done
done
}
# 检查 libcore 库
check_libcore() {
log_info "检查 libcore 库..."
if [ -f "libcore/bin/libcore.dylib" ]; then
log_success "找到 libcore.dylib"
# 检查库的架构
local arch=$(file libcore/bin/libcore.dylib)
log_info "库架构: $arch"
# 检查库的依赖
log_info "库依赖:"
otool -L libcore/bin/libcore.dylib | head -10
else
log_error "未找到 libcore.dylib"
return 1
fi
}
# 检查应用配置
check_app_config() {
log_info "检查应用配置..."
# 检查当前域名配置
if [ -f "lib/app/common/app_config.dart" ]; then
log_info "检查域名配置..."
grep -n "kr_baseDomains\|kr_currentDomain" lib/app/common/app_config.dart | head -5
fi
# 检查超时配置
log_info "检查超时配置..."
grep -n "kr_domainTimeout\|kr_totalTimeout" lib/app/common/app_config.dart | head -5
}
# 监控应用日志
monitor_logs() {
log_info "开始监控应用日志..."
log_info "请运行应用并尝试连接节点,然后按 Ctrl+C 停止监控"
# 监控 Flutter 日志
flutter logs --device-id=macos 2>/dev/null | grep -E "(ERROR|WARNING|INFO|超时|连接|节点|SingBox)" || true
}
# 主函数
main() {
log_info "开始 BearVPN 连接调试..."
log_info "=========================================="
check_network
check_proxy
check_firewall
test_ports
check_libcore
check_app_config
log_info "=========================================="
log_info "基础检查完成"
log_info "=========================================="
# 询问是否监控日志
read -p "是否开始监控应用日志?(y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
monitor_logs
fi
log_success "调试完成"
}
# 运行主函数
main "$@"

View File

@ -1,35 +0,0 @@
@echo off
REM Fix NuGet installation using Chocolatey
echo Installing NuGet via Chocolatey...
REM Check if Chocolatey is available
where choco >nul 2>nul
if %errorlevel% neq 0 (
echo Chocolatey not found, installing Chocolatey first...
powershell -Command "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))"
)
echo Installing NuGet via Chocolatey...
choco install nuget.commandline -y
if %errorlevel% equ 0 (
echo SUCCESS: NuGet installed via Chocolatey
echo Updating PATH...
set PATH=C:\ProgramData\chocolatey\bin;%PATH%
setx PATH "C:\ProgramData\chocolatey\bin;%PATH%"
echo Verifying installation...
nuget help | findstr "NuGet"
if %errorlevel% equ 0 (
echo NuGet is working correctly!
) else (
echo WARNING: NuGet installed but not accessible
)
) else (
echo ERROR: NuGet installation failed
exit /b 1
)
pause

View File

@ -1,67 +0,0 @@
# NuGet 安装脚本 - 解决 SSL 问题
Write-Host "=== 安装 NuGet ===" -ForegroundColor Green
# 设置 TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# 检查是否已安装
$nugetExists = Get-Command nuget -ErrorAction SilentlyContinue
if ($nugetExists) {
Write-Host "NuGet 已安装: $($nugetExists.Source)" -ForegroundColor Green
exit 0
}
# 下载 NuGet
Write-Host "下载 NuGet CLI..." -ForegroundColor Yellow
$downloadUrls = @(
"https://dist.nuget.org/win-x86-commandline/latest/nuget.exe",
"https://dist.nuget.org/win-x86-commandline/v6.7.0/nuget.exe",
"http://dist.nuget.org/win-x86-commandline/v6.7.0/nuget.exe"
)
$downloaded = $false
foreach ($url in $downloadUrls) {
try {
Write-Host "尝试下载: $url"
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($url, "C:\nuget.exe")
$downloaded = $true
Write-Host "下载成功!" -ForegroundColor Green
break
} catch {
Write-Host "下载失败: $($_.Exception.Message)" -ForegroundColor Red
continue
}
}
if (-not $downloaded) {
Write-Host "所有下载都失败了,尝试使用 Chocolatey..." -ForegroundColor Yellow
try {
choco install nuget.commandline -y
if (Get-Command nuget -ErrorAction SilentlyContinue) {
Write-Host "通过 Chocolatey 安装成功!" -ForegroundColor Green
exit 0
}
} catch {
Write-Host "Chocolatey 安装也失败了: $($_.Exception.Message)" -ForegroundColor Red
}
Write-Host "NuGet 安装失败,但继续构建..." -ForegroundColor Yellow
exit 0
}
# 验证安装
if (Test-Path "C:\nuget.exe") {
$env:PATH = "C:\;$env:PATH"
Write-Host "NuGet 安装完成" -ForegroundColor Green
# 测试
try {
$version = & "C:\nuget.exe" help | Select-String -Pattern "NuGet Version" | Select-Object -First 1
Write-Host "版本信息: $version" -ForegroundColor Green
} catch {
Write-Host "NuGet 可用,但版本检查失败" -ForegroundColor Yellow
}
} else {
Write-Host "NuGet 文件不存在" -ForegroundColor Red
}

View File

@ -1,64 +0,0 @@
# Windows 构建修复脚本
# 以管理员身份运行
Write-Host "=== Windows Flutter 构建修复 ===" -ForegroundColor Green
# 1. 安装 NuGet
Write-Host "`n1. 安装 NuGet..." -ForegroundColor Yellow
$nugetPath = "C:\nuget.exe"
if (-not (Test-Path $nugetPath)) {
try {
Write-Host "下载 NuGet..."
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile $nugetPath
$env:PATH = "C:\;$env:PATH"
Write-Host "NuGet 安装成功" -ForegroundColor Green
} catch {
Write-Host "NuGet 下载失败: $_" -ForegroundColor Red
exit 1
}
} else {
Write-Host "NuGet 已存在" -ForegroundColor Green
}
# 2. 启用长路径支持
Write-Host "`n2. 启用长路径支持..." -ForegroundColor Yellow
try {
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -Type DWORD -Force
Write-Host "长路径支持已启用" -ForegroundColor Green
} catch {
Write-Host "长路径设置失败: $_" -ForegroundColor Red
}
# 3. 清理构建缓存
Write-Host "`n3. 清理构建缓存..." -ForegroundColor Yellow
if (Test-Path "build") {
Remove-Item -Path "build" -Recurse -Force
Write-Host "Build 目录已清理" -ForegroundColor Green
}
if (Test-Path "windows") {
Remove-Item -Path "windows" -Recurse -Force
Write-Host "Windows 目录已清理" -ForegroundColor Green
}
# 4. 重新创建 Windows 项目
Write-Host "`n4. 重新创建 Windows 项目..." -ForegroundColor Yellow
flutter create --platforms=windows .
# 5. 获取依赖
Write-Host "`n5. 获取依赖..." -ForegroundColor Yellow
flutter pub get
# 6. 构建 Debug 版本
Write-Host "`n6. 构建 Debug 版本..." -ForegroundColor Yellow
flutter build windows
if ($LASTEXITCODE -eq 0) {
Write-Host "`n=== 构建成功! ===" -ForegroundColor Green
Write-Host "输出目录: build\windows\runner\Debug\" -ForegroundColor Cyan
} else {
Write-Host "`n=== 构建失败 ===" -ForegroundColor Red
Write-Host "请检查错误信息并尝试手动修复" -ForegroundColor Red
}
Write-Host "`n修复完成!" -ForegroundColor Green

View File

@ -1,172 +0,0 @@
#!/bin/bash
# 获取 Apple Developer Team ID 的脚本
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Apple ID 和密码
check_credentials() {
if [ -z "$APPLE_ID" ] || [ -z "$APPLE_PASSWORD" ]; then
log_error "请先设置 APPLE_ID 和 APPLE_PASSWORD 环境变量"
log_info "运行: export APPLE_ID='your-apple-id@example.com'"
log_info "运行: export APPLE_PASSWORD='your-app-password'"
exit 1
fi
log_info "使用 Apple ID: $APPLE_ID"
}
# 方法1: 通过 xcrun altool 获取
get_team_id_altool() {
log_info "尝试通过 xcrun altool 获取 Team ID..."
local output
if output=$(xcrun altool --list-providers -u "$APPLE_ID" -p "$APPLE_PASSWORD" 2>&1); then
local team_id=$(echo "$output" | grep -o 'Team ID: [A-Z0-9]*' | head -1 | cut -d' ' -f3)
if [ -n "$team_id" ]; then
echo "$team_id"
return 0
fi
fi
return 1
}
# 方法2: 通过 xcodebuild 获取
get_team_id_xcodebuild() {
log_info "尝试通过 xcodebuild 获取 Team ID..."
# 检查是否有 Xcode 项目
if [ -f "ios/Runner.xcodeproj/project.pbxproj" ]; then
local team_id=$(grep -o 'DEVELOPMENT_TEAM = [A-Z0-9]*' ios/Runner.xcodeproj/project.pbxproj | head -1 | cut -d' ' -f3)
if [ -n "$team_id" ]; then
echo "$team_id"
return 0
fi
fi
return 1
}
# 方法3: 通过开发者证书获取
get_team_id_certificates() {
log_info "尝试通过开发者证书获取 Team ID..."
local identities=$(security find-identity -v -p codesigning 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$identities" ]; then
local team_id=$(echo "$identities" | grep -o '([A-Z0-9]*)' | head -1 | tr -d '()')
if [ -n "$team_id" ]; then
echo "$team_id"
return 0
fi
fi
return 1
}
# 方法4: 手动输入
get_team_id_manual() {
log_warning "无法自动获取 Team ID"
log_info "请手动输入您的 Team ID"
log_info "1. 登录 https://developer.apple.com"
log_info "2. 进入 'Account' -> 'Membership'"
log_info "3. 查看 'Team ID' 字段"
echo ""
read -p "请输入您的 Team ID: " team_id
if [ -n "$team_id" ]; then
echo "$team_id"
return 0
else
return 1
fi
}
# 更新配置文件
update_config() {
local team_id=$1
if [ -z "$team_id" ]; then
log_error "Team ID 为空"
return 1
fi
log_info "更新 ios_signing_config.sh 文件..."
# 备份原文件
cp ios_signing_config.sh ios_signing_config.sh.backup
# 更新 Team ID
sed -i '' "s/export TEAM_ID=\"YOUR_TEAM_ID\"/export TEAM_ID=\"$team_id\"/" ios_signing_config.sh
# 更新签名身份
sed -i '' "s/export SIGNING_IDENTITY=\"iPhone Developer: Your Name (YOUR_TEAM_ID)\"/export SIGNING_IDENTITY=\"iPhone Developer: Your Name ($team_id)\"/" ios_signing_config.sh
sed -i '' "s/export DISTRIBUTION_IDENTITY=\"iPhone Distribution: Your Name (YOUR_TEAM_ID)\"/export DISTRIBUTION_IDENTITY=\"iPhone Distribution: Your Name ($team_id)\"/" ios_signing_config.sh
log_success "配置文件已更新"
log_info "Team ID: $team_id"
}
# 主函数
main() {
log_info "开始获取 Apple Developer Team ID..."
log_info "=========================================="
check_credentials
local team_id=""
# 尝试各种方法获取 Team ID
if team_id=$(get_team_id_altool); then
log_success "通过 xcrun altool 获取到 Team ID: $team_id"
elif team_id=$(get_team_id_xcodebuild); then
log_success "通过 xcodebuild 获取到 Team ID: $team_id"
elif team_id=$(get_team_id_certificates); then
log_success "通过开发者证书获取到 Team ID: $team_id"
else
team_id=$(get_team_id_manual)
if [ $? -eq 0 ]; then
log_success "手动输入 Team ID: $team_id"
else
log_error "无法获取 Team ID"
exit 1
fi
fi
# 更新配置文件
update_config "$team_id"
log_success "=========================================="
log_success "Team ID 获取完成!"
log_success "=========================================="
log_info "现在可以运行: source ios_signing_config.sh"
log_info "然后运行: ./build_ios_dmg.sh"
log_success "=========================================="
}
# 运行主函数
main "$@"

View File

@ -1,68 +0,0 @@
#!/bin/bash
# BearVPN 安装脚本
# 此脚本帮助用户在 macOS 上安全安装 BearVPN
echo "🐻 BearVPN 安装助手"
echo "===================="
echo ""
# 检查是否在正确的目录
if [ ! -f "BearVPN.app/Contents/Info.plist" ]; then
echo "❌ 错误:请在包含 BearVPN.app 的目录中运行此脚本"
exit 1
fi
echo "📱 正在检查应用..."
APP_PATH="./BearVPN.app"
# 检查应用是否存在
if [ ! -d "$APP_PATH" ]; then
echo "❌ 错误:找不到 BearVPN.app"
exit 1
fi
echo "✅ 找到 BearVPN.app"
# 移除隔离属性
echo "🔓 正在移除隔离属性..."
sudo xattr -rd com.apple.quarantine "$APP_PATH"
if [ $? -eq 0 ]; then
echo "✅ 隔离属性已移除"
else
echo "⚠️ 警告:无法移除隔离属性,请手动操作"
fi
# 检查签名状态
echo "🔍 检查应用签名状态..."
codesign -dv "$APP_PATH" 2>&1 | grep -q "Developer ID"
if [ $? -eq 0 ]; then
echo "✅ 应用已使用开发者证书签名"
else
echo "⚠️ 应用未使用开发者证书签名"
fi
# 移动到应用程序文件夹
echo "📁 正在安装到应用程序文件夹..."
if [ -d "/Applications/BearVPN.app" ]; then
echo "⚠️ 发现已存在的 BearVPN正在备份..."
mv "/Applications/BearVPN.app" "/Applications/BearVPN.app.backup.$(date +%Y%m%d_%H%M%S)"
fi
cp -R "$APP_PATH" "/Applications/"
if [ $? -eq 0 ]; then
echo "✅ BearVPN 已安装到 /Applications/"
else
echo "❌ 安装失败"
exit 1
fi
echo ""
echo "🎉 安装完成!"
echo ""
echo "📋 如果应用无法打开,请尝试以下步骤:"
echo "1. 右键点击 BearVPN.app → '打开'"
echo "2. 在系统偏好设置 → 安全性与隐私 → 允许从以下位置下载的应用 → 选择 '任何来源'"
echo "3. 或者运行sudo spctl --master-disable"
echo ""
echo "🔧 如需帮助,请联系技术支持"

View File

@ -1,64 +0,0 @@
@echo off
:: This script checks for and installs all necessary tools for building and packaging the Flutter application on Windows.
:: 1. Check for Administrator Privileges
net session >nul 2>&1
if %errorLevel% == 0 (
echo Administrator privileges detected. Continuing...
) else (
echo Requesting Administrator privileges to install tools...
powershell -Command "Start-Process cmd.exe -ArgumentList '/c %~s0' -Verb RunAs" >nul 2>&1
exit /b
)
:: 2. Check for and Install Chocolatey
echo.
echo === Checking for Chocolatey ===
where choco >nul 2>&1
if %errorlevel% equ 0 (
echo Chocolatey is already installed.
) else (
echo Chocolatey not found. Installing now...
powershell -NoProfile -ExecutionPolicy Bypass -Command "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))"
if %errorlevel% neq 0 (
echo ERROR: Failed to install Chocolatey. Please install it manually from https://chocolatey.org
pause
exit /b 1
)
echo Chocolatey installed successfully.
:: Add Chocolatey to the PATH for the current session
set "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
)
:: 3. Install Required Tools via Chocolatey
echo.
echo === Installing Build Tools (7-Zip and Enigma Virtual Box) ===
:: Install 7-Zip
echo Installing 7-Zip...
choco install 7zip -y
if %errorlevel% neq 0 (
echo ERROR: Failed to install 7-Zip.
pause
exit /b 1
)
echo 7-Zip installed successfully.
:: Install Enigma Virtual Box
echo Installing Enigma Virtual Box...
choco install enigma-virtual-box -y
if %errorlevel% neq 0 (
echo ERROR: Failed to install Enigma Virtual Box.
pause
exit /b 1
)
echo Enigma Virtual Box installed successfully.
echo.
echo =======================================================
echo All required build tools have been installed.
echo You can now use 'package_windows_single_exe.ps1' to build your single-file executable.
echo =======================================================
echo.
pause

View File

@ -1,44 +0,0 @@
@echo off
REM Simple Flutter installer for Windows Gitea Runner
echo Installing Flutter for Windows...
REM Create flutter directory
mkdir C:\flutter 2>nul
REM Download Flutter stable version
echo Downloading Flutter...
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_3.24.5-stable.zip', 'C:\flutter.zip')"
if %errorlevel% neq 0 (
echo Download failed, trying alternative...
powershell -Command "Invoke-WebRequest -Uri 'https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_3.24.5-stable.zip' -OutFile 'C:\flutter.zip'"
)
REM Extract Flutter
echo Extracting Flutter...
powershell -Command "Expand-Archive -Path 'C:\flutter.zip' -DestinationPath 'C:\' -Force"
REM Set PATH
echo Setting PATH...
set PATH=C:\flutter\bin;%PATH%
setx PATH "C:\flutter\bin;%PATH%"
REM Clean up
del C:\flutter.zip
REM Verify installation
echo Verifying Flutter installation...
C:\flutter\bin\flutter --version
if %errorlevel% equ 0 (
echo SUCCESS: Flutter installed successfully
echo Running flutter doctor...
C:\flutter\bin\flutter doctor
) else (
echo ERROR: Flutter installation failed
exit /b 1
)
echo Flutter installation complete!
pause

View File

@ -1,39 +0,0 @@
@echo off
REM Simple NuGet installer for Windows
echo Installing NuGet...
REM Check if NuGet exists
where nuget >nul 2>nul
if %errorlevel% == 0 (
echo NuGet already installed
nuget help | findstr "NuGet"
pause
exit /b 0
)
REM Download NuGet using PowerShell
echo Downloading NuGet CLI...
powershell -Command "(New-Object Net.WebClient).DownloadFile('http://dist.nuget.org/win-x86-commandline/v6.7.0/nuget.exe', 'C:\nuget.exe')"
if %errorlevel% neq 0 (
echo Download failed, trying alternative...
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://dist.nuget.org/win-x86-commandline/v6.7.0/nuget.exe', 'C:\nuget.exe')"
)
REM Add to PATH
set PATH=C:\;%PATH%
setx PATH "C:\;%PATH%"
REM Verify installation
echo Verifying NuGet installation...
C:\nuget.exe help | findstr "NuGet"
if %errorlevel% equ 0 (
echo SUCCESS: NuGet installed successfully
) else (
echo ERROR: NuGet installation failed
exit /b 1
)
pause

View File

@ -1,46 +0,0 @@
#!/bin/bash
# iOS 签名配置脚本
# 请根据您的开发者账户信息修改以下配置
# Apple Developer 账户信息
export APPLE_ID="kieran@newlifeephrata.us"
export APPLE_PASSWORD="Asd112211@"
export TEAM_ID="3UR892FAP3"
# 应用信息
export APP_NAME="BearVPN"
export BUNDLE_ID="app.baer.com"
export VERSION="1.0.0"
export BUILD_NUMBER="1"
# 代码签名身份(运行 security find-identity -v -p codesigning 查看可用身份)
export SIGNING_IDENTITY="Mac Developer: Kieran Parker (R36D2VJYBT)"
# 分发签名身份(用于 App Store 或 Ad Hoc 分发)
export DISTRIBUTION_IDENTITY="Developer ID Application: Kieran Parker (3UR892FAP3)"
# 配置文件名称(需要在 Apple Developer Portal 中创建)
export PROVISIONING_PROFILE_NAME="BearVPN Development Profile"
export DISTRIBUTION_PROFILE_NAME="BearVPN Distribution Profile"
# 输出路径
export OUTPUT_DIR="build/ios"
export IPA_PATH="${OUTPUT_DIR}/BearVPN-${VERSION}.ipa"
export DMG_PATH="${OUTPUT_DIR}/BearVPN-${VERSION}-iOS.dmg"
echo "🔧 iOS 签名配置已加载"
echo "📧 Apple ID: $APPLE_ID"
echo "🏢 Team ID: $TEAM_ID"
echo "📱 Bundle ID: $BUNDLE_ID"
echo "🔐 签名身份: $SIGNING_IDENTITY"
echo ""
echo "💡 使用方法:"
echo "1. 修改此文件中的配置信息"
echo "2. 运行: source ios_signing_config.sh"
echo "3. 运行: ./build_ios.sh"
echo ""
echo "⚠️ 请确保:"
echo "- 已在 Apple Developer Portal 中创建了 App ID"
echo "- 已下载并安装了 Provisioning Profile"
echo "- 已安装了开发者证书"

View File

@ -16,7 +16,6 @@ import '../../../localization/app_translations.dart';
import '../../../localization/kr_language_utils.dart'; import '../../../localization/kr_language_utils.dart';
import '../../../model/business/kr_group_outbound_list.dart'; import '../../../model/business/kr_group_outbound_list.dart';
import '../../../model/business/kr_outbound_item.dart'; import '../../../model/business/kr_outbound_item.dart';
import '../../../services/kr_announcement_service.dart';
import '../../../utils/kr_event_bus.dart'; import '../../../utils/kr_event_bus.dart';
import '../../../utils/kr_update_util.dart'; import '../../../utils/kr_update_util.dart';
import '../../../widgets/dialogs/kr_dialog.dart'; import '../../../widgets/dialogs/kr_dialog.dart';
@ -595,7 +594,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
kr_currentViewStatus.value = KRHomeViewsStatus.kr_loggedIn; kr_currentViewStatus.value = KRHomeViewsStatus.kr_loggedIn;
KRLogUtil.kr_i('登录状态变化:设置为已登录', tag: 'HomeController'); KRLogUtil.kr_i('登录状态变化:设置为已登录', tag: 'HomeController');
KRAnnouncementService().kr_checkAnnouncement();
// splash // splash
KRLogUtil.kr_i('订阅服务已在启动页初始化,跳过重复初始化', tag: 'HomeController'); KRLogUtil.kr_i('订阅服务已在启动页初始化,跳过重复初始化', tag: 'HomeController');

View File

@ -1,153 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../model/response/kr_message_list.dart';
import 'api_service/kr_api.user.dart';
import '../utils/kr_common_util.dart';
import '../widgets/dialogs/kr_dialog.dart';
import '../localization/app_translations.dart';
class KRAnnouncementService {
static final KRAnnouncementService _instance = KRAnnouncementService._internal();
final KRUserApi _kr_userApi = KRUserApi();
bool _kr_hasShownAnnouncement = false;
factory KRAnnouncementService() {
return _instance;
}
KRAnnouncementService._internal();
// 退
void kr_reset() {
_kr_hasShownAnnouncement = false;
}
//
Future<void> kr_checkAnnouncement() async {
if (_kr_hasShownAnnouncement) {
return;
}
final either = await _kr_userApi.kr_getMessageList(1, 1, popup: true);
either.fold(
(error) {
KRCommonUtil.kr_showToast(error.msg);
},
(list) {
if (list.announcements.isNotEmpty) {
//
final sortedAnnouncements = list.announcements;
final latestAnnouncement = sortedAnnouncements.first;
//
if (latestAnnouncement.popup) {
_kr_hasShownAnnouncement = true;
KRDialog.show(
title: latestAnnouncement.title,
message: null,
confirmText: AppTranslations.kr_dialog.kr_iKnow,
onConfirm: () {
// Navigator.of(Get.context!).pop();
},
customMessageWidget: _kr_buildMessageContent(latestAnnouncement.content, Get.context!),
);
}
}
},
);
}
//
Widget _kr_buildMessageContent(String content, BuildContext context) {
//
final bool kr_isHtml = content.contains('<') && content.contains('>');
final bool kr_isMarkdown = content.contains('**') ||
content.contains('*') ||
content.contains('#') ||
content.contains('- ') ||
content.contains('[');
final textStyle = TextStyle(
fontSize: 14.sp,
color: Theme.of(context).textTheme.bodySmall?.color,
fontFamily: 'AlibabaPuHuiTi-Regular',
height: 1.4,
);
if (kr_isHtml) {
// 使 flutter_html HTML
return Html(
data: content,
style: {
'body': Style(
margin: Margins.all(0),
padding: HtmlPaddings.all(0),
fontSize: FontSize(14.sp),
color: Theme.of(context).textTheme.bodySmall?.color,
fontFamily: 'AlibabaPuHuiTi-Regular',
lineHeight: LineHeight(1.4),
),
'p': Style(
margin: Margins.only(bottom: 8.h),
),
'b': Style(
fontWeight: FontWeight.bold,
),
'i': Style(
fontStyle: FontStyle.italic,
),
'a': Style(
color: Colors.blue,
textDecoration: TextDecoration.underline,
),
},
shrinkWrap: true,
);
} else if (kr_isMarkdown) {
// 使 flutter_markdown Markdown
return MarkdownBody(
data: content,
styleSheet: MarkdownStyleSheet(
p: TextStyle(
fontSize: 14.sp,
color: Theme.of(context).textTheme.bodySmall?.color,
fontFamily: 'AlibabaPuHuiTi-Regular',
height: 1.4,
),
strong: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.bold,
color: Theme.of(context).textTheme.bodySmall?.color,
fontFamily: 'AlibabaPuHuiTi-Regular',
height: 1.4,
),
em: TextStyle(
fontSize: 14.sp,
fontStyle: FontStyle.italic,
color: Theme.of(context).textTheme.bodySmall?.color,
fontFamily: 'AlibabaPuHuiTi-Regular',
height: 1.4,
),
a: TextStyle(
fontSize: 14.sp,
color: Colors.blue,
decoration: TextDecoration.underline,
fontFamily: 'AlibabaPuHuiTi-Regular',
height: 1.4,
),
),
);
} else {
//
return Text(
content,
style: textStyle,
);
}
}
}

View File

@ -1,5 +0,0 @@
create-dmg "HiFastVPN.app" \
--overwrite \
--dmg-title="HiFastVPN" \
--app-drop-link \
--dmg "HiFastVPN.dmg"

View File

@ -1,25 +0,0 @@
#!/bin/bash
# macOS 签名配置脚本
# 请根据您的开发者账户信息修改以下配置
# Apple Developer 账户信息
export APPLE_ID="kieran@newlifeephrata.us"
export APPLE_PASSWORD="gtvp-izmw-cubf-yxfe"
export TEAM_ID="3UR892FAP3"
# 代码签名身份(运行 security find-identity -v -p codesigning 查看可用身份)
export SIGNING_IDENTITY="Developer ID Application: Civil Rights Corps (3UR892FAP3)"
# 安装包签名身份
export INSTALLER_IDENTITY="Developer ID Installer: Civil Rights Corps (3UR892FAP3)"
echo "🔧 macOS 签名配置已加载"
echo "📧 Apple ID: $APPLE_ID"
echo "🏢 Team ID: $TEAM_ID"
echo "🔐 签名身份: $SIGNING_IDENTITY"
echo ""
echo "💡 使用方法:"
echo "1. 修改此文件中的配置信息"
echo "2. 运行: source macos_signing_config.sh"
echo "3. 运行: ./build_macos_dmg.sh"

View File

@ -1,169 +0,0 @@
#!/bin/bash
# 手动公证脚本
# 作者: AI Assistant
set -e
# 配置变量
APP_NAME="BearVPN"
APP_VERSION="1.0.0"
APP_PATH="build/macos/Build/Products/Release/${APP_NAME}.app"
DMG_PATH="build/macos/Build/Products/Release/${APP_NAME}-${APP_VERSION}-macOS-Signed.dmg"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查文件
check_files() {
if [ ! -d "$APP_PATH" ]; then
log_error "应用文件不存在: $APP_PATH"
exit 1
fi
if [ ! -f "$DMG_PATH" ]; then
log_error "DMG 文件不存在: $DMG_PATH"
exit 1
fi
log_success "找到应用和 DMG 文件"
}
# 创建 ZIP 文件
create_zip() {
log_info "创建 ZIP 文件用于公证..."
ZIP_PATH="build/macos/Build/Products/Release/${APP_NAME}-${APP_VERSION}.zip"
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
log_success "ZIP 文件创建完成: $ZIP_PATH"
}
# 手动公证应用
notarize_app_manual() {
log_info "开始手动公证应用..."
# 创建 ZIP 文件
create_zip
ZIP_PATH="build/macos/Build/Products/Release/${APP_NAME}-${APP_VERSION}.zip"
log_warning "请按照以下步骤进行手动公证:"
echo ""
log_info "1. 打开浏览器访问https://developer.apple.com/account/resources/certificates/list"
log_info "2. 登录您的 Apple Developer 账户"
log_info "3. 点击左侧菜单的 'Services' > 'Notarization'"
log_info "4. 点击 'Upload' 按钮"
log_info "5. 选择文件:$ZIP_PATH"
log_info "6. 等待公证完成(通常需要几分钟)"
echo ""
read -p "按回车键继续,当公证完成后..."
# 检查公证状态
log_info "检查公证状态..."
xcrun stapler validate "$APP_PATH" 2>/dev/null || log_warning "应用尚未公证或公证失败"
}
# 手动公证 DMG
notarize_dmg_manual() {
log_info "开始手动公证 DMG..."
log_warning "请按照以下步骤进行手动公证:"
echo ""
log_info "1. 打开浏览器访问https://developer.apple.com/account/resources/certificates/list"
log_info "2. 登录您的 Apple Developer 账户"
log_info "3. 点击左侧菜单的 'Services' > 'Notarization'"
log_info "4. 点击 'Upload' 按钮"
log_info "5. 选择文件:$DMG_PATH"
log_info "6. 等待公证完成(通常需要几分钟)"
echo ""
read -p "按回车键继续,当公证完成后..."
# 检查公证状态
log_info "检查公证状态..."
xcrun stapler validate "$DMG_PATH" 2>/dev/null || log_warning "DMG 尚未公证或公证失败"
}
# 装订公证票据
staple_tickets() {
log_info "装订公证票据..."
# 装订应用
log_info "装订应用公证票据..."
xcrun stapler staple "$APP_PATH" 2>/dev/null || log_warning "应用公证票据装订失败"
# 装订 DMG
log_info "装订 DMG 公证票据..."
xcrun stapler staple "$DMG_PATH" 2>/dev/null || log_warning "DMG 公证票据装订失败"
}
# 验证最终结果
verify_result() {
log_info "验证最终结果..."
# 检查应用签名
log_info "应用签名状态:"
codesign -dv "$APP_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier|BundleId)" || true
# 检查 DMG 签名
log_info "DMG 签名状态:"
codesign -dv "$DMG_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier)" || true
# 检查公证状态
log_info "应用公证状态:"
xcrun stapler validate "$APP_PATH" 2>/dev/null && log_success "应用已公证" || log_warning "应用未公证"
log_info "DMG 公证状态:"
xcrun stapler validate "$DMG_PATH" 2>/dev/null && log_success "DMG 已公证" || log_warning "DMG 未公证"
}
# 显示结果
show_result() {
log_success "=========================================="
log_success "手动公证完成!"
log_success "=========================================="
log_info "应用: $APP_PATH"
log_info "DMG: $DMG_PATH"
log_success "=========================================="
log_info "现在应用已通过 Apple 公证"
log_info "可以在任何 Mac 上安全运行"
log_success "=========================================="
}
# 主函数
main() {
log_info "开始 BearVPN macOS 手动公证流程..."
log_info "=========================================="
check_files
notarize_app_manual
notarize_dmg_manual
staple_tickets
verify_result
show_result
log_success "手动公证完成!"
}
# 运行主函数
main "$@"

View File

@ -1,255 +0,0 @@
#!/bin/bash
# Nextcloud 文件管理脚本
# 用于管理员查看和管理用户文件
set -e
# 配置变量
NEXTCLOUD_PATH="/var/www/nextcloud"
DATA_PATH="/var/www/nextcloud/data"
WEB_USER="www-data"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Nextcloud 安装
check_nextcloud() {
if [ ! -d "$NEXTCLOUD_PATH" ]; then
log_error "Nextcloud 未安装在 $NEXTCLOUD_PATH"
log_info "请修改脚本中的 NEXTCLOUD_PATH 变量"
exit 1
fi
log_success "找到 Nextcloud 安装"
}
# 显示所有用户
list_users() {
log_info "获取所有用户列表..."
echo ""
echo "=== 用户列表 ==="
sudo -u $WEB_USER php $NEXTCLOUD_PATH/occ user:list
echo ""
}
# 显示用户详细信息
show_user_info() {
local username=$1
if [ -z "$username" ]; then
log_error "请提供用户名"
return 1
fi
log_info "获取用户 $username 的详细信息..."
echo ""
echo "=== 用户 $username 信息 ==="
sudo -u $WEB_USER php $NEXTCLOUD_PATH/occ user:info "$username"
echo ""
}
# 显示用户文件统计
show_user_files() {
local username=$1
if [ -z "$username" ]; then
log_error "请提供用户名"
return 1
fi
local user_path="$DATA_PATH/$username/files"
if [ ! -d "$user_path" ]; then
log_error "用户 $username 的文件目录不存在"
return 1
fi
log_info "分析用户 $username 的文件..."
echo ""
echo "=== 用户 $username 文件统计 ==="
echo "文件总数: $(find "$user_path" -type f | wc -l)"
echo "目录总数: $(find "$user_path" -type d | wc -l)"
echo "总大小: $(du -sh "$user_path" | cut -f1)"
echo ""
echo "=== 按文件类型统计 ==="
find "$user_path" -type f -name ".*" -prune -o -type f -print | \
sed 's/.*\.//' | sort | uniq -c | sort -nr | head -10
echo ""
echo "=== 最大的 10 个文件 ==="
find "$user_path" -type f -exec ls -lh {} + | \
sort -k5 -hr | head -10 | awk '{print $5, $9}'
echo ""
}
# 搜索文件
search_files() {
local username=$1
local pattern=$2
if [ -z "$username" ] || [ -z "$pattern" ]; then
log_error "请提供用户名和搜索模式"
return 1
fi
local user_path="$DATA_PATH/$username/files"
if [ ! -d "$user_path" ]; then
log_error "用户 $username 的文件目录不存在"
return 1
fi
log_info "在用户 $username 的文件中搜索: $pattern"
echo ""
echo "=== 搜索结果 ==="
find "$user_path" -iname "*$pattern*" -type f | head -20
echo ""
}
# 显示存储使用情况
show_storage_usage() {
log_info "分析存储使用情况..."
echo ""
echo "=== 存储使用统计 ==="
# 总存储使用
total_size=$(du -sh "$DATA_PATH" | cut -f1)
echo "总存储使用: $total_size"
echo ""
# 按用户统计
echo "=== 各用户存储使用 ==="
for user_dir in "$DATA_PATH"/*; do
if [ -d "$user_dir" ] && [ "$(basename "$user_dir")" != "appdata_oc" ]; then
username=$(basename "$user_dir")
user_size=$(du -sh "$user_dir" | cut -f1)
file_count=$(find "$user_dir/files" -type f 2>/dev/null | wc -l)
echo "$username: $user_size ($file_count 个文件)"
fi
done
echo ""
}
# 清理用户文件
cleanup_user_files() {
local username=$1
local pattern=$2
if [ -z "$username" ]; then
log_error "请提供用户名"
return 1
fi
local user_path="$DATA_PATH/$username/files"
if [ ! -d "$user_path" ]; then
log_error "用户 $username 的文件目录不存在"
return 1
fi
log_warning "即将清理用户 $username 的文件"
if [ -n "$pattern" ]; then
log_warning "清理模式: $pattern"
fi
read -p "确认继续?(y/N): " confirm
if [[ $confirm != [yY] ]]; then
log_info "操作已取消"
return 0
fi
if [ -n "$pattern" ]; then
find "$user_path" -iname "*$pattern*" -type f -delete
log_success "已清理匹配 $pattern 的文件"
else
log_error "请提供清理模式"
return 1
fi
}
# 显示帮助
show_help() {
echo "Nextcloud 文件管理脚本"
echo ""
echo "用法: $0 [选项] [参数]"
echo ""
echo "选项:"
echo " list-users 显示所有用户"
echo " user-info <用户名> 显示用户详细信息"
echo " user-files <用户名> 显示用户文件统计"
echo " search <用户名> <模式> 搜索用户文件"
echo " storage 显示存储使用情况"
echo " cleanup <用户名> <模式> 清理用户文件(危险操作)"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 list-users"
echo " $0 user-info john"
echo " $0 user-files john"
echo " $0 search john *.pdf"
echo " $0 storage"
echo " $0 cleanup john *.tmp"
}
# 主函数
main() {
case "$1" in
"list-users")
check_nextcloud
list_users
;;
"user-info")
check_nextcloud
show_user_info "$2"
;;
"user-files")
check_nextcloud
show_user_files "$2"
;;
"search")
check_nextcloud
search_files "$2" "$3"
;;
"storage")
check_nextcloud
show_storage_usage
;;
"cleanup")
check_nextcloud
cleanup_user_files "$2" "$3"
;;
"help"|"--help"|"-h")
show_help
;;
*)
log_error "未知选项: $1"
show_help
exit 1
;;
esac
}
# 运行主函数
main "$@"

View File

@ -1,102 +0,0 @@
#!/bin/bash
# 异步公证脚本 - 不等待结果
# 作者: AI Assistant
set -e
# 配置变量
APPLE_ID="kieran@newlifeephrata.us"
PASSWORD="gtvp-izmw-cubf-yxfe"
TEAM_ID="3UR892FAP3"
ZIP_FILE="build/macos/Build/Products/Release/BearVPN-1.0.0.zip"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查文件
check_file() {
if [ ! -f "$ZIP_FILE" ]; then
log_error "ZIP 文件不存在: $ZIP_FILE"
exit 1
fi
log_success "找到文件: $ZIP_FILE"
}
# 异步提交公证
submit_async() {
log_info "开始异步提交公证..."
# 提交但不等待结果
SUBMISSION_ID=$(xcrun notarytool submit "$ZIP_FILE" \
--apple-id "$APPLE_ID" \
--password "$PASSWORD" \
--team-id "$TEAM_ID" \
--output-format json | jq -r '.id')
if [ -z "$SUBMISSION_ID" ] || [ "$SUBMISSION_ID" = "null" ]; then
log_error "提交失败,无法获取提交 ID"
exit 1
fi
log_success "提交成功!"
log_info "提交 ID: $SUBMISSION_ID"
# 保存提交 ID 到文件
echo "$SUBMISSION_ID" > .notarization_id
echo "$(date)" > .notarization_time
log_info "提交 ID 已保存到 .notarization_id"
log_warning "请稍后使用 ./check_notarization_status.sh 检查状态"
}
# 显示后续操作
show_next_steps() {
log_success "=========================================="
log_success "异步提交完成!"
log_success "=========================================="
log_info "提交 ID: $SUBMISSION_ID"
log_info "提交时间: $(date)"
log_success "=========================================="
log_info "后续操作:"
log_info "1. 检查状态: ./check_notarization_status.sh info $SUBMISSION_ID"
log_info "2. 查看历史: ./check_notarization_status.sh history"
log_info "3. 实时监控: ./check_notarization_status.sh monitor"
log_info "4. 完成后装订: xcrun stapler staple BearVPN-1.0.0-macOS-Signed.dmg"
log_success "=========================================="
}
# 主函数
main() {
log_info "开始异步公证提交..."
log_info "=========================================="
check_file
submit_async
show_next_steps
log_success "提交完成,您可以继续其他工作!"
}
# 运行主函数
main "$@"

View File

@ -1,175 +0,0 @@
#!/bin/bash
# BearVPN macOS 公证脚本
# 作者: AI Assistant
set -e
# 配置变量
APP_NAME="BearVPN"
APP_VERSION="1.0.0"
APP_PATH="build/macos/Build/Products/Release/${APP_NAME}.app"
DMG_PATH="build/macos/Build/Products/Release/${APP_NAME}-${APP_VERSION}-macOS-Signed.dmg"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查文件是否存在
check_files() {
if [ ! -d "$APP_PATH" ]; then
log_error "应用文件不存在: $APP_PATH"
log_info "请先运行 ./sign_and_package.sh 构建应用"
exit 1
fi
if [ ! -f "$DMG_PATH" ]; then
log_error "DMG 文件不存在: $DMG_PATH"
log_info "请先运行 ./sign_and_package.sh 构建 DMG"
exit 1
fi
log_success "找到应用和 DMG 文件"
}
# 公证应用
notarize_app() {
log_info "开始公证应用..."
# 创建 ZIP 文件用于公证
ZIP_PATH="build/macos/Build/Products/Release/${APP_NAME}-${APP_VERSION}.zip"
log_info "创建 ZIP 文件: $ZIP_PATH"
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
log_warning "请确保您已生成应用专用密码:"
log_warning "1. 访问 https://appleid.apple.com"
log_warning "2. 登录您的 Apple ID"
log_warning "3. 在'安全'部分生成应用专用密码"
log_warning "4. 使用该密码进行公证"
echo ""
# 上传进行公证
log_info "上传应用进行公证..."
xcrun notarytool submit "$ZIP_PATH" \
--apple-id "kieran@newlifeephrata.us" \
--password "gtvp-izmw-cubf-yxfe" \
--team-id "3UR892FAP3" \
--wait
if [ $? -eq 0 ]; then
log_success "应用公证成功"
# 装订公证票据
log_info "装订公证票据到应用..."
xcrun stapler staple "$APP_PATH"
if [ $? -eq 0 ]; then
log_success "公证票据装订成功"
else
log_warning "公证票据装订失败,但应用已公证"
fi
else
log_error "应用公证失败"
log_info "请检查 Apple ID 和应用专用密码是否正确"
exit 1
fi
# 清理 ZIP 文件
rm -f "$ZIP_PATH"
}
# 公证 DMG
notarize_dmg() {
log_info "开始公证 DMG..."
# 上传 DMG 进行公证
log_info "上传 DMG 进行公证..."
xcrun notarytool submit "$DMG_PATH" \
--apple-id "kieran@newlifeephrata.us" \
--password "gtvp-izmw-cubf-yxfe" \
--team-id "3UR892FAP3" \
--wait
if [ $? -eq 0 ]; then
log_success "DMG 公证成功"
# 装订公证票据
log_info "装订公证票据到 DMG..."
xcrun stapler staple "$DMG_PATH"
if [ $? -eq 0 ]; then
log_success "DMG 公证票据装订成功"
else
log_warning "DMG 公证票据装订失败,但 DMG 已公证"
fi
else
log_error "DMG 公证失败"
log_info "请检查 Apple ID 和应用专用密码是否正确"
exit 1
fi
}
# 验证公证状态
verify_notarization() {
log_info "验证公证状态..."
# 验证应用公证
log_info "应用公证状态:"
xcrun stapler validate "$APP_PATH"
# 验证 DMG 公证
log_info "DMG 公证状态:"
xcrun stapler validate "$DMG_PATH"
}
# 显示结果
show_result() {
log_success "=========================================="
log_success "公证完成!"
log_success "=========================================="
log_info "应用: $APP_PATH"
log_info "DMG: $DMG_PATH"
log_success "=========================================="
log_info "现在应用已通过 Apple 公证"
log_info "可以在任何 Mac 上安全运行"
log_success "=========================================="
}
# 主函数
main() {
log_info "开始 BearVPN macOS 公证流程..."
log_info "=========================================="
check_files
notarize_app
notarize_dmg
verify_notarization
show_result
log_success "公证完成!"
}
# 运行主函数
main "$@"

View File

@ -1,137 +0,0 @@
# Flutter Windows 单文件 EXE 打包指南
## 🎯 目标
将 Flutter Windows 应用打包成单个可执行文件,便于分发和部署。
## 📋 当前状态
### 现有构建输出
```
build/windows/x64/runner/Release/
├── hostexecutor.exe # 主程序
├── flutter_windows.dll # Flutter 引擎
├── msvcp140.dll # Visual C++ 运行时
├── vcruntime140.dll # Visual C++ 运行时
├── vcruntime140_1.dll # Visual C++ 运行时
└── data/ # 应用数据文件夹
├── app.so # Dart 代码编译结果
└── flutter_assets/ # 资源文件
```
### 问题分析
Flutter 默认构建会生成多个文件,因为:
1. **Flutter 引擎** (`flutter_windows.dll`) - 必须包含
2. **Visual C++ 运行时** - 系统依赖
3. **应用数据** (`data` 文件夹) - 包含资源和 Dart 代码
## 🔧 解决方案
### 方案一:使用 Enigma Virtual Box推荐
#### 步骤 1下载安装
1. 下载 [Enigma Virtual Box](https://enigmaprotector.com/en/downloads.html)
2. 安装并运行
#### 步骤 2打包配置
1. **主程序文件**: 选择 `build/windows/x64/runner/Release/hostexecutor.exe`
2. **添加文件夹**: 选择整个 `Release` 文件夹
3. **输出文件**: 设置输出路径和文件名
4. **文件选项**: 勾选"压缩文件"
#### 步骤 3生成单文件
点击"Process"生成单个可执行文件。
### 方案二:使用 Inno Setup安装程序
#### 步骤 1下载安装
1. 下载 [Inno Setup](https://jrsoftware.org/isinfo.php)
2. 安装并运行
#### 步骤 2创建脚本
```ini
[Setup]
AppName=HostExecutor
AppVersion=1.0.0
DefaultDirName={autopf}\HostExecutor
OutputBaseFilename=HostExecutor_Setup
[Files]
Source: "build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
[Icons]
Name: "{group}\HostExecutor"; Filename: "{app}\hostexecutor.exe"
```
#### 步骤 3编译生成
编译脚本生成安装程序。
### 方案三:使用 Windows 自带工具(高级)
#### 使用 `dotnet publish`(需要 .NET 包装)
```bash
# 需要创建 .NET 包装器项目
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true
```
## 🚀 自动化脚本
### Enigma Virtual Box 自动化脚本
```powershell
# package_single_exe.ps1
$enigmaPath = "C:\Program Files\Enigma Virtual Box\enigmavb.exe"
$inputFile = "build\windows\x64\runner\Release\hostexecutor.exe"
$outputFile = "dist\HostExecutor_Single.exe"
$folderPath = "build\windows\x64\runner\Release"
& $enigmaPath /sf $inputFile /lf $outputFile /folder $folderPath /compress
```
## 📦 打包后文件结构
### 单文件输出
```
dist/
└── HostExecutor_Single.exe # 单个可执行文件50-100MB
```
### 文件大小分析
- **原始文件**: 约 30-50MB
- **压缩后**: 约 25-40MB取决于压缩率
- **最终大小**: 50-100MB包含所有依赖
## ⚠️ 注意事项
### 运行时依赖
1. **Windows 版本**: Windows 10 版本 1903+ 或 Windows 11
2. **系统组件**: 确保目标系统有最新的 Windows 更新
3. **防病毒软件**: 单文件可能被误报,需要添加信任
### 性能影响
- **启动时间**: 单文件启动会稍慢(需要解压)
- **内存使用**: 运行时内存占用相同
- **文件大小**: 比多文件版本大约 10-20%
## 🎯 推荐方案
### 开发阶段
使用多文件版本,便于调试和更新。
### 分发阶段
使用 Enigma Virtual Box 创建单文件版本:
1. **简单易用** - 图形化界面
2. **压缩率高** - 有效减小文件大小
3. **兼容性好** - 支持所有 Windows 版本
4. **免费** - 个人和商业使用都免费
## 📋 下一步行动
1. **安装 Enigma Virtual Box**
2. **测试单文件打包**
3. **验证运行效果**
4. **创建自动化打包流程**
## 🔗 相关资源
- [Enigma Virtual Box 官网](https://enigmaprotector.com/en/downloads.html)
- [Inno Setup 官网](https://jrsoftware.org/isinfo.php)
- [Flutter Windows 文档](https://docs.flutter.dev/desktop)

View File

@ -1,168 +0,0 @@
#Requires -RunAsAdministrator
<#
.SYNOPSIS
Builds and packages a Flutter Windows application into a single executable.
.DESCRIPTION
This script automates the entire process of creating a single-file executable for a Flutter Windows project.
It performs the following steps:
1. Checks for and installs Chocolatey if not present.
2. Installs Enigma Virtual Box and 7-Zip using Chocolatey.
3. Builds the Flutter application in release mode.
4. Packages the build output into a single EXE using Enigma Virtual Box.
5. If Enigma fails, it falls back to creating a 7-Zip self-extracting archive.
6. Places the final packaged executable in the 'dist' directory.
.NOTES
- This script must be run with Administrator privileges to install software.
- An internet connection is required for the first run to download and install dependencies.
#>
# --- Configuration ---
$ErrorActionPreference = "Stop"
$buildPath = ".\build\windows\x64\runner\Release"
$outputPath = ".\dist"
# --- Helper Functions ---
function Test-CommandExists {
param($command)
return (Get-Command $command -ErrorAction SilentlyContinue)
}
function Install-Chocolatey {
if (Test-CommandExists "choco") {
Write-Host "✅ Chocolatey is already installed."
return
}
Write-Host "Chocolatey not found. Installing..."
try {
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
Write-Host "✅ Chocolatey installed successfully."
} catch {
Write-Host "❌ Failed to install Chocolatey. Please install it manually and re-run the script."
exit 1
}
}
function Install-Tools {
Write-Host "Checking for required tools (Enigma Virtual Box, 7-Zip)..."
$tools = @("enigma-virtual-box", "7zip")
foreach ($tool in $tools) {
if (choco list --local-only --exact $tool) {
Write-Host "$tool is already installed."
} else {
Write-Host "Installing $tool..."
try {
choco install $tool -y --force
Write-Host "$tool installed successfully."
} catch {
Write-Host "❌ Failed to install $tool."
exit 1
}
}
}
}
# --- Main Script ---
# 1. Setup Environment
Write-Host "=== 1/4: Setting up build environment ==="
Install-Chocolatey
Install-Tools
# 2. Build Flutter App
Write-Host "=== 2/4: Building Flutter Windows application (Release) ==="
try {
flutter build windows --release
} catch {
Write-Host "❌ Flutter build failed."
exit 1
}
# 3. Package Application
Write-Host "=== 3/4: Packaging into a single executable ==="
if (-not (Test-Path $buildPath)) {
Write-Host "❌ Build directory not found: $buildPath"
exit 1
}
# Create output directory
New-Item -ItemType Directory -Path $outputPath -Force | Out-Null
# Get main executable
$exeFile = Get-ChildItem -Path $buildPath -Filter "*.exe" | Select-Object -First 1
if (-not $exeFile) {
Write-Host "❌ No executable found in build directory."
exit 1
}
$inputExe = $exeFile.FullName
$outputExe = "$outputPath\$($exeFile.BaseName)_Single.exe"
$enigmaCliPath = "C:\Program Files\Enigma Virtual Box\enigmavb.exe"
$packageSuccess = $false
# Attempt to package with Enigma Virtual Box
if (Test-Path $enigmaCliPath) {
Write-Host "Attempting to package with Enigma Virtual Box..."
try {
& $enigmaCliPath /quiet /project "$outputPath\project.evb" /input "$inputExe" /output "$outputExe" /folder "$buildPath" /compress 3 /deleteext
if ($?) {
Write-Host "✅ Enigma Virtual Box packaging successful."
$packageSuccess = $true
} else {
Write-Host "⚠️ Enigma Virtual Box packaging failed. Exit code: $lastexitcode"
}
} catch {
Write-Host "⚠️ An error occurred during Enigma Virtual Box packaging."
}
} else {
Write-Host "⚠️ Enigma Virtual Box not found at $enigmaCliPath."
}
# 4. Fallback to 7-Zip if Enigma failed
if (-not $packageSuccess) {
Write-Host "=== 4/4: Fallback: Packaging with 7-Zip SFX ==="
$7zipCliPath = "C:\Program Files\7-Zip\7z.exe"
$outputSfx = "$outputPath\$($exeFile.BaseName)_Package.exe"
if (-not (Test-Path $7zipCliPath)) {
Write-Host "❌ 7-Zip not found. Cannot create self-extracting archive."
exit 1
}
$sfxConfig = @'
;!@Install@!UTF-8!
Title="Flutter Application"
BeginPrompt="Do you want to extract and run the application?"
RunProgram="%%T\%%S\$($exeFile.Name)"
;!@InstallEnd@!
'@
$sfxConfigFile = "$outputPath\sfx_config.txt"
Set-Content -Path $sfxConfigFile -Value $sfxConfig
try {
& $7zipCliPath a -sfx7z.sfx "$outputSfx" "$buildPath\*" -r "-i!$sfxConfigFile"
Write-Host "✅ 7-Zip self-extracting archive created successfully."
$outputExe = $outputSfx
$packageSuccess = $true
} catch {
Write-Host "❌ 7-Zip packaging failed."
exit 1
}
}
# --- Final Summary ---
if ($packageSuccess) {
$finalSize = (Get-Item $outputExe).Length / 1MB
Write-Host "================================================"
Write-Host "✅ Packaging Complete!"
Write-Host " Output file: $outputExe"
Write-Host " Size: $([math]::Round($finalSize, 2)) MB"
Write-Host "================================================"
} else {
Write-Host "❌ All packaging attempts failed."
}

View File

@ -1,97 +0,0 @@
# Flutter Windows 单文件打包脚本 - Enigma Virtual Box
# 以管理员身份运行
Write-Host "=== Flutter Windows 单文件打包工具 ===" -ForegroundColor Green
# 配置参数
$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$buildPath = "$projectRoot\build\windows\x64\runner\Release"
$outputPath = "$projectRoot\dist"
$enigmaPath = "C:\Program Files\Enigma Virtual Box\enigmavb.exe"
# 检查构建文件
Write-Host "`n检查构建文件..." -ForegroundColor Yellow
if (-not (Test-Path $buildPath)) {
Write-Host "错误: 构建文件不存在,请先运行 flutter build windows" -ForegroundColor Red
exit 1
}
# 创建输出目录
if (-not (Test-Path $outputPath)) {
New-Item -ItemType Directory -Path $outputPath -Force | Out-Null
}
# 检查 Enigma Virtual Box
if (-not (Test-Path $enigmaPath)) {
Write-Host "错误: Enigma Virtual Box 未安装" -ForegroundColor Red
Write-Host "请下载安装: https://enigmaprotector.com/en/downloads.html" -ForegroundColor Yellow
exit 1
}
# 获取主程序名称
$exeFile = Get-ChildItem -Path $buildPath -Filter "*.exe" | Select-Object -First 1
if (-not $exeFile) {
Write-Host "错误: 未找到可执行文件" -ForegroundColor Red
exit 1
}
$inputExe = $exeFile.FullName
$outputExe = "$outputPath\$($exeFile.BaseName)_Single.exe"
Write-Host "主程序: $inputExe" -ForegroundColor Cyan
Write-Host "输出文件: $outputExe" -ForegroundColor Cyan
# 创建打包配置文件
$configContent = @"
; Enigma Virtual Box 配置文件
[Config]
InputFile=$inputExe
OutputFile=$outputExe
Files=%DEFAULT FOLDER%
VirtualizationMode=Never Write To Disk
Compression=Yes
ShareVirtualSystem=Yes
[Files]
; 添加整个 Release 文件夹
Folder=$buildPath\*
"@
$configFile = "$outputPath\package_config.evb"
Set-Content -Path $configFile -Value $configContent
# 执行打包
Write-Host "`n开始打包..." -ForegroundColor Yellow
Write-Host "这可能需要几分钟时间,请耐心等待..." -ForegroundColor Yellow
$process = Start-Process -FilePath $enigmaPath -ArgumentList "/sf", $inputExe, "/lf", $outputExe, "/folder", $buildPath, "/compress" -Wait -PassThru
if ($process.ExitCode -eq 0) {
Write-Host "`n✅ 打包成功!" -ForegroundColor Green
# 显示结果信息
$originalSize = (Get-Item $inputExe).Length / 1MB
$packedSize = (Get-Item $outputExe).Length / 1MB
$compressionRatio = [math]::Round((1 - $packedSize / $originalSize) * 100, 2)
Write-Host "`n打包结果:" -ForegroundColor Cyan
Write-Host "原始大小: $([math]::Round($originalSize, 2)) MB" -ForegroundColor White
Write-Host "打包大小: $([math]::Round($packedSize, 2)) MB" -ForegroundColor White
Write-Host "压缩率: $compressionRatio%" -ForegroundColor White
Write-Host "输出文件: $outputExe" -ForegroundColor White
Write-Host "`n📋 使用说明:" -ForegroundColor Yellow
Write-Host "1. 将生成的单文件复制到目标计算机" -ForegroundColor White
Write-Host "2. 直接运行即可,无需安装其他依赖" -ForegroundColor White
Write-Host "3. 首次运行可能需要管理员权限" -ForegroundColor White
} else {
Write-Host "`n❌ 打包失败!" -ForegroundColor Red
Write-Host "错误代码: $($process.ExitCode)" -ForegroundColor Red
}
# 清理临时文件
Remove-Item $configFile -ErrorAction SilentlyContinue
Write-Host "`n按任意键退出..." -ForegroundColor Gray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

View File

@ -249,14 +249,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.3" version: "2.4.3"
crisp_sdk:
dependency: "direct main"
description:
name: crisp_sdk
sha256: "46f3112b9212bf78f166fc4e3bf7121fad2c7cada204c0dfdedef4f3d99f3cf5"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
cross_file: cross_file:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,166 +0,0 @@
#!/bin/bash
# iOS 签名设置助手脚本
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查证书
check_certificates() {
log_info "检查已安装的证书..."
local identities=$(security find-identity -v -p codesigning 2>/dev/null)
if [ -n "$identities" ] && echo "$identities" | grep -q "iPhone Developer\|Apple Development"; then
log_success "找到可用的开发证书:"
echo "$identities" | grep "iPhone Developer\|Apple Development"
return 0
else
log_warning "未找到可用的开发证书"
return 1
fi
}
# 安装证书
install_certificate() {
local cert_file=$1
if [ -z "$cert_file" ]; then
log_error "请提供证书文件路径"
return 1
fi
if [ ! -f "$cert_file" ]; then
log_error "证书文件不存在: $cert_file"
return 1
fi
log_info "安装证书: $cert_file"
# 安装证书到钥匙串
security import "$cert_file" -k ~/Library/Keychains/login.keychain
if [ $? -eq 0 ]; then
log_success "证书安装成功"
else
log_error "证书安装失败"
return 1
fi
}
# 打开 Apple Developer Portal
open_developer_portal() {
log_info "打开 Apple Developer Portal..."
# 打开 App IDs 页面
open "https://developer.apple.com/account/resources/identifiers/list"
# 打开 Profiles 页面
open "https://developer.apple.com/account/resources/profiles/list"
log_info "请在浏览器中完成以下步骤:"
echo "1. 创建 App ID (Bundle ID: com.bearvpn.app)"
echo "2. 创建 Provisioning Profile"
echo "3. 下载并安装 Provisioning Profile"
}
# 验证完整设置
verify_setup() {
log_info "验证签名设置..."
# 检查证书
if ! check_certificates; then
log_error "证书检查失败"
return 1
fi
# 检查 Provisioning Profile
local profiles_dir="$HOME/Library/MobileDevice/Provisioning Profiles"
if [ -d "$profiles_dir" ] && [ "$(ls -A "$profiles_dir" 2>/dev/null)" ]; then
log_success "找到 Provisioning Profile"
ls -la "$profiles_dir"
else
log_warning "未找到 Provisioning Profile"
log_info "请确保已下载并安装了 Provisioning Profile"
fi
return 0
}
# 显示使用说明
show_instructions() {
log_info "iOS 签名设置说明"
echo "=========================================="
echo "1. 证书安装:"
echo " - 双击桌面上的 .cer 文件安装到钥匙串"
echo " - 或运行: ./setup_ios_signing.sh install ~/Desktop/your_cert.cer"
echo ""
echo "2. 创建 App ID"
echo " - Bundle ID: com.bearvpn.app"
echo " - 选择需要的功能(如 Network Extensions"
echo ""
echo "3. 创建 Provisioning Profile"
echo " - 选择 iOS App Development"
echo " - 选择刚创建的 App ID"
echo " - 选择您的证书"
echo " - 下载并双击安装 .mobileprovision 文件"
echo ""
echo "4. 验证设置:"
echo " - 运行: ./setup_ios_signing.sh verify"
echo ""
echo "5. 构建签名应用:"
echo " - 运行: source ios_signing_config.sh"
echo " - 运行: ./build_ios_dmg.sh"
echo "=========================================="
}
# 主函数
main() {
case "${1:-}" in
"install")
if [ -z "$2" ]; then
log_error "请提供证书文件路径"
echo "用法: $0 install <certificate_file>"
exit 1
fi
install_certificate "$2"
;;
"verify")
verify_setup
;;
"open")
open_developer_portal
;;
"check")
check_certificates
;;
*)
show_instructions
;;
esac
}
# 运行主函数
main "$@"

View File

@ -1,214 +0,0 @@
#!/bin/bash
# BearVPN macOS 签名和打包脚本
# 作者: AI Assistant
# 日期: $(date)
set -e
# 配置变量
APP_NAME="BearVPN"
APP_VERSION="1.0.0"
DMG_NAME="${APP_NAME}-${APP_VERSION}-macOS-Signed"
APP_PATH="build/macos/Build/Products/Release/${APP_NAME}.app"
DMG_PATH="build/macos/Build/Products/Release/${DMG_NAME}.dmg"
# 签名配置
DEVELOPER_ID="Developer ID Application: Civil Rights Corps (3UR892FAP3)"
TEAM_ID="3UR892FAP3"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查证书
check_certificates() {
log_info "检查开发者证书..."
# 检查证书是否存在
if ! security find-certificate -a -c "Civil Rights Corps" > /dev/null 2>&1; then
log_error "未找到 Developer ID Application 证书"
log_info "请确保已安装有效的开发者证书"
exit 1
fi
log_success "找到 Developer ID Application 证书"
}
# 清理旧文件
cleanup() {
log_info "清理旧的构建文件..."
rm -rf build/macos/Build/Products/Release/*
log_success "清理完成"
}
# 构建应用
build_app() {
log_info "开始构建 macOS 应用..."
flutter build macos --release
if [ ! -d "$APP_PATH" ]; then
log_error "应用构建失败"
exit 1
fi
log_success "应用构建完成"
}
# 签名应用
sign_app() {
log_info "开始签名应用..."
# 签名应用
codesign --force --deep --sign "$DEVELOPER_ID" "$APP_PATH"
if [ $? -eq 0 ]; then
log_success "应用签名成功"
else
log_error "应用签名失败"
exit 1
fi
# 验证签名
log_info "验证应用签名..."
codesign --verify --verbose "$APP_PATH"
if [ $? -eq 0 ]; then
log_success "应用签名验证通过"
else
log_error "应用签名验证失败"
exit 1
fi
# 显示签名信息
log_info "签名信息:"
codesign -dv --verbose=4 "$APP_PATH"
}
# 创建 DMG
create_dmg() {
log_info "开始创建签名的 DMG 文件..."
# 使用 create-dmg 创建 DMG
create-dmg \
--volname "$APP_NAME" \
--volicon "macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--icon "$APP_NAME.app" 175 190 \
--hide-extension "$APP_NAME.app" \
--app-drop-link 425 190 \
--no-internet-enable \
"$DMG_PATH" \
"$APP_PATH"
if [ $? -eq 0 ]; then
log_success "DMG 文件创建成功: $DMG_PATH"
else
log_error "DMG 文件创建失败"
exit 1
fi
}
# 签名 DMG
sign_dmg() {
log_info "开始签名 DMG 文件..."
# 签名 DMG
codesign --force --sign "$DEVELOPER_ID" "$DMG_PATH"
if [ $? -eq 0 ]; then
log_success "DMG 签名成功"
else
log_error "DMG 签名失败"
exit 1
fi
# 验证 DMG 签名
log_info "验证 DMG 签名..."
codesign --verify --verbose "$DMG_PATH"
if [ $? -eq 0 ]; then
log_success "DMG 签名验证通过"
else
log_error "DMG 签名验证失败"
exit 1
fi
}
# 验证最终结果
verify_final() {
log_info "验证最终结果..."
# 检查文件大小
APP_SIZE=$(du -h "$APP_PATH" | cut -f1)
DMG_SIZE=$(du -h "$DMG_PATH" | cut -f1)
log_info "应用大小: $APP_SIZE"
log_info "DMG 大小: $DMG_SIZE"
# 检查签名状态
log_info "应用签名状态:"
codesign -dv "$APP_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier|BundleId)"
log_info "DMG 签名状态:"
codesign -dv "$DMG_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier)"
}
# 显示结果
show_result() {
log_success "=========================================="
log_success "签名和打包完成!"
log_success "=========================================="
log_info "应用名称: $APP_NAME"
log_info "版本: $APP_VERSION"
log_info "签名应用: $APP_PATH"
log_info "签名 DMG: $DMG_PATH"
log_info "开发者: $DEVELOPER_ID"
log_success "=========================================="
log_info "现在可以安全地分发给用户"
log_info "用户安装时不会看到安全警告"
log_success "=========================================="
}
# 主函数
main() {
log_info "开始 BearVPN macOS 签名和打包流程..."
log_info "=========================================="
check_certificates
cleanup
build_app
sign_app
create_dmg
sign_dmg
verify_final
show_result
log_success "所有操作完成!"
}
# 运行主函数
main "$@"

View File

@ -1,42 +0,0 @@
#!/bin/bash
# 简化的连接测试脚本
echo "🔍 开始连接调试..."
# 测试基本网络连接
echo "📡 测试基本网络连接..."
if ping -c 3 8.8.8.8 > /dev/null 2>&1; then
echo "✅ 基本网络连接正常"
else
echo "❌ 基本网络连接失败"
exit 1
fi
# 测试 DNS 解析
echo "🌐 测试 DNS 解析..."
if nslookup google.com > /dev/null 2>&1; then
echo "✅ DNS 解析正常"
else
echo "❌ DNS 解析失败"
fi
# 测试常见端口
echo "🔌 测试常见端口连接..."
for port in 80 443 8080; do
if timeout 3 bash -c "echo >/dev/tcp/google.com/$port" 2>/dev/null; then
echo "✅ google.com:$port 连接正常"
else
echo "❌ google.com:$port 连接失败"
fi
done
# 检查 libcore 库
echo "📚 检查 libcore 库..."
if [ -f "libcore/bin/libcore.dylib" ]; then
echo "✅ 找到 libcore.dylib"
file libcore/bin/libcore.dylib
else
echo "❌ 未找到 libcore.dylib"
fi
echo "🎯 调试完成,现在可以运行应用查看详细日志"

View File

@ -1,23 +0,0 @@
@echo off
REM 测试 Flutter 安装和版本
REM 设置 Flutter 路径(假设已安装,如果未安装需手动设置)
set FLUTTER_ROOT=C:\flutter REM 替换为您的 Flutter 安装路径
REM 添加 Flutter 到 PATH
set PATH=%FLUTTER_ROOT%\bin;%PATH%
REM 检查 Flutter 版本
flutter --version
REM 如果需要,升级到指定版本
REM flutter upgrade --force
REM 启用 Windows desktop
flutter config --enable-windows-desktop
REM 获取依赖(假设在项目目录中运行)
flutter pub get
REM 暂停以查看输出
pause

View File

@ -1,38 +0,0 @@
#!/bin/bash
# 测试 URL 连通性脚本
echo "🔍 测试 URL 连通性..."
# 测试 Google 的连通性测试 URL
echo "📡 测试 http://www.gstatic.com/generate_204"
if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "http://www.gstatic.com/generate_204" | grep -q "204"; then
echo "✅ http://www.gstatic.com/generate_204 连接正常"
else
echo "❌ http://www.gstatic.com/generate_204 连接失败"
fi
# 测试 Google 的专用连通性测试 URL
echo "📡 测试 http://connectivitycheck.gstatic.com/generate_204"
if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "http://connectivitycheck.gstatic.com/generate_204" | grep -q "204"; then
echo "✅ http://connectivitycheck.gstatic.com/generate_204 连接正常"
else
echo "❌ http://connectivitycheck.gstatic.com/generate_204 连接失败"
fi
# 测试 Cloudflare 的连通性测试 URL
echo "📡 测试 http://cp.cloudflare.com"
if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "http://cp.cloudflare.com" | grep -q "200\|204"; then
echo "✅ http://cp.cloudflare.com 连接正常"
else
echo "❌ http://cp.cloudflare.com 连接失败"
fi
# 测试其他常用的连通性测试 URL
echo "📡 测试 http://www.cloudflare.com"
if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "http://www.cloudflare.com" | grep -q "200"; then
echo "✅ http://www.cloudflare.com 连接正常"
else
echo "❌ http://www.cloudflare.com 连接失败"
fi
echo "🎯 URL 连通性测试完成"

View File

@ -1,101 +0,0 @@
#!/bin/bash
# 更新 TEAM_ID 的简单脚本
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 获取 Team ID
get_team_id() {
log_info "请提供您的 Apple Developer Team ID"
log_info "您可以通过以下方式获取:"
log_info "1. 登录 https://developer.apple.com"
log_info "2. 进入 'Account' -> 'Membership'"
log_info "3. 查看 'Team ID' 字段格式类似ABC123DEF4"
echo ""
read -p "请输入您的 Team ID: " team_id
if [ -z "$team_id" ]; then
log_error "Team ID 不能为空"
exit 1
fi
# 验证 Team ID 格式应该是10位字母数字组合
if [[ ! "$team_id" =~ ^[A-Z0-9]{10}$ ]]; then
log_warning "Team ID 格式可能不正确,但继续执行"
fi
echo "$team_id"
}
# 更新配置文件
update_config() {
local team_id=$1
log_info "更新 ios_signing_config.sh 文件..."
# 备份原文件
cp ios_signing_config.sh ios_signing_config.sh.backup
# 更新 Team ID
sed -i '' "s/export TEAM_ID=\"YOUR_TEAM_ID\"/export TEAM_ID=\"$team_id\"/" ios_signing_config.sh
# 更新签名身份
sed -i '' "s/export SIGNING_IDENTITY=\"iPhone Developer: Your Name (YOUR_TEAM_ID)\"/export SIGNING_IDENTITY=\"iPhone Developer: Your Name ($team_id)\"/" ios_signing_config.sh
sed -i '' "s/export DISTRIBUTION_IDENTITY=\"iPhone Distribution: Your Name (YOUR_TEAM_ID)\"/export DISTRIBUTION_IDENTITY=\"iPhone Distribution: Your Name ($team_id)\"/" ios_signing_config.sh
log_success "配置文件已更新"
log_info "Team ID: $team_id"
}
# 显示更新后的配置
show_config() {
log_info "更新后的配置:"
echo "----------------------------------------"
grep -E "export (APPLE_ID|TEAM_ID|BUNDLE_ID|SIGNING_IDENTITY)" ios_signing_config.sh
echo "----------------------------------------"
}
# 主函数
main() {
log_info "开始更新 TEAM_ID..."
log_info "=========================================="
local team_id=$(get_team_id)
update_config "$team_id"
show_config
log_success "=========================================="
log_success "TEAM_ID 更新完成!"
log_success "=========================================="
log_info "现在可以运行:"
log_info "1. source ios_signing_config.sh"
log_info "2. ./build_ios_dmg.sh"
log_success "=========================================="
}
# 运行主函数
main "$@"

View File

@ -1,119 +0,0 @@
# Windows 构建日志分析
## 🎉 构建结果:成功!
### ✅ 成功状态
- **Debug 构建**: ✓ 成功 (282.5s)
- **Release 构建**: ✓ 成功 (27.0s)
- **最终状态**: ✅ Job succeeded
### 📁 构建输出位置
```
Debug: build\windows\x64\runner\Debug\hostexecutor.exe
Release: build\windows\x64\runner\Release\hostexecutor.exe
```
---
## ⚠️ 警告信息分析
### 1. CMake 警告(可忽略)
```
CMake Warning (dev) at flutter_inappwebview_windows/windows/CMakeLists.txt:31
Policy CMP0175 is not set: add_custom_command() rejects invalid arguments.
```
- **影响**: 无影响,这是开发者警告
- **解决方案**: 添加 `-Wno-dev` 参数可抑制
### 2. WebView2 编译警告(可忽略)
```
warning C4244: conversion from '__int64' to 'int', possible loss of data
warning C4458: declaration of 'value' hides class member
```
- **影响**: 无功能影响,只是类型转换警告
- **状态**: 正常现象,不影响使用
---
## 📤 产物上传问题
### 问题描述
```
::warning::No files were found with the provided path: build/windows/runner/Debug/
::warning::No files were found with the provided path: build/windows/runner/Release/
```
### 根本原因
**路径配置错误**workflow 配置的路径 `build/windows/runner/Debug/` 与实际构建输出路径 `build/windows/x64/runner/Debug/` 不匹配。
### 🔧 解决方案
需要更新 `.gitea/workflows/docker.yml` 中的上传路径:
```yaml
# 原配置(错误)
- name: Upload Debug build artifacts
uses: actions/upload-artifact@v3
with:
name: windows-debug-build
path: build/windows/runner/Debug/ # ❌ 错误路径
# 正确配置
- name: Upload Debug build artifacts
uses: actions/upload-artifact@v3
with:
name: windows-debug-build
path: build/windows/x64/runner/Debug/ # ✅ 正确路径
```
---
## 🏗️ 构建过程总结
### 成功的步骤
1. ✅ NuGet 安装成功(通过 Chocolatey
2. ✅ Flutter 环境配置正确
3. ✅ Windows 桌面支持启用
4. ✅ 依赖获取成功
5. ✅ 代码生成成功
6. ✅ Windows Debug 构建成功
7. ✅ Windows Release 构建成功
### 耗时分析
- **Debug 构建**: 282.5秒约4.7分钟)
- **Release 构建**: 27秒优化后更快
- **总耗时**: 约5分钟
---
## 🎯 下一步行动
### 立即修复
1. **修复上传路径** - 更新 workflow 中的产物路径
2. **验证可执行文件** - 确认 `hostexecutor.exe` 可正常运行
### 可选优化
1. **缓存优化** - 添加 Flutter 和依赖缓存
2. **并行构建** - Debug 和 Release 可并行执行
3. **压缩产物** - 减少上传文件大小
---
## 📋 构建环境信息
### 软件版本
- **Flutter**: 3.24.5
- **Visual Studio**: 2022 Enterprise
- **NuGet**: 6.14.0 (通过 Chocolatey)
- **CMake**: 最新版本
### 系统环境
- **操作系统**: Windows Server
- **架构**: x64
- **构建工具**: MSBuild
---
## 🚀 结论
**构建完全成功!** 主要的可执行文件已经生成只是上传配置需要微调。Windows 应用构建流程已经稳定运行。

View File

@ -1,147 +0,0 @@
# 工作流自动打包单文件 EXE 说明
## 🎯 功能概述
现在工作流会自动完成以下步骤:
1. ✅ 构建 Windows 应用Debug 和 Release
2. ✅ 自动下载打包工具
3. ✅ 创建单文件 EXE
4. ✅ 上传打包结果
## 🚀 工作流程
### 步骤 1: Enigma Virtual Box 打包(首选方案)
- **工具**: 自动下载 Enigma Virtual Box
- **输出**: `hostexecutor_single.exe`
- **特点**: 真正的单文件,高压缩率
### 步骤 2: 7-Zip 自解压方案(备选方案)
- **工具**: 使用系统自带的 7-Zip
- **输出**: `hostexecutor_package.exe`
- **特点**: 自解压安装包,兼容性更好
### 步骤 3: 产物上传
- **单文件 EXE**: `windows-single-exe` 工件
- **原始文件**: `windows-release-build` 工件
## 📦 打包产物
### 成功时你会得到:
```
工件列表:
├── windows-debug-build # Debug 版本(多文件)
├── windows-release-build # Release 版本(多文件)
└── windows-single-exe # 单文件 EXE自动打包
```
### 文件结构:
```
单文件 EXE:
└── hostexecutor_single.exe # 50-80MB直接运行
原始文件:
└── hostexecutor.exe # 主程序
├── flutter_windows.dll # Flutter 引擎
├── *.dll # 运行时库
└── data/ # 应用数据
```
## ⚙️ 技术实现
### 自动下载 Enigma Virtual Box
```powershell
$enigmaUrl = "https://enigmaprotector.com/assets/files/enigmavb.exe"
Invoke-WebRequest -Uri $enigmaUrl -OutFile "C:\enigmavb.exe"
```
### 智能打包逻辑
1. **尝试 Enigma** - 创建真正的单文件
2. **失败时回退** - 使用 7-Zip 自解压
3. **总是成功** - 确保有输出文件
### 压缩优化
- **压缩级别**: 最高压缩率 (`/compress`)
- **虚拟化模式**: 内存运行,不写磁盘
- **多线程**: 并行处理,加快速度
## 📋 使用说明
### 获取单文件 EXE
1. 进入 Gitea Actions 页面
2. 找到最新的成功构建
3. 下载 `windows-single-exe` 工件
4. 直接运行 `hostexecutor_single.exe`
### 验证打包结果
```powershell
# 检查文件大小(应该在 50-80MB
dir hostexecutor_single.exe
# 验证单文件(应该只有 1 个文件)
dir *.exe
```
## 🎯 优势特点
### 完全自动化
- ✅ 无需手动操作
- ✅ 自动下载工具
- ✅ 智能错误处理
- ✅ 保证输出结果
### 高质量打包
- ✅ 真正的单文件
- ✅ 高压缩率
- ✅ 内存运行,不写临时文件
- ✅ 兼容所有 Windows 版本
### 可靠回退
- ✅ Enigma 失败时自动切换 7-Zip
- ✅ 总是生成可用的输出
- ✅ 详细的构建日志
## 🔧 自定义配置
### 修改压缩级别
在工作流脚本中找到:
```powershell
# 最高压缩(当前设置)
/compress
# 快速压缩(速度优先)
/compress:fast
# 平衡压缩(推荐)
/compress:normal
```
### 修改输出文件名
```powershell
# 当前设置
$outputExe = "$outputPath\$($exeFile.BaseName)_Single.exe"
# 自定义名称
$outputExe = "$outputPath\MyApp_Portable.exe"
```
## 📊 性能指标
### 构建时间
- **Debug 构建**: ~4.7 分钟
- **Release 构建**: ~27 秒
- **单文件打包**: ~2-5 分钟
- **总时间**: ~8-12 分钟
### 文件大小
- **原始文件**: ~70MB多文件
- **单文件**: ~50-80MB压缩后
- **压缩率**: 10-30% 减小
## 🎉 总结
**现在工作流完全自动化了!**
- 🔄 每次推送代码 → 自动构建 → 自动打包单文件
- 📦 构建完成后 → 直接下载单文件 EXE 使用
- 🔧 无需手动配置 → 开箱即用
**你只需要**:等待构建完成,下载单文件,直接运行!✨