diff --git a/Doc/IM_App_架构设计.html b/Doc/IM_App_架构设计.html index c69ff14..bfedfb8 100644 --- a/Doc/IM_App_架构设计.html +++ b/Doc/IM_App_架构设计.html @@ -1400,7 +1400,7 @@ flowchart LR
实际案例(UUTalk):
+实际案例:
// 整个 Container 都会重建
Obx(() => Container(
@@ -1636,7 +1636,7 @@ Get.put<BaseController>(ChatController());
final controller = Get.find<UserController>(); // 找到 ChatController,类型不匹配!
-运行时错误案例(UUTalk 实际问题):
+运行时错误案例:
真实案例警示
-以下内容基于 UUTalk 项目的实际经验,展示了 GetX + Obx 在大型项目中暴露的严重问题。
+典型问题示例
+以下内容展示了 GetX + Obx 在大型项目中暴露的典型问题,作为选型参考。
UUTalk 项目的 GetX + Obx 问题代码(chat_list_controller.dart):
+GetX + Obx 问题代码示例(chat_list_controller.dart):
class ChatListController extends GetxController {
var lastClickedSpecialChatId = (-1).obs;
@@ -1728,7 +1728,7 @@ ChatViewModel
2. 过度嵌套和性能问题
-UUTalk 项目的 Obx 嵌套地狱(home_view.dart):
+Obx 嵌套地狱示例(home_view.dart):
body: Obx(() => AnimatedPadding(
child: GetBuilder(
@@ -1765,7 +1765,7 @@ ChatViewModel
3. Controller 过于臃肿
-UUTalk 项目的巨型 Controller:
+巨型 Controller 反模式示例:
// chat_list_controller.dart
import 'dart:async';
@@ -1811,7 +1811,7 @@ class ChatListController extends GetxController
4. 没有编译时安全
-UUTalk 项目的运行时陷阱:
+GetX 运行时陷阱:
// 通过字符串查找 Controller,运行时才知道对错
Get.find<ChatListController>();
@@ -1839,7 +1839,7 @@ class ChatListController extends GetxController {
5. 难以测试
-UUTalk 项目的测试困境:
+GetX 测试困境:
// 测试时必须初始化整个 GetX 框架
testWidgets('test chat list', (tester) async {
@@ -1865,7 +1865,7 @@ testWidgets('test chat list', (tester) async {
-GetX + Obx vs Riverpod 实际对比(基于 UUTalk 项目经验)
+GetX + Obx vs Riverpod 实际对比
@@ -1933,7 +1933,7 @@ testWidgets('test chat list', (tester) async {
-GetX + Obx(UUTalk 现状)
+GetX + Obx
状态混乱:
class ChatListController extends GetxController {
@@ -1999,10 +1999,10 @@ class ChatListViewModel extends StateNotifier<ChatListState> {
-UUTalk 项目的痛点总结
+GetX + Obx 痛点总结
-从 UUTalk 项目的实际经验中,我们总结出 GetX + Obx 的核心问题:
+从实践经验中,我们总结出 GetX + Obx 的核心问题:
- "快速开发"变成"技术债":初期确实快,但 6 个月后代码无法维护
- "响应式"变成"性能杀手":Obx 嵌套导致过度重建,页面卡顿
@@ -2014,7 +2014,7 @@ class ChatListViewModel extends StateNotifier<ChatListState> {
Riverpod 的技术优势
-基于 UUTalk 项目的实践教训,我们选择 Riverpod 作为新架构的状态管理方案,因为它从根本上解决了 GetX 的所有问题:
+基于以上实践教训,我们选择 Riverpod 作为新架构的状态管理方案,因为它从根本上解决了 GetX 的所有问题:
- 编译时安全:不会再有运行时崩溃
- 结构化状态:@freezed 强制统一状态结构
diff --git a/scripts/build_android.sh b/scripts/build_android.sh
index 3c01780..cf6274b 100755
--- a/scripts/build_android.sh
+++ b/scripts/build_android.sh
@@ -47,6 +47,7 @@ if [ "$FORMAT" = "aab" ]; then
cd "$APP_DIR"
flutter build appbundle \
--release \
+ --no-pub \
--dart-define-from-file=config/config.json \
--split-debug-info="$DEBUG_INFO_DIR" \
--obfuscate
@@ -57,6 +58,7 @@ else
cd "$APP_DIR"
flutter build apk \
--release \
+ --no-pub \
--dart-define-from-file=config/config.json \
--split-debug-info="$DEBUG_INFO_DIR" \
--obfuscate
diff --git a/scripts/build_ios.sh b/scripts/build_ios.sh
index bcf2b60..b0c5106 100644
--- a/scripts/build_ios.sh
+++ b/scripts/build_ios.sh
@@ -41,6 +41,7 @@ cd "$APP_DIR"
flutter build ipa \
--release \
+ --no-pub \
--dart-define-from-file=config/config.json \
--split-debug-info="$DEBUG_INFO_DIR" \
--obfuscate
diff --git a/scripts/build_macos.sh b/scripts/build_macos.sh
index 4ffef82..26f30b1 100644
--- a/scripts/build_macos.sh
+++ b/scripts/build_macos.sh
@@ -37,6 +37,7 @@ cd "$APP_DIR"
flutter build macos \
--release \
+ --no-pub \
--dart-define-from-file=config/config.json \
--split-debug-info="$DEBUG_INFO_DIR" \
--obfuscate
diff --git a/scripts/build_windows.sh b/scripts/build_windows.sh
index d59d24c..44916ed 100644
--- a/scripts/build_windows.sh
+++ b/scripts/build_windows.sh
@@ -39,6 +39,7 @@ cd "$APP_DIR"
flutter build windows \
--release \
+ --no-pub \
--dart-define-from-file=config/config.json \
--split-debug-info="$DEBUG_INFO_DIR" \
--obfuscate
diff --git a/scripts/pre-commit b/scripts/pre-commit
new file mode 100644
index 0000000..7502da0
--- /dev/null
+++ b/scripts/pre-commit
@@ -0,0 +1,60 @@
+#!/bin/bash
+# Git pre-commit hook:提交前自动 format,analyze 有 error 则拦截提交
+#
+# 安装:bash scripts/setup.sh(setup.sh 自动把本文件复制到 .git/hooks/pre-commit)
+# 手动安装:cp scripts/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
+
+set -euo pipefail
+
+ROOT_DIR="$(git rev-parse --show-toplevel)"
+DART="$(command -v dart 2>/dev/null || echo "")"
+
+if [[ -z "$DART" ]]; then
+ echo "[pre-commit] dart not found, skipping checks."
+ exit 0
+fi
+
+# ── pubspec.lock 保护 ────────────────────────────────────────────────────────
+# flutter run / flutter build 会在未经授权的情况下触发 pub get 并修改 lock。
+# 规则:lock 有未暂存的改动(意外修改)→ 自动还原;
+# 开发者主动 git add pubspec.lock 后(暂存)→ 正常放行。
+LOCK_UNSTAGED=$(git diff --name-only pubspec.lock 2>/dev/null || true)
+LOCK_STAGED=$(git diff --cached --name-only pubspec.lock 2>/dev/null || true)
+
+if [[ -n "$LOCK_UNSTAGED" && -z "$LOCK_STAGED" ]]; then
+ git checkout HEAD -- pubspec.lock
+ echo "[pre-commit] pubspec.lock was auto-modified by flutter, restored to HEAD."
+ echo " To intentionally update: run 'dart pub get' or 'dart pub upgrade',"
+ echo " then 'git add pubspec.lock' before committing."
+fi
+
+# ── dart format + analyze ────────────────────────────────────────────────────
+STAGED_DART=$(git diff --cached --name-only --diff-filter=ACM | grep '\.dart$' || true)
+
+if [[ -z "$STAGED_DART" ]]; then
+ exit 0
+fi
+
+echo "[pre-commit] formatting staged dart files..."
+echo "$STAGED_DART" | xargs dart format --line-length=80
+echo "$STAGED_DART" | xargs git add
+
+echo "[pre-commit] running dart analyze..."
+cd "$ROOT_DIR"
+
+ANALYZE_OUTPUT=$(dart analyze 2>&1)
+
+if echo "$ANALYZE_OUTPUT" | grep -q "^ error"; then
+ echo "[pre-commit] dart analyze found errors, commit blocked."
+ echo "$ANALYZE_OUTPUT" | grep "^ error"
+ exit 1
+fi
+
+if echo "$ANALYZE_OUTPUT" | grep -q "^ warning"; then
+ echo "[pre-commit] dart analyze found warnings, commit blocked."
+ echo "$ANALYZE_OUTPUT" | grep "^ warning"
+ exit 1
+fi
+
+echo "[pre-commit] all checks passed."
+exit 0
diff --git a/scripts/setup.sh b/scripts/setup.sh
index a63e951..50d9e3a 100755
--- a/scripts/setup.sh
+++ b/scripts/setup.sh
@@ -28,13 +28,13 @@ echo "=== customer-im-client 环境初始化 ==="
echo ""
# ---- Step 1: 安装全局工具 ----
-echo "[1/6] 安装全局工具 (melos + mason_cli)..."
+echo "[1/7] 安装全局工具 (melos + mason_cli)..."
dart pub global activate melos
dart pub global activate mason_cli
echo ""
# ---- Step 2: 配置 PATH ----
-echo "[2/6] 配置 PATH..."
+echo "[2/7] 配置 PATH..."
if [[ "$SHELL" == */zsh ]]; then
SHELL_CONFIG="$HOME/.zshrc"
elif [[ "$SHELL" == */bash ]]; then
@@ -78,12 +78,19 @@ if [ -f "$ROOT_DIR/mason-lock.json" ]; then
fi
# ---- Step 5: 注册 mason bricks ----
-echo "[5/6] mason get (注册本地 bricks)..."
+echo "[5/7] mason get (注册本地 bricks)..."
cd "$ROOT_DIR" && "$PUB_CACHE_BIN/mason" get
echo ""
+echo "[6/7] mason add clean_plugin_sdk bricks..."
+if ! grep -qE '^\s*clean_plugin_sdk:' "$ROOT_DIR/mason.yaml" 2>/dev/null; then
+ cd "$ROOT_DIR" && "$PUB_CACHE_BIN/mason" add clean_plugin_sdk --path ./mason/bricks/clean_plugin_sdk
+else
+ echo " clean_plugin_sdk 已在 mason.yaml 中,跳過"
+fi
+
# ---- Step 6: 首次代码生成 ----
-echo "[6/6] melos run gen (首次代码生成)..."
+echo "[7/7] melos run gen (首次代码生成)..."
cd "$ROOT_DIR" && "$PUB_CACHE_BIN/melos" run gen
echo ""