浏览代码

上传相关部署文档

yangjia 2 小时之前
父节点
当前提交
d47e97b355
共有 3 个文件被更改,包括 347 次插入1 次删除
  1. 208 0
      README.md
  2. 1 1
      pubspec.yaml
  3. 138 0
      部署文档.md

+ 208 - 0
README.md

@@ -0,0 +1,208 @@
+# 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
+```

+ 1 - 1
pubspec.yaml

@@ -1,7 +1,7 @@
 name: cex_skeleton
 description: iBit — 加密货币交易 App
 publish_to: 'none'
-version: 4.1.4+40104
+version: 4.1.5+40105
 
 
 environment:

+ 138 - 0
部署文档.md

@@ -0,0 +1,138 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project
+
+CoinVision — a production cryptocurrency exchange (CEX) Flutter app targeting Android and iOS.
+
+## Commands
+
+```bash
+# Run
+flutter run
+
+# Build
+flutter build apk --debug --target-platform android-arm64   # Android debug
+flutter build apk --release --target-platform android-arm64 # Android release
+flutter build ipa --release --export-method=ad-hoc          # iOS ad-hoc
+flutter build ipa --release                                   # iOS release
+
+# Code generation (required after model/provider changes)
+dart run build_runner build --delete-conflicting-outputs
+dart run build_runner watch   # watch mode
+
+# Format & analyze
+dart format .
+flutter analyze
+
+# Test
+flutter test
+
+# Reset
+flutter clean && flutter pub get
+```
+
+### Runtime overrides via `--dart-define`
+```bash
+flutter run --dart-define=API_BASE_URL=https://custom.api.com/api/
+flutter run --dart-define=WS_URL=wss://custom.ws.com/market
+flutter run --dart-define=ENABLE_MOCK=true
+```
+
+## Architecture
+
+Strict 3-layer clean architecture. **Never bypass layers.**
+
+```
+用户交互 → Notifier → Repository → Service/API
+                                        ↓
+UI (Widget) ←── State (immutable) ←── Notifier ←──
+```
+
+| Layer | Location | Responsibility |
+|-------|----------|----------------|
+| **Presentation** | `lib/presentation/` | Rendering & user interaction only. No business logic. |
+| **Provider (ViewModel)** | `lib/providers/` | Riverpod Notifiers. Expose immutable State + methods. |
+| **Data** | `lib/data/` | Services (stateless HTTP), Repositories (SSOT, caching), Models (Freezed) |
+| **Core** | `lib/core/` | Dio client, GoRouter, theme, l10n, utils. No business logic. |
+
+### State Management — Riverpod 2
+- Use `@riverpod` annotation for code generation
+- State objects must be **immutable Freezed classes**, updated with `copyWith`
+- In Widgets: `ref.watch()` for state, `ref.read(…notifier)` for actions
+- Notifier re-initialization: `ref.invalidate(someProvider)`
+
+### Navigation — GoRouter 14
+- All routes defined in `lib/core/router/app_router.dart`
+- StatefulShellRoute with 5 bottom-nav branches (preserves tab state)
+- Auth guard: routes under `/asset`, `/user/*`, `/broker/*` require login
+- Session expiry: API error code `4000` triggers logout dialog
+- **Always use `context.push()` / `context.go()`** — never `Navigator.push`
+
+### Networking — Dio
+- Central client in `lib/core/network/dio_client.dart` with interceptors for token injection, error wrapping, and node failover
+- Multi-node resilience: `lib/providers/node_provider.dart` — speed tests nodes, circuit-breaks after 3 failures for 60s
+- Timeouts: connect 15s, receive 15s
+- Session error (code 4000) → auto logout; interceptor suppresses duplicate navigation
+
+### Data Models — Freezed
+- All domain models use `@freezed` with `fromJson`/`toJson`
+- Run `build_runner` after any model or provider annotation change
+- Generated files (`*.freezed.dart`, `*.g.dart`) are committed
+
+### Storage
+| Data | Storage |
+|------|---------|
+| Auth tokens | `flutter_secure_storage` (platform vault) |
+| User preferences | `SharedPreferences` |
+| Local caching | Hive |
+
+### Real-time Data — WebSocket
+- `web_socket_channel` for market data streams
+- Lifecycle managed in `lib/providers/ws_provider.dart`
+- Manual reconnect logic on disconnect
+
+## Key Conventions
+
+### New feature development order (required)
+1. Define Freezed domain model (`data/models/`)
+2. Implement Service — stateless HTTP only (`data/services/`)
+3. Implement Repository — SSOT, caching, data transform (`data/repositories/`)
+4. Implement Notifier — Freezed State + methods (`providers/`)
+5. Implement Screen/Widget — ConsumerWidget, 3-state UI (`presentation/`)
+
+### UI rules
+- Widgets use `ConsumerWidget` or `ConsumerStatefulWidget`
+- Always handle **loading / error / empty** three states
+- Use `AppColors` — rise: `#0ecb81`, fall: `#f6465d`
+- Use `formatPrice()` / `formatChange()` from `core/utils/` — never hardcode decimal places
+- Layout scaled with `flutter_screenutil` (design base: 375×812)
+- Use `ListView.builder` for lists; `const` constructors for static sub-widgets
+- BottomSheets via `showModalBottomSheet` with `isScrollControlled: true`
+
+### Localization
+5 locales: `zh`, `zh_TW`, `en`, `ja`, `ko`. ARB files in `lib/core/l10n/`. Config in `l10n.yaml`.
+
+### Environment / Build
+- Debug config: `lib/core/config/env_debug.dart`, Android package `com.ibit.app.test`
+- Release config: `lib/core/config/env_release.dart`, Android package `com.ibit.app`
+- Android signing: keystore at `android/app/keystore`, password in `android/key.properties` (gitignored)
+- Version format in `pubspec.yaml`: `major.minor.patch+major*10000+minor*100+patch`
+
+## Git Commit Convention
+
+`<type>(<scope>): <subject>` (Conventional Commits)
+
+Scopes: `auth`, `market`, `trading`, `futures`, `asset`, `user`, `core`, `widget`, `l10n`
+
+Use `/commit` skill to generate commit messages. Only commit locally — do not push unless explicitly asked.
+
+## Pre-commit Checklist
+
+- `dart format .` — no errors
+- `flutter analyze` — no errors or warnings
+- No `print()` / `debugPrint()` left in code
+- `build_runner` output is up to date
+- State is immutable Freezed; updated via `copyWith`
+- Tokens stored in `flutter_secure_storage`, not `SharedPreferences`