# CoinVision Flutter App
## 版本信息
####  flutter sdk 3.41.4
####  Dart 3.11.1
####  DevTools: 2.54.1

## 自动化脚本

项目提供两个发版脚本,位于 `scripts/` 目录:

| 脚本 | 作用 |
|---|---|
| [scripts/bump-version.sh](scripts/bump-version.sh) | 升级版本号（同步 `pubspec.yaml` 和 `app_config.dart`） |
| [scripts/build.sh](scripts/build.sh) | 自动打包 Android/iOS Release,归档产物和调试符号 |

### 一键发版流程

```bash
./scripts/bump-version.sh patch   # 升级修订号 (4.0.3 → 4.0.4)
./scripts/build.sh                # 同时构建 Android + iOS Release
git add pubspec.yaml lib/core/config/app_config.dart
git commit -m "chore(release): bump version to 4.0.4"
git tag v4.0.4
```

## 版本修改

版本号存放在两处,**必须保持同步**:

- `pubspec.yaml` → `version: x.y.z+versionCode`（Android/iOS 构建系统读取）
- `lib/core/config/app_config.dart` → `appVersion = 'x.y.z'`（Dart 运行时读取,用于后端上报和 UI 展示）

**versionCode 规则**: `major × 10000 + minor × 100 + patch`
- 例如 4.0.3 → 40003,4.1.0 → 40100,5.0.0 → 50000
- 修订号/次版本号不能超过 99,否则与下一级 versionCode 冲突
- Android 严禁 versionCode 回退,系统会拒绝安装

### 使用脚本自动升级（推荐）

```bash
./scripts/bump-version.sh --show        # 显示当前版本
./scripts/bump-version.sh patch         # 4.0.3 → 4.0.4
./scripts/bump-version.sh minor         # 4.0.3 → 4.1.0
./scripts/bump-version.sh major         # 4.0.3 → 5.0.0
./scripts/bump-version.sh 4.2.1         # 手动指定版本
./scripts/bump-version.sh patch --dry-run   # 预览变更,不写入文件
```

脚本会自动:
- 同步写入 `pubspec.yaml` 和 `app_config.dart`
- 按 `major × 10000 + minor × 100 + patch` 计算 versionCode
- 校验 versionCode 必须严格递增,拒绝回退
- 校验修订号/次版本号不超过 99
- 写入后验证文件内容

### 手动升级

如需手动改,同步修改以下两处即可:

```yaml
# pubspec.yaml (第 4 行)
version: 4.0.4+40004
```

```dart
// lib/core/config/app_config.dart (第 50 行)
static const String appVersion = '4.0.4';
```

## 打包命令

### 使用脚本（推荐）

```bash
./scripts/build.sh                 # 同时构建 Android + iOS Release (默认)
./scripts/build.sh android         # 仅构建 Android Release
./scripts/build.sh android-debug   # 仅构建 Android Debug
./scripts/build.sh ios             # 仅构建 iOS Release
./scripts/build.sh ios-adhoc       # 仅构建 iOS Ad-hoc
./scripts/build.sh --clean         # 构建前执行 flutter clean
```

脚本会自动:
- 从 `pubspec.yaml` 读取版本号
- 构建时开启 Dart 混淆和符号剥离
- 归档 APK/IPA 到 `releases/v<版本>_<时间戳>/`
- 归档 Dart 调试符号到 `releases/.../symbols-android/` 和 `symbols-ios/`
- 生成 `BUILD_INFO.txt` 记录 Git 提交、构建时间等元信息

### 手动命令

#### Android

APK 直装分发，同时覆盖 armeabi-v7a（32 位老机）和 arm64-v8a（64 位新机）。

```bash
# Debug 包（包名 com.ibit.app.test，使用 env_debug.dart 接口地址）
flutter build apk --debug --target-platform android-arm,android-arm64

# Release 包（包名 com.ibit.app，使用 env_release.dart 接口地址，正式签名）
flutter build apk --release \
  --target-platform android-arm,android-arm64 \
  --obfuscate \
  --split-debug-info=build/debug-info/android
```

说明：
- `--target-platform android-arm,android-arm64`：同时打包 32/64 位，兼容 2018 年前老机
- `--obfuscate` + `--split-debug-info`：Dart 符号混淆 + 剥离调试信息，减小包体并提升反编译难度
- **不加** `--no-tree-shake-icons`：让 Flutter 对 `MaterialIcons-Regular.otf` / `CupertinoIcons.ttf` 做 tree-shake，字体从 ~1.6 MB 缩到 ~30 KB

产物位置：`build/app/outputs/flutter-apk/app-release.apk`

ADB 安装：
```bash
adb install build/app/outputs/flutter-apk/app-release.apk
```

> **重要**：`build/debug-info/android/` 下的 `.symbols` 文件务必与 APK 一起归档，否则无法反混淆线上 Crashlytics 崩溃栈。

#### iOS

```bash
# Debug 包（模拟器/真机调试，使用 env_debug.dart 接口地址）
flutter run

# ad-hoc 分发包
flutter build ipa --release --export-method=ad-hoc \
  --obfuscate \
  --split-debug-info=build/debug-info/ios

# Release 包（App Store / TestFlight）
flutter build ipa --release \
  --obfuscate \
  --split-debug-info=build/debug-info/ios
```

说明：
- iOS 与 Android 的 `--split-debug-info` 目录**必须分开**（`ios/` vs `android/`），否则互相覆盖
- 符号文件同样需要随 IPA 归档，用于线上崩溃栈反混淆

产物位置：`build/ios/ipa/*.ipa`

---

## 环境配置

接口地址按 debug/release 自动切换，配置文件：

| 环境 | 配置文件 | 触发条件 |
|------|---------|---------|
| 测试 | `lib/core/config/env_debug.dart` | `flutter run` / `flutter build --debug` |
| 生产 | `lib/core/config/env_release.dart` | `flutter build --release` |

也可通过 `--dart-define` 临时覆盖：
```bash
flutter run --dart-define=API_BASE_URL=https://custom.api.com/api/
```

---

## 包名 & Bundle ID

| 平台 | Debug | Release |
|------|-------|---------|
| Android | `com.ibit.app.test` | `com.ibit.app` |
| iOS | `com.ibit.app` | `com.ibit.app` |

Android debug/release 可同时安装在同一台设备上。

---

## 版本号

在 `pubspec.yaml` 第 4 行修改：

```yaml
version: 4.0.3+40003
#        ^^^^^  ^^^^^
#        |      └── versionCode（Android）/ build number（iOS）
#        └── versionName / CFBundleShortVersionString
```

versionCode 编码规则：`主版本×10000 + 次版本×100 + 修订号`
- 例如 4.0.3 → 40003，4.1.0 → 40100

> Android 不允许安装 versionCode 更低的包，递增即可。

---

## 签名

### Android
- 签名文件：`android/app/keystore`（PKCS12 格式）
- 密码配置：`android/key.properties`（已加入 .gitignore）
- Release 自动使用正式签名，Debug 使用系统 debug keystore

### iOS
- 通过 Xcode 自动签名管理

---

## 清理重建

遇到构建异常时：
```bash
flutter clean && flutter pub get
```
