瀏覽代碼

feat: 初始化新大洲Android项目

- 项目架构:MVVM + Clean Architecture
- 基础模块:base-core, base-common
- 能力模块:BLE, NFC, Push, QRCode, Share, SocketIO
- 分享功能:集成友盟分享SDK,支持微信、QQ、微博等平台
- 推送功能:集成极光推送SDK
- 用户系统:登录、注册、Token管理
- 版本管理:自动检查更新功能

技术栈:
- Kotlin
- AndroidX
- Navigation Component
- Retrofit + OkHttp
- Coroutines + Flow
wangmeng 2 月之前
當前提交
945d7e9368
共有 100 個文件被更改,包括 10496 次插入0 次删除
  1. 138 0
      .gitignore
  2. 648 0
      DEVELOPMENT_GUIDE.md
  3. 792 0
      MVVM_ARCHITECTURE.md
  4. 360 0
      PROJECT_STRUCTURE.md
  5. 166 0
      app/build.gradle
  6. 22 0
      app/proguard-rules.pro
  7. 93 0
      app/src/main/AndroidManifest.xml
  8. 141 0
      app/src/main/java/com/narutohuo/xindazhou/MainActivity.kt
  9. 39 0
      app/src/main/java/com/narutohuo/xindazhou/XinDaZhouApplication.kt
  10. 45 0
      app/src/main/java/com/narutohuo/xindazhou/common/main/ui/MainFragment.kt
  11. 25 0
      app/src/main/java/com/narutohuo/xindazhou/common/version/datasource/remote/VersionApi.kt
  12. 17 0
      app/src/main/java/com/narutohuo/xindazhou/common/version/model/VersionInfo.kt
  13. 59 0
      app/src/main/java/com/narutohuo/xindazhou/common/version/repository/VersionRepository.kt
  14. 61 0
      app/src/main/java/com/narutohuo/xindazhou/common/version/ui/UpdateDialog.kt
  15. 30 0
      app/src/main/java/com/narutohuo/xindazhou/community/ui/CommunityFragment.kt
  16. 30 0
      app/src/main/java/com/narutohuo/xindazhou/service/ui/ServiceFragment.kt
  17. 30 0
      app/src/main/java/com/narutohuo/xindazhou/shop/ui/ShopFragment.kt
  18. 46 0
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/local/AuthLocalDataSource.kt
  19. 108 0
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/local/TokenManager.kt
  20. 28 0
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/remote/AuthApi.kt
  21. 61 0
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/remote/AuthRemoteDataSource.kt
  22. 10 0
      app/src/main/java/com/narutohuo/xindazhou/user/model/LoginRequest.kt
  23. 17 0
      app/src/main/java/com/narutohuo/xindazhou/user/model/LoginResponse.kt
  24. 10 0
      app/src/main/java/com/narutohuo/xindazhou/user/model/RegisterRequest.kt
  25. 80 0
      app/src/main/java/com/narutohuo/xindazhou/user/repository/AuthRepository.kt
  26. 149 0
      app/src/main/java/com/narutohuo/xindazhou/user/repository/SocketIORepository.kt
  27. 17 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/constant/UiConstants.kt
  28. 156 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/login/LoginFragment.kt
  29. 141 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/profile/UserFragment.kt
  30. 119 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/register/RegisterFragment.kt
  31. 68 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/LoginViewModel.kt
  32. 23 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/LoginViewModelFactory.kt
  33. 68 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/RegisterViewModel.kt
  34. 23 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/RegisterViewModelFactory.kt
  35. 184 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/UserViewModel.kt
  36. 23 0
      app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/UserViewModelFactory.kt
  37. 910 0
      app/src/main/java/com/narutohuo/xindazhou/vehicle/ui/VehicleFragment.kt
  38. 22 0
      app/src/main/res/layout/activity_main.xml
  39. 191 0
      app/src/main/res/layout/dialog_update.xml
  40. 141 0
      app/src/main/res/layout/fragment_login.xml
  41. 34 0
      app/src/main/res/layout/fragment_main.xml
  42. 122 0
      app/src/main/res/layout/fragment_register.xml
  43. 65 0
      app/src/main/res/layout/fragment_user_socket_test.xml
  44. 725 0
      app/src/main/res/layout/fragment_vehicle.xml
  45. 28 0
      app/src/main/res/menu/bottom_navigation_menu.xml
  46. 6 0
      app/src/main/res/mipmap-anydpi/ic_launcher.xml
  47. 6 0
      app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
  48. 43 0
      app/src/main/res/navigation/main_nav_graph.xml
  49. 43 0
      app/src/main/res/navigation/nav_graph.xml
  50. 6 0
      app/src/main/res/values/colors.xml
  51. 30 0
      app/src/main/res/values/strings.xml
  52. 13 0
      app/src/main/res/values/themes.xml
  53. 12 0
      app/src/main/res/xml/file_paths.xml
  54. 16 0
      app/src/main/res/xml/network_security_config.xml
  55. 53 0
      base-common/build.gradle
  56. 3 0
      base-common/src/main/AndroidManifest.xml
  57. 78 0
      base-common/src/main/java/com/narutohuo/xindazhou/common/config/ServerConfigManager.kt
  58. 74 0
      base-common/src/main/java/com/narutohuo/xindazhou/common/dialog/ServerConfigDialog.kt
  59. 114 0
      base-common/src/main/java/com/narutohuo/xindazhou/common/network/ApiResponseParser.kt
  60. 145 0
      base-common/src/main/java/com/narutohuo/xindazhou/common/network/HttpApiClient.kt
  61. 61 0
      base-common/src/main/res/layout/dialog_server_config.xml
  62. 31 0
      base-core/build.gradle
  63. 3 0
      base-core/src/main/AndroidManifest.xml
  64. 23 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/bridge/IBridge.kt
  65. 30 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/config/IConfig.kt
  66. 31 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/executor/IExecutor.kt
  67. 204 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/log/ILog.kt
  68. 66 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/log/impl/NoOpLog.kt
  69. 75 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/log/impl/TimberLog.kt
  70. 29 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/storage/IStorage.kt
  71. 30 0
      base-core/src/main/java/com/narutohuo/xindazhou/core/util/IUtil.kt
  72. 6 0
      build.gradle
  73. 30 0
      capability-ble/build.gradle
  74. 12 0
      capability-ble/src/main/AndroidManifest.xml
  75. 149 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/api/BLEService.kt
  76. 69 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/callback/BLECallback.kt
  77. 181 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/config/BLEConstants.kt
  78. 42 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/factory/BLEServiceFactory.kt
  79. 915 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/impl/BLEServiceImpl.kt
  80. 79 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLECommand.kt
  81. 29 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEDevice.kt
  82. 85 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEPacket.kt
  83. 61 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEResponse.kt
  84. 73 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLECrypto.kt
  85. 116 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketBuilder.kt
  86. 94 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketParser.kt
  87. 110 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketSplitter.kt
  88. 137 0
      capability-ble/业务模块调用示例.md
  89. 496 0
      capability-ble/使用说明-单例模式.md
  90. 30 0
      capability-nfc/build.gradle
  91. 13 0
      capability-nfc/src/main/AndroidManifest.xml
  92. 64 0
      capability-nfc/src/main/java/com/narutohuo/xindazhou/nfc/api/NFCService.kt
  93. 107 0
      capability-nfc/src/main/java/com/narutohuo/xindazhou/nfc/impl/NFCServiceImpl.kt
  94. 61 0
      capability-nfc/src/main/java/com/narutohuo/xindazhou/nfc/model/NFCResponse.kt
  95. 47 0
      capability-push/build.gradle
  96. 二進制
      capability-push/libs/jcore-5.2.0.aar
  97. 二進制
      capability-push/libs/jcore-android-5.2.0.jar
  98. 二進制
      capability-push/libs/jpush-5.9.0.aar
  99. 二進制
      capability-push/libs/jpush-android-5.9.0.jar
  100. 0 0
      capability-push/src/main/AndroidManifest.xml

+ 138 - 0
.gitignore

@@ -0,0 +1,138 @@
+# Built application files
+*.apk
+*.aar
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+release/
+
+# Gradle files
+.gradle/
+build/
+*/build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+*.properties
+!gradle.properties
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+.idea/caches
+.idea/modules.xml
+.idea/navEditor.xml
+.idea/replScope.xml
+
+# Keystore files
+*.jks
+*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+# Android Profiling
+*.hprof
+
+# Mac
+.DS_Store
+**/.DS_Store
+
+# Windows
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+
+# Linux
+*~
+
+# Temporary files
+*.swp
+*.swo
+*~
+*.tmp
+*.bak
+*.log
+
+# Package Files
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# SDK files - keep libs directory structure but ignore temp files
+# Note: We need to keep SDK jar/aar files in libs directories
+!**/libs/
+**/libs/*.jar
+**/libs/*.aar
+!capability-push/libs/
+!capability-push/libs/*.jar
+!capability-push/libs/*.aar
+!capability-share/libs/
+!capability-share/libs/*.jar
+!capability-share/libs/*.aar
+
+# Kotlin
+*.kotlin_module
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
+
+# Temporary files
+capability-share.zip
+*.zip

+ 648 - 0
DEVELOPMENT_GUIDE.md

@@ -0,0 +1,648 @@
+# 新大洲 Android 开发规范
+
+> 本规范基于阿里巴巴《Java开发手册》和 Android 开发最佳实践制定
+
+## 目录
+
+- [一、编程规约](#一编程规约)
+  - [1.1 命名风格](#11-命名风格)
+  - [1.2 常量定义](#12-常量定义)
+  - [1.3 代码格式](#13-代码格式)
+  - [1.4 OOP规约](#14-oop规约)
+  - [1.5 集合处理](#15-集合处理)
+  - [1.6 控制语句](#16-控制语句)
+  - [1.7 注释规约](#17-注释规约)
+- [二、异常日志](#二异常日志)
+  - [2.1 异常处理](#21-异常处理)
+  - [2.2 日志规约](#22-日志规约)
+- [三、安全规约](#三安全规约)
+- [四、Android 专项规范](#四android-专项规范)
+- [五、Kotlin 专项规范](#五kotlin-专项规范)
+
+---
+
+## 一、编程规约
+
+### 1.1 命名风格
+
+#### 【强制】类名使用 UpperCamelCase 风格
+
+**正例:**
+```kotlin
+class LoginViewModel
+class AuthRepository
+class UserFragment
+```
+
+**反例:**
+```kotlin
+class loginViewModel  // ❌ 首字母小写
+class Auth_Repository  // ❌ 使用下划线
+```
+
+#### 【强制】方法名、参数名、成员变量、局部变量统一使用 lowerCamelCase 风格
+
+**正例:**
+```kotlin
+fun login(mobile: String, password: String)
+private val loginState: StateFlow<LoginState>
+val userRepository: UserRepository
+```
+
+**反例:**
+```kotlin
+fun Login()  // ❌ 首字母大写
+fun get_user_info()  // ❌ 使用下划线
+```
+
+#### 【强制】常量命名全部大写,单词间用下划线隔开
+
+**正例:**
+```kotlin
+companion object {
+    const val MAX_PASSWORD_LENGTH = 16
+    const val MIN_PASSWORD_LENGTH = 6
+    const val SUCCESS_CODE = 0
+}
+```
+
+**反例:**
+```kotlin
+const val maxPasswordLength = 16  // ❌ 应该大写
+const val SUCCESS_CODE = 0  // ✅ 正确
+const val SuccessCode = 0  // ❌ 应该全大写+下划线
+```
+
+#### 【强制】抽象类命名使用 Abstract 或 Base 开头
+
+**正例:**
+```kotlin
+abstract class BaseViewModel
+abstract class BaseRepository
+abstract class BaseFragment
+```
+
+### 1.2 常量定义
+
+#### 【强制】不允许任何魔法值(即未经定义的常量)直接出现在代码中
+
+**反例:**
+```kotlin
+// ❌ 错误示例
+if (commonResult.code != 0) {  // 魔法数字 0
+    // ...
+}
+
+if (password.length < 4 || password.length > 16) {  // 魔法数字 4, 16
+    // ...
+}
+```
+
+**正例:**
+```kotlin
+// ✅ 正确示例
+object ApiConstants {
+    /** 成功状态码 */
+    const val SUCCESS_CODE = 0
+}
+
+object ValidationConstants {
+    /** 密码最小长度 */
+    const val MIN_PASSWORD_LENGTH = 6
+    
+    /** 密码最大长度 */
+    const val MAX_PASSWORD_LENGTH = 16
+}
+
+// 使用
+if (commonResult.code != ApiConstants.SUCCESS_CODE) {
+    // ...
+}
+
+if (password.length < ValidationConstants.MIN_PASSWORD_LENGTH 
+    || password.length > ValidationConstants.MAX_PASSWORD_LENGTH) {
+    // ...
+}
+```
+
+#### 【推荐】常量应该按功能分组,定义在对应的 Constants 类中
+
+**目录结构:**
+```
+module/
+├── data/
+│   └── constant/
+│       └── ApiConstants.kt      # API 相关常量
+├── domain/
+│   └── constant/
+│       └── ValidationConstants.kt  # 验证相关常量
+└── ui/
+    └── constant/
+        └── UiConstants.kt       # UI 相关常量
+```
+
+**示例:**
+```kotlin
+// user/data/constant/ApiConstants.kt
+package com.narutohuo.xindazhou.user.data.constant
+
+/**
+ * API 相关常量
+ */
+object ApiConstants {
+    /** 成功状态码 */
+    const val SUCCESS_CODE = 0
+    
+    /** 请求超时时间(秒) */
+    const val TIMEOUT_SECONDS = 30
+}
+
+// user/ui/constant/UiConstants.kt
+package com.narutohuo.xindazhou.user.ui.constant
+
+/**
+ * UI 相关常量
+ */
+object UiConstants {
+    /** 提示信息 */
+    const val MSG_MOBILE_EMPTY = "请输入手机号"
+    const val MSG_PASSWORD_EMPTY = "请输入密码"
+    const val MSG_LOGIN_SUCCESS = "登录成功"
+    const val MSG_LOGIN_FAILED = "登录失败"
+}
+```
+
+### 1.3 代码格式
+
+#### 【强制】大括号的使用约定
+
+**正例:**
+```kotlin
+// 如果大括号内为空,则简洁地写成 {} 即可
+fun emptyFunction() {}
+
+// 如果大括号内非空,则:
+// 1) 左大括号前不换行
+// 2) 左大括号后换行
+// 3) 右大括号前换行
+// 4) 右大括号后还有 else 等代码则不换行
+if (condition) {
+    statements
+} else {
+    statements
+}
+```
+
+#### 【强制】单行字符数限制不超过 120 个
+
+超出需要换行,换行时遵循以下原则:
+- 第二行相对第一行缩进 4 个空格
+- 运算符与下文一起换行
+- 方法调用的点符号与下文一起换行
+
+**正例:**
+```kotlin
+val result = repository.getUserInfo(mobile = mobile, 
+    password = password, 
+    deviceId = deviceId)
+
+val longString = "这是一个很长的字符串" +
+    "需要换行显示"
+```
+
+### 1.4 OOP规约
+
+#### 【强制】避免通过类的实例对象访问静态成员
+
+**正例:**
+```kotlin
+// 通过类名访问
+ApiConstants.SUCCESS_CODE
+ValidationConstants.MIN_PASSWORD_LENGTH
+```
+
+**反例:**
+```kotlin
+// ❌ 通过实例访问(虽然Kotlin不推荐这样写)
+val constants = ApiConstants()
+constants.SUCCESS_CODE
+```
+
+#### 【推荐】类的成员方法之间、成员变量与成员方法之间,顺序建议按如下顺序排列
+
+1. 伴生对象(companion object)
+2. 常量定义(const val)
+3. 成员变量(属性)
+4. 初始化方法(init)
+5. 公共方法
+6. 私有方法
+
+**示例:**
+```kotlin
+class LoginViewModel(application: Application) : AndroidViewModel(application) {
+    
+    companion object {
+        private const val TAG = "LoginViewModel"
+    }
+    
+    private val authRepository = AuthRepository()
+    private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)
+    val loginState: StateFlow<LoginState> = _loginState
+    
+    fun login(mobile: String, password: String) {
+        // ...
+    }
+    
+    private fun validateInput(mobile: String, password: String): Boolean {
+        // ...
+    }
+}
+```
+
+### 1.5 集合处理
+
+#### 【强制】关于 hashCode 和 equals 的处理,遵循如下规则
+
+- 只要重写 equals,就必须重写 hashCode
+- 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断
+- Map 的 key 也是依据 hashCode 和 equals 进行判断
+
+**正例:**
+```kotlin
+data class User(val id: Long, val name: String) {
+    // data class 会自动生成 equals 和 hashCode
+}
+```
+
+### 1.6 控制语句
+
+#### 【强制】当 switch 语句内的 case 分支数目超过 3 个时,必须使用 when 表达式
+
+**正例:**
+```kotlin
+when (state) {
+    is LoginState.Idle -> { /* ... */ }
+    is LoginState.Loading -> { /* ... */ }
+    is LoginState.Success -> { /* ... */ }
+    is LoginState.Error -> { /* ... */ }
+}
+```
+
+#### 【强制】在高并发场景中,避免使用"等于"判断作为中断或退出的条件
+
+**说明:** 如果并发控制没有处理好,容易产生等值判断被"击穿"的情况,使用大于或小于的区间判断条件来代替。
+
+### 1.7 注释规约
+
+#### 【强制】类、类属性、类方法的注释必须使用 Kotlin 文档注释(/** */)
+
+**正例:**
+```kotlin
+/**
+ * 认证数据仓库
+ * 
+ * 负责统一管理认证相关的数据获取和缓存
+ * 
+ * @author YourName
+ * @date 2024-01-01
+ */
+class AuthRepository {
+    
+    /**
+     * 用户登录
+     * 
+     * @param mobile 手机号(11位数字)
+     * @param password 密码(6-16位字符)
+     * @return Result<LoginResponse> 登录结果,成功包含登录响应数据
+     */
+    suspend fun login(mobile: String, password: String): Result<LoginResponse> {
+        // ...
+    }
+}
+```
+
+#### 【强制】所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释
+
+除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
+
+#### 【推荐】代码修改的同时,注释也要进行相应的修改,特别是参数、返回值、异常、核心逻辑等的修改
+
+---
+
+## 二、异常日志
+
+### 2.1 异常处理
+
+#### 【强制】禁止使用 printStackTrace() 方法打印异常堆栈
+
+**反例:**
+```kotlin
+catch (e: Exception) {
+    e.printStackTrace()  // ❌ 禁止使用
+}
+```
+
+**正例:**
+```kotlin
+catch (e: Exception) {
+    Timber.e(e, "$TAG - login: 登录异常")  // ✅ 使用日志框架
+}
+```
+
+#### 【强制】异常不要被生吞
+
+捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之。
+
+**反例:**
+```kotlin
+try {
+    // ...
+} catch (e: Exception) {
+    // ❌ 空 catch 块
+}
+```
+
+**正例:**
+```kotlin
+try {
+    // ...
+} catch (e: Exception) {
+    Timber.e(e, "$TAG - login: 登录异常")
+    // 记录日志或返回错误结果
+    return Result.failure(e)
+}
+```
+
+#### 【强制】不要在 finally 块中使用 return
+
+#### 【推荐】方法的返回值可以为 null,不强制返回空集合(emptyList)或者空对象等
+
+#### 【推荐】防止 NPE,是程序员的基本修养
+
+**Kotlin 安全调用操作符:**
+
+**反例:**
+```kotlin
+val commonResult = response.body()!!  // ❌ 危险的非空断言
+```
+
+**正例:**
+```kotlin
+val commonResult = response.body() 
+    ?: return Result.failure(Exception("响应体为空"))
+
+// 或者
+response.body()?.let { commonResult ->
+    // 处理逻辑
+} ?: run {
+    return Result.failure(Exception("响应体为空"))
+}
+```
+
+### 2.2 日志规约
+
+#### 【强制】日志框架统一使用 Timber
+
+**正例:**
+```kotlin
+import timber.log.Timber
+
+class AuthRepository {
+    companion object {
+        private const val TAG = "AuthRepository"
+    }
+    
+    suspend fun login(mobile: String, password: String) {
+        Timber.d("$TAG - login: 开始登录,mobile=${mobile.take(3)}***")
+        // ...
+        Timber.d("$TAG - login: 登录成功")
+    }
+}
+```
+
+#### 【强制】日志输出必须使用占位符的方式
+
+**反例:**
+```kotlin
+// ❌ 错误:字符串拼接
+Timber.d("$TAG - login: mobile=$mobile, password=$password")
+```
+
+**正例:**
+```kotlin
+// ✅ 正确:Kotlin 的字符串模板(推荐)
+Timber.d("$TAG - login: mobile=${mobile.take(3)}***, passwordLength=${password.length}")
+
+// ✅ 或者使用 Timber 的格式化(推荐用于敏感信息)
+Timber.d("$TAG - login: 开始登录")
+```
+
+#### 【强制】日志级别说明
+
+- **DEBUG**:调试信息,用于开发调试
+- **INFO**:一般信息,记录程序正常运行的关键信息
+- **WARN**:警告信息,表示可能存在潜在问题
+- **ERROR**:错误信息,表示出现错误但不影响程序继续运行
+- **ASSERT**:断言错误,表示严重的错误
+
+**使用建议:**
+```kotlin
+Timber.d("$TAG - method: 调试信息")  // 开发调试
+Timber.i("$TAG - method: 重要信息")  // 关键业务节点
+Timber.w("$TAG - method: 警告信息")  // 异常但不影响运行
+Timber.e(e, "$TAG - method: 错误信息")  // 错误并记录异常
+```
+
+#### 【强制】日志格式规范
+
+格式:`类名 - 方法名: 消息`
+
+**正例:**
+```kotlin
+Timber.d("$TAG - login: 开始登录")
+Timber.d("$TAG - login: 登录成功")
+Timber.e(e, "$TAG - login: 登录失败")
+```
+
+**反例:**
+```kotlin
+// ❌ 过多装饰符号和emoji
+Timber.d("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
+Timber.d("📝 [注册] 开始注册请求")
+Timber.d("🔐 [注册] 密码长度: ${password.length}")
+```
+
+#### 【推荐】敏感信息脱敏处理
+
+**反例:**
+```kotlin
+Timber.d("$TAG - login: mobile=$mobile, password=$password")  // ❌ 密码不应该打印
+```
+
+**正例:**
+```kotlin
+Timber.d("$TAG - login: mobile=${mobile.take(3)}***, passwordLength=${password.length}")
+```
+
+---
+
+## 三、安全规约
+
+#### 【强制】用户敏感数据必须加密存储
+
+包括但不限于:密码、Token、用户个人信息等。
+
+#### 【强制】用户输入的 SQL 参数严格使用参数绑定或者参数预编译
+
+#### 【推荐】禁止向日志输出用户的密码、Token 等敏感信息
+
+---
+
+## 四、Android 专项规范
+
+### 4.1 Activity/Fragment 规范
+
+#### 【强制】Activity 或 Fragment 中使用 ViewBinding/DataBinding
+
+**正例:**
+```kotlin
+class LoginFragment : Fragment() {
+    private var _binding: FragmentLoginBinding? = null
+    private val binding get() = _binding!!
+    
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        _binding = FragmentLoginBinding.inflate(inflater, container, false)
+        return binding.root
+    }
+    
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
+```
+
+#### 【强制】避免在 Activity/Fragment 中直接处理业务逻辑
+
+业务逻辑应该放在 ViewModel 或 UseCase 中。
+
+### 4.2 ViewModel 规范
+
+#### 【强制】ViewModel 不应该持有 Activity/Fragment 的引用
+
+#### 【推荐】使用 StateFlow/Flow 管理 UI 状态
+
+**正例:**
+```kotlin
+private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)
+val loginState: StateFlow<LoginState> = _loginState
+```
+
+### 4.3 资源文件规范
+
+#### 【强制】字符串资源必须定义在 strings.xml 中
+
+**反例:**
+```kotlin
+Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show()  // ❌
+```
+
+**正例:**
+```kotlin
+// strings.xml
+<string name="login_success">登录成功</string>
+
+// Kotlin代码
+Toast.makeText(context, getString(R.string.login_success), Toast.LENGTH_SHORT).show()
+```
+
+---
+
+## 五、Kotlin 专项规范
+
+### 5.1 空安全
+
+#### 【强制】优先使用 Kotlin 的空安全特性
+
+**正例:**
+```kotlin
+val name: String? = getUserName()
+name?.let {
+    println(it.length)
+}
+```
+
+#### 【强制】禁止滥用 `!!` 非空断言操作符
+
+**反例:**
+```kotlin
+val result = response.body()!!  // ❌ 危险
+```
+
+**正例:**
+```kotlin
+val result = response.body() ?: return Result.failure(Exception("响应体为空"))
+```
+
+### 5.2 协程规范
+
+#### 【推荐】使用 suspend 函数处理异步操作
+
+**正例:**
+```kotlin
+suspend fun login(mobile: String, password: String): Result<LoginResponse> {
+    return withContext(Dispatchers.IO) {
+        // 网络请求
+    }
+}
+```
+
+#### 【强制】在 ViewModel 中使用 viewModelScope
+
+**正例:**
+```kotlin
+fun login(mobile: String, password: String) {
+    viewModelScope.launch {
+        repository.login(mobile, password)
+    }
+}
+```
+
+### 5.3 数据类规范
+
+#### 【推荐】使用 data class 定义数据模型
+
+**正例:**
+```kotlin
+data class LoginRequest(
+    val mobile: String,
+    val password: String
+)
+```
+
+---
+
+## 附录:检查清单
+
+### 代码提交前检查
+
+- [ ] 是否有魔法数字/字符串,已提取为常量
+- [ ] 是否使用了 `!!` 非空断言,已改为安全调用
+- [ ] 异常处理是否使用了日志框架,而不是 printStackTrace
+- [ ] 日志是否遵循格式规范(类名 - 方法名: 消息)
+- [ ] 敏感信息是否已脱敏处理
+- [ ] 代码注释是否完整(类、方法)
+- [ ] 命名是否符合规范(类名大驼峰,方法名小驼峰,常量全大写下划线)
+- [ ] 硬编码字符串是否已提取到资源文件或常量类
+- [ ] 是否有 TODO 未完成,需要补充或删除
+
+---
+
+**文档版本**: v1.0  
+**最后更新**: 2024-01-01  
+**维护者**: 开发团队
+

+ 792 - 0
MVVM_ARCHITECTURE.md

@@ -0,0 +1,792 @@
+# MVVM 四层架构设计文档
+
+> 本文档说明新大洲 Android 项目采用的 MVVM 四层架构设计
+
+## 目录
+
+- [一、架构概述](#一架构概述)
+- [二、四层架构详解](#二四层架构详解)
+- [三、目录结构规范](#三目录结构规范)
+- [四、数据流向](#四数据流向)
+- [五、代码示例](#五代码示例)
+- [六、依赖关系](#六依赖关系)
+- [七、最佳实践](#七最佳实践)
+
+---
+
+## 一、架构概述
+
+### 1.1 架构说明
+
+本项目采用 **MVVM 四层架构**,基于 Clean Architecture 和 Android 架构组件,将代码分为以下四层:
+
+```
+┌─────────────────────────────────────────┐
+│         UI/Presentation 层               │
+│      (Fragment + ViewModel)              │
+└──────────────┬──────────────────────────┘
+               │
+               ▼
+┌─────────────────────────────────────────┐
+│            Domain 层                     │
+│         (UseCase + Model)                │
+└──────────────┬──────────────────────────┘
+               │
+               ▼
+┌─────────────────────────────────────────┐
+│          Repository 层                   │
+│      (数据仓库,统一数据源)                │
+└──────────────┬──────────────────────────┘
+               │
+               ▼
+┌─────────────────────────────────────────┐
+│            Data 层                       │
+│    (Remote + Local DataSource)          │
+└─────────────────────────────────────────┘
+```
+
+### 1.2 架构优势
+
+1. **职责分离**:每一层都有明确的职责,互不干扰
+2. **易于测试**:各层独立,便于单元测试
+3. **可维护性**:代码结构清晰,易于维护和扩展
+4. **可复用性**:Domain 层不依赖 Android 框架,可在其他平台复用
+5. **数据统一**:Repository 层统一管理数据源,处理缓存策略
+
+### 1.3 与传统 MVVM 的区别
+
+**传统三层 MVVM:**
+```
+View → ViewModel → Repository → API
+```
+
+**四层 MVVM(Clean Architecture):**
+```
+View → ViewModel → UseCase → Repository → DataSource
+```
+
+**主要改进:**
+- 新增 **Domain 层**:封装业务逻辑,与 UI 和 Data 解耦
+- 新增 **DataSource 层**:将数据源(Remote/Local)与 Repository 分离
+- 更好的可测试性和可维护性
+
+---
+
+## 二、四层架构详解
+
+### 2.1 UI/Presentation 层
+
+**职责:**
+- 展示 UI,处理用户交互
+- 观察 ViewModel 的状态变化,更新 UI
+- 不包含业务逻辑
+
+**包含内容:**
+- Fragment/Activity
+- ViewModel
+- UI State(Sealed Class)
+
+**依赖关系:**
+- 只依赖 Domain 层(通过 UseCase)
+- 不直接依赖 Data 层
+
+**示例结构:**
+```
+ui/
+├── login/
+│   └── LoginFragment.kt
+├── viewmodel/
+│   ├── LoginViewModel.kt
+│   └── LoginViewModelFactory.kt
+└── state/
+    └── LoginState.kt
+```
+
+### 2.2 Domain 层
+
+**职责:**
+- 封装业务逻辑
+- 定义业务实体模型
+- 定义 UseCase(用例)
+
+**包含内容:**
+- UseCase(用例)
+- Domain Model(业务模型)
+- Repository Interface(可选)
+
+**依赖关系:**
+- 不依赖任何 Android 框架
+- 只依赖 Repository Interface(接口,不依赖实现)
+
+**示例结构:**
+```
+domain/
+├── model/
+│   └── User.kt
+└── usecase/
+    ├── LoginUseCase.kt
+    └── RegisterUseCase.kt
+```
+
+### 2.3 Repository 层
+
+**职责:**
+- 统一数据源管理
+- 协调 Remote 和 Local 数据源
+- 处理数据缓存策略
+- 数据转换(Data Model → Domain Model)
+
+**包含内容:**
+- Repository 实现类
+- 数据转换逻辑
+
+**依赖关系:**
+- 依赖 Domain 层(UseCase)
+- 依赖 Data 层(RemoteDataSource + LocalDataSource)
+
+**示例结构:**
+```
+data/
+└── repository/
+    └── AuthRepository.kt
+```
+
+### 2.4 Data 层
+
+**职责:**
+- 提供数据源接口和实现
+- 处理网络请求(Remote)
+- 处理本地存储(Local)
+- 定义数据模型(Data Model)
+
+**包含内容:**
+- RemoteDataSource(远程数据源)
+- LocalDataSource(本地数据源)
+- Data Model(数据模型)
+- API 接口
+
+**依赖关系:**
+- 只依赖 Android 框架和第三方库
+- 不依赖其他业务层
+
+**示例结构:**
+```
+data/
+├── remote/
+│   └── AuthRemoteDataSource.kt
+├── local/
+│   ├── AuthLocalDataSource.kt
+│   └── TokenManager.kt
+├── model/
+│   ├── LoginRequest.kt
+│   └── LoginResponse.kt
+└── api/
+    └── AuthApi.kt
+```
+
+---
+
+## 三、目录结构规范
+
+### 3.1 模块目录结构
+
+每个功能模块应遵循以下目录结构:
+
+```
+module_name/
+├── ui/                          # UI 层
+│   ├── feature_name/
+│   │   └── FeatureFragment.kt
+│   ├── viewmodel/
+│   │   ├── FeatureViewModel.kt
+│   │   └── FeatureViewModelFactory.kt
+│   └── state/
+│       └── FeatureState.kt
+│
+├── domain/                      # Domain 层
+│   ├── model/
+│   │   └── DomainModel.kt
+│   └── usecase/
+│       └── FeatureUseCase.kt
+│
+├── data/                        # Data 层
+│   ├── repository/
+│   │   └── FeatureRepository.kt
+│   ├── remote/
+│   │   └── FeatureRemoteDataSource.kt
+│   ├── local/
+│   │   └── FeatureLocalDataSource.kt
+│   ├── model/
+│   │   ├── FeatureRequest.kt
+│   │   └── FeatureResponse.kt
+│   └── api/
+│       └── FeatureApi.kt
+│
+├── di/                          # 依赖注入(可选)
+│   └── FeatureModule.kt
+│
+└── constant/                    # 常量(可选)
+    └── FeatureConstants.kt
+```
+
+### 3.2 实际示例(用户模块)
+
+```
+user/
+├── ui/
+│   ├── login/
+│   │   └── LoginFragment.kt
+│   ├── register/
+│   │   └── RegisterFragment.kt
+│   ├── viewmodel/
+│   │   ├── LoginViewModel.kt
+│   │   ├── LoginViewModelFactory.kt
+│   │   ├── RegisterViewModel.kt
+│   │   └── RegisterViewModelFactory.kt
+│   └── state/
+│       ├── LoginState.kt
+│       └── RegisterState.kt
+│
+├── domain/
+│   ├── model/
+│   │   └── User.kt
+│   └── usecase/
+│       ├── LoginUseCase.kt
+│       └── RegisterUseCase.kt
+│
+├── data/
+│   ├── repository/
+│   │   └── AuthRepository.kt
+│   ├── remote/
+│   │   └── AuthRemoteDataSource.kt
+│   ├── local/
+│   │   ├── AuthLocalDataSource.kt
+│   │   └── TokenManager.kt
+│   ├── model/
+│   │   ├── LoginRequest.kt
+│   │   ├── LoginResponse.kt
+│   │   └── RegisterRequest.kt
+│   └── api/
+│       └── AuthApi.kt
+│
+└── constant/
+    ├── ApiConstants.kt
+    └── ValidationConstants.kt
+```
+
+---
+
+## 四、数据流向
+
+### 4.1 请求数据流向
+
+```
+用户操作
+  ↓
+Fragment (UI)
+  ↓ 调用
+ViewModel.login()
+  ↓ 调用
+UseCase.invoke()
+  ↓ 调用
+Repository.login()
+  ↓ 调用
+RemoteDataSource.login() 或 LocalDataSource.getData()
+  ↓
+API/数据库
+  ↓ 返回数据
+Repository (转换 Data Model → Domain Model)
+  ↓ 返回
+UseCase (业务逻辑处理)
+  ↓ 返回
+ViewModel (转换为 UI State)
+  ↓ 更新 StateFlow
+Fragment (观察 StateFlow,更新 UI)
+```
+
+### 4.2 具体示例(登录流程)
+
+```
+1. 用户在 LoginFragment 点击登录按钮
+   ↓
+2. LoginFragment 调用 viewModel.login(mobile, password)
+   ↓
+3. LoginViewModel 调用 loginUseCase(mobile, password)
+   ↓
+4. LoginUseCase 验证输入,调用 authRepository.login()
+   ↓
+5. AuthRepository 调用 remoteDataSource.login()
+   ↓
+6. AuthRemoteDataSource 调用 authApi.login() (Retrofit)
+   ↓
+7. 网络请求返回 LoginResponse (Data Model)
+   ↓
+8. AuthRemoteDataSource 返回 Result<LoginResponse>
+   ↓
+9. AuthRepository 保存 Token 到 LocalDataSource
+   ↓
+10. AuthRepository 返回 Result<LoginResponse>
+    ↓
+11. LoginUseCase 返回 Result<Unit>
+    ↓
+12. LoginViewModel 更新 _loginState (Success/Error)
+    ↓
+13. LoginFragment 观察 loginState,更新 UI
+```
+
+---
+
+## 五、代码示例
+
+### 5.1 UI 层示例
+
+#### LoginFragment.kt
+
+```kotlin
+package com.narutohuo.xindazhou.user.ui.login
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import com.narutohuo.xindazhou.R
+import com.narutohuo.xindazhou.user.ui.viewmodel.LoginViewModel
+import com.narutohuo.xindazhou.user.ui.viewmodel.LoginViewModelFactory
+import kotlinx.coroutines.launch
+
+/**
+ * 登录Fragment
+ */
+class LoginFragment : Fragment() {
+    
+    private val viewModel: LoginViewModel by viewModels { 
+        LoginViewModelFactory(requireContext().applicationContext as android.app.Application)
+    }
+    
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_login, container, false)
+    }
+    
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        
+        // 初始化视图
+        initViews(view)
+        
+        // 观察状态
+        observeState()
+    }
+    
+    private fun initViews(view: View) {
+        // 绑定视图和设置点击事件
+        view.findViewById<View>(R.id.btnLogin).setOnClickListener {
+            val mobile = view.findViewById<EditText>(R.id.etMobile).text.toString()
+            val password = view.findViewById<EditText>(R.id.etPassword).text.toString()
+            viewModel.login(mobile, password)
+        }
+    }
+    
+    private fun observeState() {
+        lifecycleScope.launch {
+            viewModel.loginState.collect { state ->
+                when (state) {
+                    is LoginState.Idle -> { /* 初始状态 */ }
+                    is LoginState.Loading -> { /* 显示加载 */ }
+                    is LoginState.Success -> { /* 登录成功 */ }
+                    is LoginState.Error -> { /* 显示错误 */ }
+                }
+            }
+        }
+    }
+}
+```
+
+#### LoginViewModel.kt
+
+```kotlin
+package com.narutohuo.xindazhou.user.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import com.narutohuo.xindazhou.user.domain.usecase.LoginUseCase
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+
+/**
+ * 登录状态
+ */
+sealed class LoginState {
+    object Idle : LoginState()
+    object Loading : LoginState()
+    data class Success(val message: String) : LoginState()
+    data class Error(val message: String) : LoginState()
+}
+
+/**
+ * 登录ViewModel
+ */
+class LoginViewModel(
+    application: Application,
+    private val loginUseCase: LoginUseCase
+) : AndroidViewModel(application) {
+    
+    private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)
+    val loginState: StateFlow<LoginState> = _loginState
+    
+    fun login(mobile: String, password: String) {
+        viewModelScope.launch {
+            _loginState.value = LoginState.Loading
+            loginUseCase(mobile, password)
+                .onSuccess {
+                    _loginState.value = LoginState.Success("登录成功")
+                }
+                .onFailure { e ->
+                    _loginState.value = LoginState.Error(e.message ?: "登录失败")
+                }
+        }
+    }
+}
+```
+
+### 5.2 Domain 层示例
+
+#### LoginUseCase.kt
+
+```kotlin
+package com.narutohuo.xindazhou.user.domain.usecase
+
+import com.narutohuo.xindazhou.user.data.repository.AuthRepository
+import com.narutohuo.xindazhou.user.domain.constant.ValidationConstants
+import timber.log.Timber
+
+/**
+ * 登录用例
+ * 
+ * 封装登录业务逻辑
+ */
+class LoginUseCase(
+    private val authRepository: AuthRepository
+) {
+    suspend operator fun invoke(mobile: String, password: String): Result<Unit> {
+        // 业务逻辑验证
+        if (mobile.isBlank()) {
+            return Result.failure(IllegalArgumentException("手机号不能为空"))
+        }
+        
+        if (password.length < ValidationConstants.MIN_PASSWORD_LENGTH 
+            || password.length > ValidationConstants.MAX_PASSWORD_LENGTH) {
+            return Result.failure(
+                IllegalArgumentException("密码长度应为${ValidationConstants.MIN_PASSWORD_LENGTH}-${ValidationConstants.MAX_PASSWORD_LENGTH}位")
+            )
+        }
+        
+        // 调用 Repository
+        return authRepository.login(mobile, password).map { }
+    }
+}
+```
+
+### 5.3 Repository 层示例
+
+#### AuthRepository.kt
+
+```kotlin
+package com.narutohuo.xindazhou.user.data.repository
+
+import com.narutohuo.xindazhou.user.data.local.AuthLocalDataSource
+import com.narutohuo.xindazhou.user.data.model.LoginRequest
+import com.narutohuo.xindazhou.user.data.model.LoginResponse
+import com.narutohuo.xindazhou.user.data.remote.AuthRemoteDataSource
+import timber.log.Timber
+
+/**
+ * 认证数据仓库
+ * 
+ * 统一管理认证相关的数据获取和缓存
+ */
+class AuthRepository(
+    private val remoteDataSource: AuthRemoteDataSource,
+    private val localDataSource: AuthLocalDataSource
+) {
+    
+    companion object {
+        private const val TAG = "AuthRepository"
+    }
+    
+    /**
+     * 用户登录
+     */
+    suspend fun login(mobile: String, password: String): Result<LoginResponse> {
+        return try {
+            val request = LoginRequest(mobile, password)
+            
+            // 先尝试从远程获取
+            val result = remoteDataSource.login(request)
+            
+            // 如果成功,保存到本地
+            result.onSuccess { response ->
+                localDataSource.saveToken(response)
+                Timber.d("$TAG - login: Token已保存")
+            }
+            
+            result
+        } catch (e: Exception) {
+            Timber.e(e, "$TAG - login: 登录异常")
+            Result.failure(e)
+        }
+    }
+}
+```
+
+### 5.4 Data 层示例
+
+#### AuthRemoteDataSource.kt
+
+```kotlin
+package com.narutohuo.xindazhou.user.data.remote
+
+import com.narutohuo.xindazhou.user.api.AuthApi
+import com.narutohuo.xindazhou.user.data.constant.ApiConstants
+import com.narutohuo.xindazhou.user.data.model.LoginRequest
+import com.narutohuo.xindazhou.user.data.model.LoginResponse
+import timber.log.Timber
+
+/**
+ * 认证远程数据源接口
+ */
+interface AuthRemoteDataSource {
+    suspend fun login(request: LoginRequest): Result<LoginResponse>
+}
+
+/**
+ * 认证远程数据源实现
+ */
+class AuthRemoteDataSourceImpl(
+    private val authApi: AuthApi
+) : AuthRemoteDataSource {
+    
+    companion object {
+        private const val TAG = "AuthRemoteDataSource"
+    }
+    
+    override suspend fun login(request: LoginRequest): Result<LoginResponse> {
+        return try {
+            val response = authApi.login(request)
+            
+            if (!response.isSuccessful) {
+                val errorMsg = response.message() ?: "登录失败"
+                Timber.w("$TAG - login: HTTP请求失败,code=${response.code()}")
+                return Result.failure(Exception(errorMsg))
+            }
+            
+            val commonResult = response.body() 
+                ?: return Result.failure(Exception("响应体为空"))
+            
+            if (commonResult.code != ApiConstants.SUCCESS_CODE) {
+                val errorMsg = commonResult.msg ?: "登录失败 (code: ${commonResult.code})"
+                Timber.w("$TAG - login: 业务失败,code=${commonResult.code}")
+                return Result.failure(Exception(errorMsg))
+            }
+            
+            val loginResponse = commonResult.data 
+                ?: return Result.failure(Exception("服务器返回数据为空"))
+            
+            Timber.d("$TAG - login: 登录成功")
+            Result.success(loginResponse)
+            
+        } catch (e: Exception) {
+            Timber.e(e, "$TAG - login: 登录异常")
+            Result.failure(e)
+        }
+    }
+}
+```
+
+#### AuthLocalDataSource.kt
+
+```kotlin
+package com.narutohuo.xindazhou.user.data.local
+
+import com.narutohuo.xindazhou.user.data.model.LoginResponse
+
+/**
+ * 认证本地数据源接口
+ */
+interface AuthLocalDataSource {
+    suspend fun saveToken(loginResponse: LoginResponse)
+    suspend fun getToken(): String?
+    suspend fun clearToken()
+}
+
+/**
+ * 认证本地数据源实现
+ */
+class AuthLocalDataSourceImpl : AuthLocalDataSource {
+    
+    override suspend fun saveToken(loginResponse: LoginResponse) {
+        TokenManager.saveToken(
+            loginResponse.accessToken,
+            loginResponse.refreshToken,
+            loginResponse.userId
+        )
+    }
+    
+    override suspend fun getToken(): String? {
+        return TokenManager.getAccessToken()
+    }
+    
+    override suspend fun clearToken() {
+        TokenManager.clearToken()
+    }
+}
+```
+
+---
+
+## 六、依赖关系
+
+### 6.1 依赖方向
+
+```
+UI 层
+  ↓ 依赖
+Domain 层
+  ↑ 被依赖
+Repository 层
+  ↓ 依赖
+Data 层
+```
+
+**原则:**
+- 内层不依赖外层
+- 外层可以依赖内层
+- Domain 层不依赖任何 Android 框架
+
+### 6.2 依赖注入
+
+建议使用依赖注入框架(如 Hilt/Koin)管理依赖关系:
+
+```kotlin
+// 示例:使用 Koin
+val authModule = module {
+    // Data 层
+    factory<AuthRemoteDataSource> { AuthRemoteDataSourceImpl(get()) }
+    factory<AuthLocalDataSource> { AuthLocalDataSourceImpl() }
+    single { AuthApi.create() }
+    
+    // Repository 层
+    single<AuthRepository> { 
+        AuthRepository(get(), get()) 
+    }
+    
+    // Domain 层
+    factory { LoginUseCase(get()) }
+    factory { RegisterUseCase(get()) }
+    
+    // UI 层
+    viewModel { LoginViewModel(get(), get()) }
+}
+```
+
+---
+
+## 七、最佳实践
+
+### 7.1 状态管理
+
+使用 Sealed Class 定义 UI 状态:
+
+```kotlin
+sealed class LoginState {
+    object Idle : LoginState()
+    object Loading : LoginState()
+    data class Success(val message: String) : LoginState()
+    data class Error(val message: String) : LoginState()
+}
+```
+
+### 7.2 错误处理
+
+统一使用 Result 类型处理错误:
+
+```kotlin
+suspend fun login(mobile: String, password: String): Result<LoginResponse> {
+    return try {
+        // 成功
+        Result.success(data)
+    } catch (e: Exception) {
+        // 失败
+        Result.failure(e)
+    }
+}
+```
+
+### 7.3 数据转换
+
+Repository 层负责 Data Model 到 Domain Model 的转换:
+
+```kotlin
+// Data Model (API 响应)
+data class LoginResponseData(...)
+
+// Domain Model (业务模型)
+data class User(...)
+
+// Repository 中转换
+fun toDomainModel(data: LoginResponseData): User {
+    return User(
+        id = data.userId,
+        name = data.username,
+        // ...
+    )
+}
+```
+
+### 7.4 测试建议
+
+- **UI 层**:使用 AndroidX Test 测试 Fragment/Activity
+- **ViewModel**:使用 JUnit 测试,不依赖 Android 框架
+- **UseCase**:使用 JUnit 测试,Mock Repository
+- **Repository**:使用 JUnit 测试,Mock DataSource
+- **DataSource**:使用 JUnit 测试,Mock API
+
+### 7.5 命名规范
+
+- **ViewModel**:`功能ViewModel`,如 `LoginViewModel`
+- **UseCase**:`功能UseCase`,如 `LoginUseCase`
+- **Repository**:`功能Repository`,如 `AuthRepository`
+- **DataSource**:`功能RemoteDataSource` / `功能LocalDataSource`
+- **State**:`功能State`,如 `LoginState`
+
+---
+
+## 附录:架构检查清单
+
+### 代码审查检查项
+
+- [ ] UI 层是否只包含 UI 逻辑,业务逻辑是否在 UseCase 中
+- [ ] ViewModel 是否只调用 UseCase,不直接调用 Repository
+- [ ] UseCase 是否封装了业务逻辑验证
+- [ ] Repository 是否统一管理数据源(Remote + Local)
+- [ ] DataSource 是否分离为 Remote 和 Local
+- [ ] 是否遵循依赖方向(内层不依赖外层)
+- [ ] 是否使用了 Result 类型处理错误
+- [ ] 是否使用 Sealed Class 管理 UI 状态
+- [ ] 命名是否规范(ViewModel、UseCase、Repository、DataSource)
+- [ ] 是否添加了必要的注释(类、方法)
+
+---
+
+**文档版本**: v1.0  
+**最后更新**: 2024-01-01  
+**维护者**: 开发团队
+

+ 360 - 0
PROJECT_STRUCTURE.md

@@ -0,0 +1,360 @@
+# 新大洲 Android 项目结构文档
+
+## 一、项目结构图
+
+```
+xdz_android/
+├── app/                          # 应用主模块(业务层)
+│   ├── src/main/
+│   │   ├── java/                # 业务代码(Activity、Fragment、ViewModel等)
+│   │   └── res/                  # 资源文件(布局、图片、字符串等)
+│   └── build.gradle
+│
+├── base-core/                    # 基础核心模块(最底层)
+│   └── src/main/
+│       └── java/                # 核心工具类和接口定义
+│
+├── base-common/                  # 基础通用模块
+│   └── src/main/
+│       └── java/                # 通用组件(Dialog、网络请求封装等)
+│
+├── capability-ble/               # BLE 蓝牙能力模块
+│   └── src/main/
+│       └── java/                # BLE 相关功能实现
+│
+├── capability-socketio/          # SocketIO 实时通信能力模块
+│   └── src/main/
+│       └── java/                # SocketIO 客户端封装
+│
+├── capability-push/              # 推送能力模块
+│   └── src/main/
+│       └── java/                # 推送功能封装(极光推送等)
+│
+├── capability-qrcode/           # 二维码能力模块
+│   └── src/main/
+│       └── java/                # 二维码扫描/生成功能
+│
+├── capability-share/            # 分享能力模块
+│   └── src/main/
+│       └── java/                # 微信、QQ等分享功能
+│
+├── capability-nfc/              # NFC 能力模块
+│   └── src/main/
+│       └── java/                # NFC 读写功能
+│
+├── build.gradle                  # 项目根 build.gradle
+├── settings.gradle              # 模块配置
+└── gradle/                       # Gradle 配置
+    └── libs.versions.toml       # 依赖版本管理
+```
+
+## 二、模块说明
+
+### 2.1 应用层
+
+| 模块 | 命名空间 | 说明 |
+|------|---------|------|
+| **app** | `com.narutohuo.xindazhou` | 应用主模块,包含所有业务代码和UI |
+
+### 2.2 基础层
+
+| 模块 | 命名空间 | 说明 |
+|------|---------|------|
+| **base-core** | `com.narutohuo.xindazhou.core` | 核心基础模块,提供最基础的接口和工具类 |
+| **base-common** | `com.narutohuo.xindazhou.common` | 通用基础模块,提供通用组件和网络封装 |
+
+### 2.3 能力层(SDK层)
+
+| 模块 | 命名空间 | 说明 |
+|------|---------|------|
+| **capability-ble** | `com.narutohuo.xindazhou.ble` | 蓝牙BLE功能封装 |
+| **capability-socketio** | `com.narutohuo.xindazhou.socketio` | SocketIO实时通信封装 |
+| **capability-push** | `com.narutohuo.xindazhou.push` | 推送功能封装(极光推送等) |
+| **capability-qrcode** | `com.narutohuo.xindazhou.qrcode` | 二维码扫描/生成功能 |
+| **capability-share** | `com.narutohuo.xindazhou.share` | 分享功能封装(微信、QQ等) |
+| **capability-nfc** | `com.narutohuo.xindazhou.nfc` | NFC读写功能封装 |
+
+## 三、依赖关系图
+
+### 3.1 模块依赖关系
+
+```
+┌─────────────────────────────────────────────────────────┐
+│                        app                               │
+│              (应用主模块 - 业务层)                        │
+└────────────┬────────────────────────────────────────────┘
+             │
+             │ 依赖所有模块
+             │
+    ┌────────┼────────┬────────┬────────┬────────┬────────┐
+    │        │        │        │        │        │        │
+    ▼        ▼        ▼        ▼        ▼        ▼        ▼
+┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
+│base- │ │base-  │ │cap-   │ │cap-   │ │cap-   │ │cap-   │
+│common│ │core   │ │socket │ │ble    │ │push   │ │qrcode │
+└───┬───┘ └───────┘ │io     │ └───────┘ └───────┘ └───────┘
+    │               └───────┘
+    │               ┌───────┐
+    │               │cap-   │
+    │               │share  │
+    │               └───────┘
+    │               ┌───────┐
+    │               │cap-   │
+    │               │nfc    │
+    │               └───────┘
+    │
+    │ 依赖
+    ▼
+┌───────┐
+│base-  │
+│core   │
+└───────┘
+    ▲
+    │ 所有 capability-* 模块都依赖
+    │
+┌───┴───────────────────────────────────────────┐
+│  capability-ble                               │
+│  capability-socketio                          │
+│  capability-push                               │
+│  capability-qrcode                             │
+│  capability-share                              │
+│  capability-nfc                                │
+└───────────────────────────────────────────────┘
+```
+
+### 3.2 详细依赖关系
+
+#### app 模块依赖
+
+```yaml
+app:
+  基础模块:
+    - base-core
+    - base-common
+  能力模块:
+    - capability-ble
+    - capability-socketio
+    - capability-push
+    - capability-qrcode
+    - capability-share
+    - capability-nfc
+  第三方库:
+    - AndroidX Core KTX
+    - AppCompat
+    - Material Design
+    - ConstraintLayout
+    - Lifecycle (ViewModel, LiveData)
+    - Kotlin Coroutines
+    - Navigation
+    - Retrofit & OkHttp
+    - Glide
+    - Room
+    - Jetpack Compose
+    - Timber (日志)
+    - Hyperion (调试工具)
+    - Chuck (网络调试)
+```
+
+#### base-common 模块依赖
+
+```yaml
+base-common:
+  项目模块:
+    - base-core  # 依赖基础核心模块
+  第三方库:
+    - AndroidX Core KTX
+    - Fragment KTX
+    - Material Design
+    - Gson
+    - Retrofit & Gson Converter
+```
+
+#### base-core 模块依赖
+
+```yaml
+base-core:
+  第三方库:
+    - AndroidX Core KTX  # 仅依赖最基础的 AndroidX
+```
+
+#### capability-socketio 模块依赖
+
+```yaml
+capability-socketio:
+  项目模块:
+    - base-core  # 依赖基础核心模块
+  第三方库:
+    - AndroidX Core KTX
+    - Socket.IO Client (io.socket:socket.io-client:2.1.0)
+    - Gson
+    - Kotlin Coroutines
+```
+
+#### capability-ble 模块依赖
+
+```yaml
+capability-ble:
+  项目模块:
+    - base-core  # 依赖基础核心模块
+  第三方库:
+    - AndroidX Core KTX
+```
+
+#### capability-push 模块依赖
+
+```yaml
+capability-push:
+  项目模块:
+    - base-core  # 依赖基础核心模块
+  第三方库:
+    - AndroidX Core KTX
+    # 极光推送SDK(待添加)
+```
+
+#### capability-qrcode 模块依赖
+
+```yaml
+capability-qrcode:
+  项目模块:
+    - base-core  # 依赖基础核心模块
+  第三方库:
+    - AndroidX Core KTX
+    # 华为扫码SDK(待添加)
+```
+
+#### capability-share 模块依赖
+
+```yaml
+capability-share:
+  项目模块:
+    - base-core  # 依赖基础核心模块
+  第三方库:
+    - AndroidX Core KTX
+    # 微信分享SDK(待添加)
+    # QQ分享SDK(待添加)
+```
+
+#### capability-nfc 模块依赖
+
+```yaml
+capability-nfc:
+  项目模块:
+    - base-core  # 依赖基础核心模块
+  第三方库:
+    - AndroidX Core KTX
+```
+
+## 四、依赖关系总结
+
+### 4.1 依赖层级
+
+```
+层级 1: base-core
+  └─ 最底层,不依赖任何项目模块,只依赖 AndroidX Core
+
+层级 2: base-common + 所有 capability-* 模块
+  └─ 都依赖 base-core
+
+层级 3: app
+  └─ 依赖所有基础模块和能力模块
+```
+
+### 4.2 依赖原则
+
+1. **base-core**: 
+   - 最底层模块,不依赖任何项目内部模块
+   - 只依赖 AndroidX Core KTX
+   - 提供最基础的接口和工具类
+
+2. **base-common**: 
+   - 依赖 base-core
+   - 提供通用组件(Dialog、网络请求封装等)
+
+3. **capability-* 模块**: 
+   - 所有能力模块都依赖 base-core
+   - 每个模块独立封装特定功能
+   - 不相互依赖,保持模块独立性
+
+4. **app 模块**: 
+   - 依赖所有基础模块和能力模块
+   - 包含业务代码和UI
+   - 通过能力模块提供的接口使用功能
+
+### 4.3 模块独立性
+
+- ✅ **capability-* 模块之间不相互依赖**,保持独立
+- ✅ **所有 capability-* 模块都依赖 base-core**,统一基础
+- ✅ **app 模块依赖所有模块**,整合所有功能
+
+## 五、主要第三方依赖
+
+### 5.1 网络请求
+
+- **Retrofit**: `2.9.0` - HTTP 客户端
+- **OkHttp**: `4.12.0` - HTTP 网络库
+- **Gson**: `2.10.1` - JSON 解析
+
+### 5.2 UI 框架
+
+- **Jetpack Compose**: 现代 UI 框架
+- **Material Design**: `1.11.0` - Material 组件
+- **Navigation**: `2.7.6` - 导航组件
+
+### 5.3 异步处理
+
+- **Kotlin Coroutines**: `1.7.3` - 协程支持
+
+### 5.4 数据存储
+
+- **Room**: `2.6.1` - 本地数据库
+
+### 5.5 图片加载
+
+- **Glide**: `4.16.0` - 图片加载库
+
+### 5.6 实时通信
+
+- **Socket.IO Client**: `2.1.0` - SocketIO 客户端
+
+### 5.7 调试工具
+
+- **Hyperion**: `0.9.34` - 应用内调试工具
+- **Chuck**: `4.0.0` - 网络请求拦截器(调试用)
+- **Timber**: `5.0.1` - 日志库
+
+## 六、项目配置
+
+### 6.1 编译配置
+
+- **compileSdk**: 36
+- **minSdk**: 26
+- **targetSdk**: 36
+- **Java Version**: 17
+- **Kotlin JVM Target**: 17
+
+### 6.2 构建特性
+
+- **ViewBinding**: 启用
+- **DataBinding**: 部分启用
+- **Jetpack Compose**: 启用
+- **BuildConfig**: 启用
+
+## 七、模块职责划分
+
+| 模块 | 职责 | 可被谁依赖 |
+|------|------|-----------|
+| **base-core** | 提供最基础的接口和工具类 | 所有模块 |
+| **base-common** | 提供通用组件和网络封装 | app |
+| **capability-ble** | BLE 功能封装 | app |
+| **capability-socketio** | SocketIO 功能封装 | app |
+| **capability-push** | 推送功能封装 | app |
+| **capability-qrcode** | 二维码功能封装 | app |
+| **capability-share** | 分享功能封装 | app |
+| **capability-nfc** | NFC 功能封装 | app |
+| **app** | 业务代码和UI | 无(应用入口) |
+
+---
+
+**文档版本**: v1.0  
+**最后更新**: 2024年
+

+ 166 - 0
app/build.gradle

@@ -0,0 +1,166 @@
+plugins {
+    alias(libs.plugins.android.application)
+    alias(libs.plugins.kotlin.android)
+    alias(libs.plugins.kotlin.compose)
+}
+
+android {
+    namespace 'com.narutohuo.xindazhou'
+    compileSdk {
+        version = release(36)
+    }
+
+    // 从资源文件读取配置值(用于 manifestPlaceholders)
+    // 这样所有配置都在 strings.xml 中,build.gradle 只是读取并设置占位符
+    def getStringResource = { String name ->
+        def resFile = file("src/main/res/values/strings.xml")
+        if (!resFile.exists()) {
+            return ""
+        }
+        def xml = new XmlParser().parse(resFile)
+        def stringNode = xml.string.find { it.@name == name }
+        return stringNode ? stringNode.text() : ""
+    }
+
+    defaultConfig {
+        applicationId "com.narutohuo.xindazhou"
+        minSdk 26
+        targetSdk 36
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        
+        // SDK 占位符配置(从资源文件读取,所有值都在 strings.xml 中)
+        // 这样用户只需要在 strings.xml 中配置一次,不需要在 AndroidManifest.xml 中手动填写
+        
+        // QQ scheme 处理:优先使用 qq_app_id_scheme,如果没有则使用 qq_app_id 拼接
+        def qqAppIdScheme = getStringResource("qq_app_id_scheme")
+        def qqAppId = getStringResource("qq_app_id")
+        def qqScheme = ""
+        if (qqAppIdScheme && !qqAppIdScheme.contains("your_qq_appid_here")) {
+            qqScheme = qqAppIdScheme
+        } else if (qqAppId && !qqAppId.contains("your_qq_appid_here")) {
+            qqScheme = "tencent" + qqAppId
+        } else {
+            qqScheme = "tencentyour_qq_appid_here"
+        }
+        
+        manifestPlaceholders = [
+            JPUSH_APPKEY: getStringResource("jpush_app_key") ?: "your_jpush_appkey_here",
+            JPUSH_CHANNEL: getStringResource("push_jpush_channel") ?: "developer-default",
+            // QQ scheme 格式:tencent + qq_app_id(例如:tencent1101234567)
+            qqappid: qqScheme
+        ]
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_17
+        targetCompatibility JavaVersion.VERSION_17
+    }
+    kotlinOptions {
+        jvmTarget = '17'
+    }
+    buildFeatures {
+        compose true
+        viewBinding true
+        buildConfig true  // 启用 BuildConfig 生成
+    }
+}
+
+dependencies {
+    // 基础模块
+    implementation project(':base-core')
+    implementation project(':base-common')
+    
+    // SDK模块(能力层)
+    implementation project(':capability-ble')
+    implementation project(':capability-socketio')
+    implementation project(':capability-push')
+    implementation project(':capability-qrcode')
+    implementation project(':capability-share')
+    implementation project(':capability-nfc')
+    
+    // 友盟分享需要的第三方平台 SDK(确保运行时能找到)
+    // 注意:友盟分享模块已经添加了这些依赖,但为了确保运行时能找到,也在 app 模块中添加
+    implementation("com.tencent.mm.opensdk:wechat-sdk-android:6.8.24")
+    
+    // 业务模块代码已迁移到 app 模块内,不再需要独立的 module-* 依赖
+    
+    // AndroidX Core
+    implementation libs.androidx.core.ktx
+    implementation 'androidx.appcompat:appcompat:1.6.1'
+    implementation 'com.google.android.material:material:1.11.0'
+    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+    implementation 'androidx.cardview:cardview:1.0.0'
+    
+    // ViewModel & LiveData & StateFlow
+    implementation libs.androidx.lifecycle.runtime.ktx
+    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
+    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0'
+    
+    // Kotlin Coroutines
+    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
+    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
+    
+    // Navigation
+    implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6'
+    implementation 'androidx.navigation:navigation-ui-ktx:2.7.6'
+    
+    // Timber (日志库,用于Hyperion)
+    implementation 'com.jakewharton.timber:timber:5.0.1'
+    
+    // Retrofit & OkHttp
+    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
+    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
+    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
+    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
+    
+    // Glide
+    implementation 'com.github.bumptech.glide:glide:4.16.0'
+    
+    // Room
+    implementation 'androidx.room:room-runtime:2.6.1'
+    implementation 'androidx.room:room-ktx:2.6.1'
+    annotationProcessor 'androidx.room:room-compiler:2.6.1'
+    
+    // Compose
+    implementation libs.androidx.activity.compose
+    implementation platform(libs.androidx.compose.bom)
+    implementation libs.androidx.compose.ui
+    implementation libs.androidx.compose.ui.graphics
+    implementation libs.androidx.compose.ui.tooling.preview
+    implementation libs.androidx.compose.material3
+    
+    // 调试工具(只在Debug版本使用)
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-core:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-attr:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-measurement:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-disk:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-recorder:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-phoenix:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-crash:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-shared-preferences:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-geiger-counter:0.9.34'
+    debugImplementation 'com.willowtreeapps.hyperion:hyperion-timber:0.9.34'  // 日志查看
+    
+    // Chuck - 网络请求调试(只在Debug版本使用)
+    debugImplementation 'com.github.chuckerteam.chucker:library:4.0.0'
+    releaseImplementation 'com.github.chuckerteam.chucker:library-no-op:4.0.0'
+    
+    // Testing
+    testImplementation libs.junit
+    androidTestImplementation libs.androidx.junit
+    androidTestImplementation libs.androidx.espresso.core
+    androidTestImplementation platform(libs.androidx.compose.bom)
+    androidTestImplementation libs.androidx.compose.ui.test.junit4
+    debugImplementation libs.androidx.compose.ui.tooling
+    debugImplementation libs.androidx.compose.ui.test.manifest
+}
+

+ 22 - 0
app/proguard-rules.pro

@@ -0,0 +1,22 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+

+ 93 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <!-- Android 11+ 查询权限(必需,用于检测第三方应用安装状态) -->
+    <!-- 如果不添加此权限,会出现"错误码2008:没有安装应用"等问题 -->
+    <queries>
+        <!-- 微信 -->
+        <package android:name="com.tencent.mm" />
+        <!-- QQ -->
+        <package android:name="com.tencent.mobileqq" />
+        <!-- 微博 -->
+        <package android:name="com.sina.weibo" />
+        <!-- 企业微信 -->
+        <package android:name="com.tencent.wework" />
+        <!-- 钉钉 -->
+        <package android:name="com.alibaba.android.rimet" />
+        <!-- 支付宝 -->
+        <package android:name="com.eg.android.AlipayGphone" />
+        <!-- 抖音 -->
+        <package android:name="com.ss.android.ugc.aweme" />
+        <!-- 小红书 -->
+        <package android:name="com.xingin.xhs" />
+        <!-- 快手 -->
+        <package android:name="com.smile.gifmaker" />
+    </queries>
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" tools:targetApi="s" />
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.NFC" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <!-- 安装APK权限 -->
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+    <!-- 写入外部存储权限(用于下载APK) -->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" 
+        android:maxSdkVersion="32" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" 
+        android:maxSdkVersion="32" />
+
+    <application
+        android:name=".XinDaZhouApplication"
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.XinDaZhou"
+        android:networkSecurityConfig="@xml/network_security_config"
+        tools:targetApi="31">
+        
+        <!-- 极光推送配置(从资源文件读取,覆盖 AAR 中的占位符) -->
+        <meta-data
+            android:name="JPUSH_APPKEY"
+            android:value="@string/jpush_app_key"
+            tools:replace="android:value" />
+        <meta-data
+            android:name="JPUSH_CHANNEL"
+            android:value="@string/push_jpush_channel"
+            tools:replace="android:value" />
+        
+        
+        <activity
+            android:name=".MainActivity"
+            android:exported="true"
+            android:theme="@style/Theme.XinDaZhou">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- FileProvider 用于 Android 7.0+ 安装APK -->
+        <provider
+            android:name="androidx.core.content.FileProvider"
+            android:authorities="${applicationId}.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider>
+        
+        <!-- 注意:QQ 和微博的回调 Activity 声明已移到 capability-share 模块的 AndroidManifest.xml 中 -->
+    </application>
+
+</manifest>
+

+ 141 - 0
app/src/main/java/com/narutohuo/xindazhou/MainActivity.kt

@@ -0,0 +1,141 @@
+package com.narutohuo.xindazhou
+
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.NavHostFragment
+import com.narutohuo.xindazhou.common.config.ServerConfigManager
+import com.narutohuo.xindazhou.common.network.HttpApiClient
+import com.narutohuo.xindazhou.common.version.datasource.remote.VersionApi
+import com.narutohuo.xindazhou.common.version.repository.VersionRepository
+import com.narutohuo.xindazhou.common.version.ui.UpdateDialog
+import com.narutohuo.xindazhou.core.log.ILog
+import com.narutohuo.xindazhou.share.factory.ShareServiceFactory
+import com.narutohuo.xindazhou.user.datasource.local.TokenManager
+import kotlinx.coroutines.launch
+
+// BuildConfig 会自动生成在 app 模块的包名下
+// 由于 MainActivity 就在 app 模块的包名下,可以直接使用 BuildConfig
+
+/**
+ * 主Activity - 应用入口(单一Activity架构)
+ * 
+ * 职责:
+ * 1. 应用启动入口
+ * 2. 初始化 TokenManager 和 ServerConfigManager
+ * 3. 版本检查(启动时检查是否有新版本)
+ * 4. 使用 Navigation Component 管理页面导航
+ * 
+ * 架构说明:
+ * - 未登录状态:显示 LoginFragment
+ * - 已登录状态:显示 MainFragment(包含 TabBar 和各个业务 Fragment)
+ */
+class MainActivity : AppCompatActivity() {
+    
+    companion object {
+        private const val PLATFORM_ANDROID = 1 // 平台类型:1-安卓
+    }
+    
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        
+        // 初始化日志(自动根据 BuildConfig.DEBUG 选择实现)
+        // Debug 版本:使用 TimberLog(输出日志)
+        // Release 版本:使用 NoOpLog(不输出日志,提升性能)
+        com.narutohuo.xindazhou.core.log.ILog.init(enableLogging = BuildConfig.DEBUG)
+        
+        // 启动时检查版本更新(异步,不阻塞启动)
+        checkVersionUpdate()
+        
+        // 设置导航:根据登录状态决定起始页面
+        setupNavigation()
+    }
+    
+    /**
+     * 设置导航
+     * 根据登录状态决定显示登录页面还是主界面
+     */
+    private fun setupNavigation() {
+        val navHostFragment = supportFragmentManager.findFragmentById(R.id.navHostFragment) as? NavHostFragment
+        val navController = navHostFragment?.navController ?: return
+        
+        // 根据登录状态决定起始页面
+        if (TokenManager.isLoggedIn()) {
+            navController.navigate(R.id.mainFragment)
+        }
+        // 如果未登录,默认显示登录页面(由 nav_graph.xml 中的 startDestination 决定)
+    }
+    
+    /**
+     * 检查版本更新
+     * 如果没有版本或检查失败,不影响正常启动
+     */
+    private fun checkVersionUpdate() {
+        lifecycleScope.launch {
+            try {
+                // 获取当前版本号
+                val currentVersionCode = getCurrentVersionCode()
+                
+                // 使用 HttpApiClient 创建 API 实例
+                val versionApi = HttpApiClient.createApi<VersionApi>()
+                val versionRepository = VersionRepository(versionApi)
+                
+                // 检查版本(如果没有版本,返回 null,不影响启动)
+                val versionInfo = versionRepository.checkVersion(PLATFORM_ANDROID, currentVersionCode)
+                
+                // 如果有新版本,显示更新对话框
+                if (versionInfo != null && versionRepository.hasUpdate(versionInfo)) {
+                    val dialog = UpdateDialog.create(
+                        versionInfo = versionInfo,
+                        onDismiss = {
+                            // 对话框关闭后的回调
+                            if (versionRepository.isForceUpdate(versionInfo)) {
+                                // 强制更新时,如果用户关闭对话框,退出应用
+                                finish()
+                            }
+                        }
+                    )
+                    dialog.show(supportFragmentManager, "UpdateDialog")
+                }
+            } catch (e: Exception) {
+                // 版本检查失败不影响应用启动
+                // 可以记录日志,但不显示错误提示
+                ILog.e("MainActivity", "版本检查失败", e)
+            }
+        }
+    }
+    
+    /**
+     * 获取当前应用的版本号
+     */
+    private fun getCurrentVersionCode(): Int {
+        return try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+                // API 28+ 使用 longVersionCode
+                packageManager.getPackageInfo(packageName, 0).longVersionCode.toInt()
+            } else {
+                // API 26-27 使用 versionCode
+                @Suppress("DEPRECATION")
+                packageManager.getPackageInfo(packageName, 0).versionCode
+            }
+        } catch (e: PackageManager.NameNotFoundException) {
+            // 记录异常
+            ILog.e("MainActivity", "无法获取版本号", e)
+            1 // 默认版本号
+        }
+    }
+    
+    /**
+     * 处理分享回调
+     * 友盟分享 SDK 需要在这里处理回调
+     */
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: android.content.Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        // 处理友盟分享回调
+        ShareServiceFactory.getInstance().onActivityResult(this, requestCode, resultCode, data)
+    }
+}
+

+ 39 - 0
app/src/main/java/com/narutohuo/xindazhou/XinDaZhouApplication.kt

@@ -0,0 +1,39 @@
+package com.narutohuo.xindazhou
+
+import android.app.Application
+import com.narutohuo.xindazhou.common.config.ServerConfigManager
+import com.narutohuo.xindazhou.common.network.HttpApiClient
+import com.narutohuo.xindazhou.share.factory.ShareServiceFactory
+import com.narutohuo.xindazhou.user.datasource.local.TokenManager
+
+/**
+ * 应用程序入口
+ */
+class XinDaZhouApplication : Application() {
+    
+    override fun onCreate() {
+        super.onCreate()
+        
+        // 初始化 ServerConfigManager
+        ServerConfigManager.init(applicationContext)
+        
+        // 初始化 TokenManager
+        TokenManager.init(applicationContext)
+        
+        // 配置 HttpApiClient 的 Token 提供器
+        HttpApiClient.tokenProvider = {
+            TokenManager.getAccessToken()
+        }
+        
+        // 初始化分享服务(从资源文件读取配置)
+        // 注意:需要在 strings.xml 中配置 share_umeng_app_key 等参数
+        try {
+            ShareServiceFactory.init(applicationContext)
+            android.util.Log.d("XinDaZhouApplication", "分享服务初始化成功")
+        } catch (e: Exception) {
+            // 分享服务初始化失败不影响应用运行,但分享功能将不可用
+            android.util.Log.e("XinDaZhouApplication", "分享服务初始化失败", e)
+        }
+    }
+}
+

+ 45 - 0
app/src/main/java/com/narutohuo/xindazhou/common/main/ui/MainFragment.kt

@@ -0,0 +1,45 @@
+package com.narutohuo.xindazhou.common.main.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import androidx.navigation.ui.setupWithNavController
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.narutohuo.xindazhou.R
+
+/**
+ * 主界面Fragment
+ * 
+ * 包含底部导航栏(TabBar)和各个业务模块的Fragment容器
+ * 默认显示"车辆"标签页
+ */
+class MainFragment : Fragment() {
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_main, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        val bottomNavView: BottomNavigationView = view.findViewById(R.id.bottomNavView)
+
+        // 获取嵌套的 NavController(main_nav_graph)
+        // FragmentContainerView 会自动创建 NavHostFragment
+        val childNavHostFragment = childFragmentManager.findFragmentById(R.id.navHostFragment) 
+            as? androidx.navigation.fragment.NavHostFragment
+        
+        // 将底部导航栏与嵌套的 NavController 关联
+        childNavHostFragment?.navController?.let { navController ->
+            bottomNavView.setupWithNavController(navController)
+        }
+    }
+}
+

+ 25 - 0
app/src/main/java/com/narutohuo/xindazhou/common/version/datasource/remote/VersionApi.kt

@@ -0,0 +1,25 @@
+package com.narutohuo.xindazhou.common.version.datasource.remote
+
+import com.narutohuo.xindazhou.common.version.model.VersionInfo
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+/**
+ * 版本检查 API 接口
+ */
+interface VersionApi {
+    
+    /**
+     * 获取最新版本
+     * 
+     * @param platform 平台类型:1-安卓,2-鸿蒙,3-iOS
+     * @param currentVersionCode 当前版本号(可选,用于判断是否有更新)
+     * @return 版本信息
+     */
+    @GET("app-api/version/latest")
+    suspend fun getLatestVersion(
+        @Query("platform") platform: Int,
+        @Query("currentVersionCode") currentVersionCode: Int? = null
+    ): VersionInfo
+}
+

+ 17 - 0
app/src/main/java/com/narutohuo/xindazhou/common/version/model/VersionInfo.kt

@@ -0,0 +1,17 @@
+package com.narutohuo.xindazhou.common.version.model
+
+/**
+ * 版本信息数据模型
+ */
+data class VersionInfo(
+    val hasUpdate: Boolean = false,           // 是否有新版本
+    val forceUpdate: Boolean = false,         // 是否强制更新
+    val versionName: String? = null,          // 版本名称(如:1.0.0)
+    val versionCode: Int? = null,             // 版本号(内部版本号)
+    val versionDesc: String? = null,          // 版本描述
+    val downloadUrl: String? = null,          // 下载地址
+    val packageSize: Long? = null,            // 包大小(字节)
+    val updateLog: String? = null,            // 更新日志
+    val publishTime: String? = null           // 发布时间
+)
+

+ 59 - 0
app/src/main/java/com/narutohuo/xindazhou/common/version/repository/VersionRepository.kt

@@ -0,0 +1,59 @@
+package com.narutohuo.xindazhou.common.version.repository
+
+import com.narutohuo.xindazhou.common.version.datasource.remote.VersionApi
+import com.narutohuo.xindazhou.common.version.model.VersionInfo
+
+/**
+ * 版本管理 Repository
+ */
+class VersionRepository(
+    private val versionApi: VersionApi
+) {
+    
+    /**
+     * 检查版本更新
+     * 
+     * @param platform 平台类型:1-安卓,2-鸿蒙,3-iOS
+     * @param currentVersionCode 当前版本号
+     * @return 版本信息,如果没有版本则返回 null
+     */
+    suspend fun checkVersion(
+        platform: Int,
+        currentVersionCode: Int
+    ): VersionInfo? {
+        return try {
+            val versionInfo = versionApi.getLatestVersion(platform, currentVersionCode)
+            // 如果没有版本或没有更新,返回 null
+            if (!versionInfo.hasUpdate) {
+                null
+            } else {
+                versionInfo
+            }
+        } catch (e: Exception) {
+            // 如果请求失败(比如没有版本),返回 null
+            // 这样客户端可以正常启动,不会因为版本检查失败而阻塞
+            null
+        }
+    }
+    
+    /**
+     * 检查版本更新
+     * 
+     * @param versionInfo 版本信息
+     * @return 是否需要更新(true 表示需要更新)
+     */
+    fun hasUpdate(versionInfo: VersionInfo?): Boolean {
+        return versionInfo != null && versionInfo.hasUpdate
+    }
+    
+    /**
+     * 判断是否为强制更新
+     * 
+     * @param versionInfo 版本信息
+     * @return 是否为强制更新
+     */
+    fun isForceUpdate(versionInfo: VersionInfo?): Boolean {
+        return versionInfo?.forceUpdate == true
+    }
+}
+

+ 61 - 0
app/src/main/java/com/narutohuo/xindazhou/common/version/ui/UpdateDialog.kt

@@ -0,0 +1,61 @@
+package com.narutohuo.xindazhou.common.version.ui
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.os.Bundle
+import androidx.fragment.app.DialogFragment
+import com.narutohuo.xindazhou.common.version.model.VersionInfo
+
+/**
+ * 版本更新对话框
+ */
+class UpdateDialog : DialogFragment() {
+    
+    private var versionInfo: VersionInfo? = null
+    private var onDismiss: (() -> Unit)? = null
+    
+    companion object {
+        fun create(
+            versionInfo: VersionInfo,
+            onDismiss: (() -> Unit)? = null
+        ): UpdateDialog {
+            return UpdateDialog().apply {
+                this.versionInfo = versionInfo
+                this.onDismiss = onDismiss
+            }
+        }
+    }
+    
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+        val info = versionInfo ?: return super.onCreateDialog(savedInstanceState)
+        val builder = AlertDialog.Builder(requireContext())
+        builder.setTitle("发现新版本")
+        builder.setMessage("版本号: ${info.versionName}\n更新内容: ${info.versionDesc ?: "优化体验"}")
+        
+        if (info.forceUpdate == true) {
+            // 强制更新,只能点击更新
+            builder.setCancelable(false)
+            builder.setPositiveButton("立即更新") { _, _ ->
+                // TODO: 打开下载链接或应用商店
+                onDismiss?.invoke()
+            }
+        } else {
+            // 可选更新
+            builder.setPositiveButton("立即更新") { _, _ ->
+                // TODO: 打开下载链接或应用商店
+                onDismiss?.invoke()
+            }
+            builder.setNegativeButton("稍后更新") { _, _ ->
+                onDismiss?.invoke()
+            }
+        }
+        
+        return builder.create()
+    }
+    
+    override fun onDismiss(dialog: android.content.DialogInterface) {
+        super.onDismiss(dialog)
+        onDismiss?.invoke()
+    }
+}
+

+ 30 - 0
app/src/main/java/com/narutohuo/xindazhou/community/ui/CommunityFragment.kt

@@ -0,0 +1,30 @@
+package com.narutohuo.xindazhou.community.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+
+/**
+ * 社区Fragment
+ * 
+ * 显示社区相关功能
+ */
+class CommunityFragment : Fragment() {
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        // 临时使用简单的 TextView,后续可以替换为实际布局
+        val textView = TextView(requireContext())
+        textView.text = "社区页面\n(待实现)"
+        textView.textSize = 18f
+        textView.gravity = android.view.Gravity.CENTER
+        return textView
+    }
+}
+

+ 30 - 0
app/src/main/java/com/narutohuo/xindazhou/service/ui/ServiceFragment.kt

@@ -0,0 +1,30 @@
+package com.narutohuo.xindazhou.service.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+
+/**
+ * 服务Fragment
+ * 
+ * 显示服务相关功能
+ */
+class ServiceFragment : Fragment() {
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        // 临时使用简单的 TextView,后续可以替换为实际布局
+        val textView = TextView(requireContext())
+        textView.text = "服务页面\n(待实现)"
+        textView.textSize = 18f
+        textView.gravity = android.view.Gravity.CENTER
+        return textView
+    }
+}
+

+ 30 - 0
app/src/main/java/com/narutohuo/xindazhou/shop/ui/ShopFragment.kt

@@ -0,0 +1,30 @@
+package com.narutohuo.xindazhou.shop.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+
+/**
+ * 商城Fragment
+ * 
+ * 显示商城相关功能
+ */
+class ShopFragment : Fragment() {
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        // 临时使用简单的 TextView,后续可以替换为实际布局
+        val textView = TextView(requireContext())
+        textView.text = "商城页面\n(待实现)"
+        textView.textSize = 18f
+        textView.gravity = android.view.Gravity.CENTER
+        return textView
+    }
+}
+

+ 46 - 0
app/src/main/java/com/narutohuo/xindazhou/user/datasource/local/AuthLocalDataSource.kt

@@ -0,0 +1,46 @@
+package com.narutohuo.xindazhou.user.datasource.local
+
+import com.narutohuo.xindazhou.user.model.LoginResponse
+
+/**
+ * 认证本地数据源接口
+ */
+interface AuthLocalDataSource {
+    /**
+     * 保存Token
+     */
+    suspend fun saveToken(loginResponse: LoginResponse)
+    
+    /**
+     * 获取Access Token
+     */
+    suspend fun getToken(): String?
+    
+    /**
+     * 清除Token
+     */
+    suspend fun clearToken()
+}
+
+/**
+ * 认证本地数据源实现
+ */
+class AuthLocalDataSourceImpl : AuthLocalDataSource {
+    
+    override suspend fun saveToken(loginResponse: LoginResponse) {
+        TokenManager.saveToken(
+            loginResponse.accessToken,
+            loginResponse.refreshToken,
+            loginResponse.userId
+        )
+    }
+    
+    override suspend fun getToken(): String? {
+        return TokenManager.getAccessToken()
+    }
+    
+    override suspend fun clearToken() {
+        TokenManager.clearToken()
+    }
+}
+

+ 108 - 0
app/src/main/java/com/narutohuo/xindazhou/user/datasource/local/TokenManager.kt

@@ -0,0 +1,108 @@
+package com.narutohuo.xindazhou.user.datasource.local
+
+import android.content.Context
+import android.content.SharedPreferences
+
+/**
+ * Token管理器
+ * 负责Token的存储、读取和清除
+ */
+object TokenManager {
+    private const val PREFS_NAME = "xdz_auth_prefs"
+    private const val KEY_ACCESS_TOKEN = "access_token"
+    private const val KEY_REFRESH_TOKEN = "refresh_token"
+    private const val KEY_USER_ID = "user_id"
+    private const val KEY_SERVER_URL = "server_url"
+    private const val KEY_SOCKET_URL = "socket_url"
+    
+    private var prefs: SharedPreferences? = null
+    private var initialized = false
+    
+    fun init(context: Context) {
+        prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
+        initialized = true
+    }
+    
+    fun isInitialized(): Boolean = initialized
+    
+    /**
+     * 保存Token
+     */
+    fun saveToken(accessToken: String, refreshToken: String, userId: Long) {
+        prefs?.edit()?.apply {
+            putString(KEY_ACCESS_TOKEN, accessToken)
+            putString(KEY_REFRESH_TOKEN, refreshToken)
+            putLong(KEY_USER_ID, userId)
+            apply()
+        }
+    }
+    
+    /**
+     * 获取Access Token
+     */
+    fun getAccessToken(): String? {
+        return prefs?.getString(KEY_ACCESS_TOKEN, null)
+    }
+    
+    /**
+     * 获取Refresh Token
+     */
+    fun getRefreshToken(): String? {
+        return prefs?.getString(KEY_REFRESH_TOKEN, null)
+    }
+    
+    /**
+     * 获取用户ID
+     */
+    fun getUserId(): Long {
+        return prefs?.getLong(KEY_USER_ID, 0) ?: 0
+    }
+    
+    /**
+     * 判断是否已登录
+     */
+    fun isLoggedIn(): Boolean {
+        return !getAccessToken().isNullOrEmpty()
+    }
+    
+    /**
+     * 清除Token(登出)
+     */
+    fun clearToken() {
+        prefs?.edit()?.apply {
+            remove(KEY_ACCESS_TOKEN)
+            remove(KEY_REFRESH_TOKEN)
+            remove(KEY_USER_ID)
+            apply()
+        }
+    }
+    
+    /**
+     * 保存服务器地址
+     */
+    fun saveServerUrl(url: String) {
+        prefs?.edit()?.putString(KEY_SERVER_URL, url)?.apply()
+    }
+    
+    /**
+     * 获取服务器地址
+     */
+    fun getServerUrl(): String? {
+        return prefs?.getString(KEY_SERVER_URL, null)
+    }
+    
+    /**
+     * 保存Socket地址
+     */
+    fun saveSocketUrl(url: String) {
+        prefs?.edit()?.putString(KEY_SOCKET_URL, url)?.apply()
+    }
+    
+    /**
+     * 获取Socket地址
+     */
+    fun getSocketUrl(): String? {
+        return prefs?.getString(KEY_SOCKET_URL, null)
+    }
+}
+

+ 28 - 0
app/src/main/java/com/narutohuo/xindazhou/user/datasource/remote/AuthApi.kt

@@ -0,0 +1,28 @@
+package com.narutohuo.xindazhou.user.datasource.remote
+
+import com.narutohuo.xindazhou.common.network.CommonResult
+import com.narutohuo.xindazhou.user.model.LoginRequest
+import com.narutohuo.xindazhou.user.model.LoginResponse
+import com.narutohuo.xindazhou.user.model.RegisterRequest
+import retrofit2.Response
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+/**
+ * 认证相关API接口
+ */
+interface AuthApi {
+    
+    /**
+     * 用户登录
+     */
+    @POST("member/auth/login")
+    suspend fun login(@Body request: LoginRequest): Response<CommonResult<LoginResponse>>
+    
+    /**
+     * 用户注册
+     */
+    @POST("member/auth/register")
+    suspend fun register(@Body request: RegisterRequest): Response<CommonResult<LoginResponse>>
+}
+

+ 61 - 0
app/src/main/java/com/narutohuo/xindazhou/user/datasource/remote/AuthRemoteDataSource.kt

@@ -0,0 +1,61 @@
+package com.narutohuo.xindazhou.user.datasource.remote
+
+import com.narutohuo.xindazhou.common.network.ApiResponseParser
+import com.narutohuo.xindazhou.common.network.HttpApiClient
+import com.narutohuo.xindazhou.user.model.LoginRequest
+import com.narutohuo.xindazhou.user.model.LoginResponse
+import com.narutohuo.xindazhou.user.model.RegisterRequest
+
+/**
+ * 认证远程数据源接口
+ */
+interface AuthRemoteDataSource {
+    /**
+     * 用户登录
+     */
+    suspend fun login(request: LoginRequest): Result<LoginResponse>
+    
+    /**
+     * 用户注册
+     */
+    suspend fun register(request: RegisterRequest): Result<LoginResponse>
+}
+
+/**
+ * 认证远程数据源实现
+ */
+class AuthRemoteDataSourceImpl : AuthRemoteDataSource {
+    
+    companion object {
+        private const val TAG = "AuthRemoteDataSource"
+    }
+    
+    private val authApi: AuthApi by lazy {
+        HttpApiClient.createApi<AuthApi>()
+    }
+    
+    override suspend fun login(request: LoginRequest): Result<LoginResponse> {
+        return try {
+            ApiResponseParser.handleResponse(
+                response = authApi.login(request),
+                tag = "$TAG - login",
+                errorMessage = "登录失败"
+            )
+        } catch (e: Exception) {
+            Result.failure(e)
+        }
+    }
+    
+    override suspend fun register(request: RegisterRequest): Result<LoginResponse> {
+        return try {
+            ApiResponseParser.handleResponse(
+                response = authApi.register(request),
+                tag = "$TAG - register",
+                errorMessage = "注册失败"
+            )
+        } catch (e: Exception) {
+            Result.failure(e)
+        }
+    }
+}
+

+ 10 - 0
app/src/main/java/com/narutohuo/xindazhou/user/model/LoginRequest.kt

@@ -0,0 +1,10 @@
+package com.narutohuo.xindazhou.user.model
+
+/**
+ * 登录请求参数
+ */
+data class LoginRequest(
+    val mobile: String,
+    val password: String
+)
+

+ 17 - 0
app/src/main/java/com/narutohuo/xindazhou/user/model/LoginResponse.kt

@@ -0,0 +1,17 @@
+package com.narutohuo.xindazhou.user.model
+
+/**
+ * 登录响应数据
+ * 对应后端 AppAuthLoginRespVO
+ */
+data class LoginResponse(
+    val userId: Long,
+    val accessToken: String,
+    val refreshToken: String,
+    val expiresTime: String? = null,  // LocalDateTime 在 JSON 中序列化为字符串
+    val openid: String? = null,
+    // 以下字段为兼容字段(后端不返回,但前端可能需要)
+    val username: String? = null,
+    val mobile: String? = null
+)
+

+ 10 - 0
app/src/main/java/com/narutohuo/xindazhou/user/model/RegisterRequest.kt

@@ -0,0 +1,10 @@
+package com.narutohuo.xindazhou.user.model
+
+/**
+ * 注册请求参数
+ */
+data class RegisterRequest(
+    val mobile: String,
+    val password: String
+)
+

+ 80 - 0
app/src/main/java/com/narutohuo/xindazhou/user/repository/AuthRepository.kt

@@ -0,0 +1,80 @@
+package com.narutohuo.xindazhou.user.repository
+
+import com.narutohuo.xindazhou.user.datasource.local.AuthLocalDataSource
+import com.narutohuo.xindazhou.user.datasource.local.AuthLocalDataSourceImpl
+import com.narutohuo.xindazhou.user.datasource.remote.AuthRemoteDataSource
+import com.narutohuo.xindazhou.user.datasource.remote.AuthRemoteDataSourceImpl
+import com.narutohuo.xindazhou.core.log.ILog
+import com.narutohuo.xindazhou.user.model.LoginRequest
+import com.narutohuo.xindazhou.user.model.LoginResponse
+import com.narutohuo.xindazhou.user.model.RegisterRequest
+
+/**
+ * 认证数据仓库
+ * 
+ * 负责统一管理认证相关的数据获取和缓存
+ */
+class AuthRepository(
+    private val remoteDataSource: AuthRemoteDataSource = AuthRemoteDataSourceImpl(),
+    private val localDataSource: AuthLocalDataSource = AuthLocalDataSourceImpl()
+) {
+    
+    companion object {
+        private const val TAG = "AuthRepository"
+    }
+    
+    /**
+     * 用户登录
+     * 
+     * @param mobile 手机号
+     * @param password 密码
+     * @return 登录结果
+     */
+    suspend fun login(mobile: String, password: String): Result<LoginResponse> {
+        return try {
+            val request = LoginRequest(mobile, password)
+            
+            // 从远程数据源获取数据
+            val result = remoteDataSource.login(request)
+            
+            // 如果成功,保存到本地
+            result.onSuccess { response ->
+                localDataSource.saveToken(response)
+                ILog.d(TAG, "login: Token已保存")
+            }
+            
+            result
+        } catch (e: Exception) {
+            ILog.e(TAG, "login: 登录异常", e)
+            Result.failure(e)
+        }
+    }
+    
+    /**
+     * 用户注册
+     * 
+     * @param mobile 手机号
+     * @param password 密码
+     * @return 注册结果
+     */
+    suspend fun register(mobile: String, password: String): Result<LoginResponse> {
+        return try {
+            val request = RegisterRequest(mobile, password)
+            
+            // 从远程数据源获取数据
+            val result = remoteDataSource.register(request)
+                
+            // 如果成功,保存到本地
+            result.onSuccess { response ->
+                localDataSource.saveToken(response)
+                ILog.d(TAG, "register: Token已保存")
+            }
+            
+            result
+        } catch (e: Exception) {
+            ILog.e(TAG, "register: 注册异常", e)
+            Result.failure(e)
+        }
+    }
+}
+

+ 149 - 0
app/src/main/java/com/narutohuo/xindazhou/user/repository/SocketIORepository.kt

@@ -0,0 +1,149 @@
+package com.narutohuo.xindazhou.user.repository
+
+import com.narutohuo.xindazhou.common.config.ServerConfigManager
+import com.narutohuo.xindazhou.socketio.api.SocketIOService
+import com.narutohuo.xindazhou.socketio.factory.SocketIOServiceFactory
+import com.narutohuo.xindazhou.socketio.model.SocketIOEvent
+import com.narutohuo.xindazhou.socketio.model.SocketIOResponse
+import com.narutohuo.xindazhou.core.log.ILog
+import com.narutohuo.xindazhou.user.datasource.local.TokenManager
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+
+/**
+ * SocketIO 数据仓库
+ * 
+ * 负责统一管理 SocketIO 连接和数据获取
+ */
+class SocketIORepository(
+    private val socketService: SocketIOService = SocketIOServiceFactory.getInstance()
+) {
+    
+    companion object {
+        private const val TAG = "SocketIORepository"
+    }
+    
+    private val _connectionState = MutableSharedFlow<Boolean>()
+    val connectionState: SharedFlow<Boolean> = _connectionState.asSharedFlow()
+    
+    private val _logMessage = MutableSharedFlow<String>()
+    val logMessage: SharedFlow<String> = _logMessage.asSharedFlow()
+    
+    private val _vehicleControlResponse = MutableSharedFlow<SocketIOResponse>()
+    val vehicleControlResponse: SharedFlow<SocketIOResponse> = _vehicleControlResponse.asSharedFlow()
+    
+    private val _vehicleAlarm = MutableSharedFlow<SocketIOResponse>()
+    val vehicleAlarm: SharedFlow<SocketIOResponse> = _vehicleAlarm.asSharedFlow()
+    
+    init {
+        subscribeEvents()
+    }
+    
+    /**
+     * 连接 SocketIO
+     */
+    suspend fun connect(): Result<Unit> {
+        return try {
+            val socketUrl = ServerConfigManager.getSocketIOUrl()
+            val token = TokenManager.getAccessToken()
+            
+            if (token.isNullOrEmpty()) {
+                return Result.failure(Exception("未登录,无法获取Token"))
+            }
+            
+            ILog.d(TAG, "connect: 正在连接 $socketUrl")
+            socketService.connect(socketUrl, token)
+            Result.success(Unit)
+        } catch (e: Exception) {
+            ILog.e(TAG, "connect: 连接失败", e)
+            Result.failure(e)
+        }
+    }
+    
+    /**
+     * 断开 SocketIO 连接
+     */
+    suspend fun disconnect(): Result<Unit> {
+        return try {
+            socketService.disconnect()
+            ILog.d(TAG, "disconnect: 已断开连接")
+            Result.success(Unit)
+        } catch (e: Exception) {
+            ILog.e(TAG, "disconnect: 断开连接失败", e)
+            Result.failure(e)
+        }
+    }
+    
+    /**
+     * 检查连接状态
+     */
+    fun isConnected(): Boolean {
+        return socketService.isConnected()
+    }
+    
+    /**
+     * 发送车辆控制指令
+     */
+    suspend fun sendVehicleControl(command: String, vehicleId: Long): Result<Unit> {
+        return try {
+            if (!socketService.isConnected()) {
+                return Result.failure(Exception("未连接,无法发送消息"))
+            }
+            
+            val data = mapOf(
+                "command" to command,
+                "vehicleId" to vehicleId,
+                "timestamp" to System.currentTimeMillis()
+            )
+            socketService.emit(SocketIOEvent.VEHICLE_CONTROL, data)
+            ILog.d(TAG, "sendVehicleControl: 发送指令 $command")
+            Result.success(Unit)
+        } catch (e: Exception) {
+            ILog.e(TAG, "sendVehicleControl: 发送失败", e)
+            Result.failure(e)
+        }
+    }
+    
+    /**
+     * 订阅 SocketIO 事件
+     */
+    private fun subscribeEvents() {
+        // 订阅连接成功事件
+        socketService.on(SocketIOEvent.CONNECT) { response ->
+            ILog.d(TAG, "onConnect")
+            _connectionState.tryEmit(true)
+            _logMessage.tryEmit("✅ 连接成功")
+        }
+        
+        // 订阅断开连接事件
+        socketService.on(SocketIOEvent.DISCONNECT) { response ->
+            ILog.d(TAG, "onDisconnect")
+            _connectionState.tryEmit(false)
+            _logMessage.tryEmit("❌ 断开连接")
+        }
+        
+        // 订阅连接错误事件
+        socketService.on(SocketIOEvent.CONNECT_ERROR) { response ->
+            ILog.e(TAG, "onConnectError: ${response.data}")
+            _connectionState.tryEmit(false)
+            _logMessage.tryEmit("❌ 连接错误:${response.data}")
+        }
+        
+        // 订阅车辆控制响应事件
+        socketService.on("vehicle_control_response") { response ->
+            ILog.d(TAG, "onVehicleControlResponse: ${response.data}")
+            _logMessage.tryEmit("📩 收到车辆控制响应:${response.data}")
+            _vehicleControlResponse.tryEmit(response)
+        }
+        
+        // 订阅车辆报警事件
+        socketService.on(SocketIOEvent.VEHICLE_ALARM) { response ->
+            ILog.d(TAG, "onVehicleAlarm: ${response.data}")
+            _logMessage.tryEmit("🚨 收到车辆报警推送")
+            _logMessage.tryEmit("   事件: ${response.event}")
+            _logMessage.tryEmit("   数据: ${response.data}")
+            _vehicleAlarm.tryEmit(response)
+        }
+    }
+}

+ 17 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/constant/UiConstants.kt

@@ -0,0 +1,17 @@
+package com.narutohuo.xindazhou.user.ui.constant
+
+/**
+ * UI 相关常量
+ */
+object UiConstants {
+    /** 提示信息 */
+    const val MSG_MOBILE_EMPTY = "请输入手机号"
+    const val MSG_PASSWORD_EMPTY = "请输入密码"
+    const val MSG_PASSWORD_INVALID = "密码长度为6-16位"
+    const val MSG_PASSWORD_NOT_MATCH = "两次输入的密码不一致"
+    const val MSG_LOGIN_SUCCESS = "登录成功"
+    const val MSG_LOGIN_FAILED = "登录失败"
+    const val MSG_REGISTER_SUCCESS = "注册成功"
+    const val MSG_REGISTER_FAILED = "注册失败"
+}
+

+ 156 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/login/LoginFragment.kt

@@ -0,0 +1,156 @@
+package com.narutohuo.xindazhou.user.ui.login
+
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.google.android.material.textfield.TextInputEditText
+import com.narutohuo.xindazhou.R
+import com.narutohuo.xindazhou.common.dialog.ServerConfigDialog
+import com.narutohuo.xindazhou.share.factory.ShareServiceFactory
+import com.narutohuo.xindazhou.share.model.ShareContent
+import com.narutohuo.xindazhou.share.model.ShareResponse
+import com.narutohuo.xindazhou.user.ui.constant.UiConstants
+import com.narutohuo.xindazhou.user.ui.viewmodel.LoginViewModel
+import com.narutohuo.xindazhou.user.ui.viewmodel.LoginState
+import com.narutohuo.xindazhou.user.ui.viewmodel.LoginViewModelFactory
+import kotlinx.coroutines.launch
+
+/**
+ * 登录Fragment
+ */
+class LoginFragment : Fragment() {
+    
+    private val viewModel: LoginViewModel by viewModels { 
+        LoginViewModelFactory(requireContext().applicationContext as android.app.Application)
+    }
+    
+    private lateinit var etMobile: TextInputEditText
+    private lateinit var etPassword: TextInputEditText
+    private lateinit var btnLogin: MaterialButton
+    private lateinit var btnRegister: MaterialButton
+    private lateinit var ivServerConfig: View
+    private lateinit var progressBar: View
+    private lateinit var fabShare: FloatingActionButton
+    
+    private val shareService = ShareServiceFactory.getInstance()
+    
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_login, container, false)
+    }
+    
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        
+        etMobile = view.findViewById(R.id.etMobile)
+        etPassword = view.findViewById(R.id.etPassword)
+        btnLogin = view.findViewById(R.id.btnLogin)
+        btnRegister = view.findViewById(R.id.btnRegister)
+        ivServerConfig = view.findViewById(R.id.ivServerConfig)
+        progressBar = view.findViewById(R.id.progressBar)
+        fabShare = view.findViewById(R.id.fabShare)
+        
+        // 登录按钮
+        btnLogin.setOnClickListener {
+            val mobile = etMobile.text?.toString()?.trim() ?: ""
+            val password = etPassword.text?.toString() ?: ""
+            
+            if (TextUtils.isEmpty(mobile)) {
+                Toast.makeText(requireContext(), UiConstants.MSG_MOBILE_EMPTY, Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            if (TextUtils.isEmpty(password)) {
+                Toast.makeText(requireContext(), UiConstants.MSG_PASSWORD_EMPTY, Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            viewModel.login(mobile, password)
+        }
+        
+        // 注册按钮
+        btnRegister.setOnClickListener {
+            findNavController().navigate(R.id.action_loginFragment_to_registerFragment)
+        }
+        
+        // 服务器配置按钮
+        ivServerConfig.setOnClickListener {
+            val dialog = ServerConfigDialog()
+            dialog.show(parentFragmentManager, "ServerConfigDialog")
+        }
+        
+        // 分享按钮(测试用)
+        fabShare.setOnClickListener {
+            testShare()
+        }
+        
+        // 观察登录状态
+        lifecycleScope.launch {
+            viewModel.loginState.collect { state ->
+                when (state) {
+                    is LoginState.Idle -> {
+                        progressBar.visibility = View.GONE
+                        btnLogin.isEnabled = true
+                    }
+                    is LoginState.Loading -> {
+                        progressBar.visibility = View.VISIBLE
+                        btnLogin.isEnabled = false
+                    }
+                    is LoginState.Success -> {
+                        progressBar.visibility = View.GONE
+                        btnLogin.isEnabled = true
+                        Toast.makeText(requireContext(), state.message, Toast.LENGTH_SHORT).show()
+                        // 导航到主界面
+                        findNavController().navigate(R.id.action_loginFragment_to_mainFragment)
+                    }
+                    is LoginState.Error -> {
+                        progressBar.visibility = View.GONE
+                        btnLogin.isEnabled = true
+                        Toast.makeText(requireContext(), state.message, Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * 测试分享功能
+     */
+    private fun testShare() {
+        val content = ShareContent.builder()
+            .setTitle("新大洲智能车控")
+            .setDescription("分享给您一个有趣的内容,这是分享功能测试")
+            .setUrl("https://www.xindazhou.com")
+            .build()
+        
+        shareService.share(requireActivity(), content) { response: ShareResponse ->
+            if (response.success) {
+                val platform = response.data
+                Toast.makeText(
+                    requireContext(),
+                    "分享成功: ${platform?.name ?: "未知平台"}",
+                    Toast.LENGTH_SHORT
+                ).show()
+            } else {
+                Toast.makeText(
+                    requireContext(),
+                    "分享失败: ${response.errorMessage}",
+                    Toast.LENGTH_SHORT
+                ).show()
+            }
+        }
+    }
+}
+

+ 141 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/profile/UserFragment.kt

@@ -0,0 +1,141 @@
+package com.narutohuo.xindazhou.user.ui.profile
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import com.google.android.material.button.MaterialButton
+import com.narutohuo.xindazhou.R
+import com.narutohuo.xindazhou.user.ui.viewmodel.UserViewModel
+import com.narutohuo.xindazhou.user.ui.viewmodel.UserViewModelFactory
+import kotlinx.coroutines.launch
+
+/**
+ * 用户Fragment - 包含 SocketIO 测试功能
+ * 
+ * 功能:
+ * 1. SocketIO 连接测试
+ * 2. 发送寻车指令测试(上行)
+ * 3. 接收报警消息测试(下行)
+ * 
+ * 架构:MVVM
+ * - View (Fragment): 只负责 UI 初始化和状态观察
+ * - ViewModel: 管理业务逻辑和状态
+ * - Repository: 数据层(封装 SocketIOService)
+ */
+class UserFragment : Fragment() {
+
+    private val viewModel: UserViewModel by viewModels {
+        UserViewModelFactory(requireContext().applicationContext as android.app.Application)
+    }
+
+    private lateinit var tvConnectionStatus: TextView
+    private lateinit var btnConnect: MaterialButton
+    private lateinit var btnFindVehicle: MaterialButton
+    private lateinit var tvLog: TextView
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_user_socket_test, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        // 初始化视图
+        tvConnectionStatus = view.findViewById(R.id.tvConnectionStatus)
+        btnConnect = view.findViewById(R.id.btnConnect)
+        btnFindVehicle = view.findViewById(R.id.btnFindVehicle)
+        tvLog = view.findViewById(R.id.tvLog)
+
+        // 设置按钮点击事件
+        btnConnect.setOnClickListener {
+            if (viewModel.uiState.value.isConnected) {
+                viewModel.disconnect()
+            } else {
+                viewModel.connect()
+            }
+        }
+
+        btnFindVehicle.setOnClickListener {
+            viewModel.sendFindVehicleCommand()
+        }
+
+        // 观察 UI 状态
+        observeUiState()
+
+        // 观察报警消息
+        observeAlarmMessage()
+
+        // 观察错误消息
+        observeErrorMessage()
+    }
+
+    /**
+     * 观察 UI 状态(连接状态、日志列表)
+     */
+    private fun observeUiState() {
+        lifecycleScope.launch {
+            viewModel.uiState.collect { state ->
+                // 更新连接状态显示
+                tvConnectionStatus.text = "连接状态:${if (state.isConnected) "已连接" else "未连接"}"
+                
+                // 更新连接按钮文本
+                btnConnect.text = if (state.isConnected) "断开连接" else "连接SocketIO"
+                
+                // 更新寻车按钮状态
+                btnFindVehicle.isEnabled = state.isConnected
+                
+                // 更新日志显示
+                tvLog.text = state.logs.joinToString("\n")
+                
+                // 自动滚动到底部
+                tvLog.post {
+                    val scrollView = tvLog.parent as? android.widget.ScrollView
+                    scrollView?.fullScroll(View.FOCUS_DOWN)
+                }
+            }
+        }
+    }
+
+    /**
+     * 观察报警消息
+     */
+    private fun observeAlarmMessage() {
+        lifecycleScope.launch {
+            viewModel.alarmMessage.collect { alarm ->
+                alarm?.let {
+                    Toast.makeText(requireContext(), "收到车辆报警!", Toast.LENGTH_LONG).show()
+                }
+            }
+        }
+    }
+
+    /**
+     * 观察错误消息
+     */
+    private fun observeErrorMessage() {
+        lifecycleScope.launch {
+            viewModel.errorMessage.collect { error ->
+                error?.let {
+                    Toast.makeText(requireContext(), error, Toast.LENGTH_SHORT).show()
+                    viewModel.clearErrorMessage()
+                }
+            }
+        }
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        // 注意:不在这里断开连接,因为是单例,其他页面可能还需要使用
+        // 如果需要断开,可以在应用退出时统一处理
+    }
+}

+ 119 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/register/RegisterFragment.kt

@@ -0,0 +1,119 @@
+package com.narutohuo.xindazhou.user.ui.register
+
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.textfield.TextInputEditText
+import com.narutohuo.xindazhou.R
+import com.narutohuo.xindazhou.user.ui.constant.UiConstants
+import com.narutohuo.xindazhou.user.ui.viewmodel.RegisterViewModel
+import com.narutohuo.xindazhou.user.ui.viewmodel.RegisterState
+import com.narutohuo.xindazhou.user.ui.viewmodel.RegisterViewModelFactory
+import kotlinx.coroutines.launch
+
+/**
+ * 注册Fragment
+ */
+class RegisterFragment : Fragment() {
+    
+    private val viewModel: RegisterViewModel by viewModels { 
+        RegisterViewModelFactory(requireContext().applicationContext as android.app.Application)
+    }
+    
+    private lateinit var etMobile: TextInputEditText
+    private lateinit var etPassword: TextInputEditText
+    private lateinit var etConfirmPassword: TextInputEditText
+    private lateinit var btnRegister: MaterialButton
+    private lateinit var btnBackToLogin: MaterialButton
+    private lateinit var progressBar: View
+    
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_register, container, false)
+    }
+    
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        
+        etMobile = view.findViewById(R.id.etMobile)
+        etPassword = view.findViewById(R.id.etPassword)
+        etConfirmPassword = view.findViewById(R.id.etConfirmPassword)
+        btnRegister = view.findViewById(R.id.btnRegister)
+        btnBackToLogin = view.findViewById(R.id.btnBackToLogin)
+        progressBar = view.findViewById(R.id.progressBar)
+        
+        // 注册按钮
+        btnRegister.setOnClickListener {
+            val mobile = etMobile.text?.toString()?.trim() ?: ""
+            val password = etPassword.text?.toString() ?: ""
+            val confirmPassword = etConfirmPassword.text?.toString() ?: ""
+            
+            if (TextUtils.isEmpty(mobile)) {
+                Toast.makeText(requireContext(), UiConstants.MSG_MOBILE_EMPTY, Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            if (TextUtils.isEmpty(password)) {
+                Toast.makeText(requireContext(), UiConstants.MSG_PASSWORD_EMPTY, Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            if (password.length < 6 || password.length > 16) {
+                Toast.makeText(requireContext(), UiConstants.MSG_PASSWORD_INVALID, Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            if (password != confirmPassword) {
+                Toast.makeText(requireContext(), UiConstants.MSG_PASSWORD_NOT_MATCH, Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            viewModel.register(mobile, password)
+        }
+        
+        // 返回登录按钮
+        btnBackToLogin.setOnClickListener {
+            findNavController().popBackStack()
+        }
+        
+        // 观察注册状态
+        lifecycleScope.launch {
+            viewModel.registerState.collect { state ->
+                when (state) {
+                    is RegisterState.Idle -> {
+                        progressBar.visibility = View.GONE
+                        btnRegister.isEnabled = true
+                    }
+                    is RegisterState.Loading -> {
+                        progressBar.visibility = View.VISIBLE
+                        btnRegister.isEnabled = false
+                    }
+                    is RegisterState.Success -> {
+                        progressBar.visibility = View.GONE
+                        btnRegister.isEnabled = true
+                        Toast.makeText(requireContext(), state.message, Toast.LENGTH_SHORT).show()
+                        // 注册成功后自动登录,导航到主界面
+                        findNavController().navigate(R.id.action_registerFragment_to_mainFragment)
+                    }
+                    is RegisterState.Error -> {
+                        progressBar.visibility = View.GONE
+                        btnRegister.isEnabled = true
+                        Toast.makeText(requireContext(), state.message, Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+    }
+}
+

+ 68 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/LoginViewModel.kt

@@ -0,0 +1,68 @@
+package com.narutohuo.xindazhou.user.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import com.narutohuo.xindazhou.user.repository.AuthRepository
+import com.narutohuo.xindazhou.user.ui.constant.UiConstants
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+
+/**
+ * 登录状态
+ */
+sealed class LoginState {
+    object Idle : LoginState()
+    object Loading : LoginState()
+    data class Success(val message: String) : LoginState()
+    data class Error(val message: String) : LoginState()
+}
+
+/**
+ * 登录ViewModel
+ */
+class LoginViewModel(
+    application: Application,
+    private val authRepository: AuthRepository
+) : AndroidViewModel(application) {
+    
+    companion object {
+        private const val MIN_PASSWORD_LENGTH = 6
+        private const val MAX_PASSWORD_LENGTH = 16
+    }
+    
+    private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)
+    val loginState: StateFlow<LoginState> = _loginState
+    
+    /**
+     * 登录
+     * 
+     * @param mobile 手机号
+     * @param password 密码
+     */
+    fun login(mobile: String, password: String) {
+        viewModelScope.launch {
+            _loginState.value = LoginState.Loading
+            
+            // 输入验证
+            if (mobile.isBlank()) {
+                _loginState.value = LoginState.Error("手机号不能为空")
+                return@launch
+            }
+            
+            if (password.length < MIN_PASSWORD_LENGTH || password.length > MAX_PASSWORD_LENGTH) {
+                _loginState.value = LoginState.Error("密码长度应为${MIN_PASSWORD_LENGTH}-${MAX_PASSWORD_LENGTH}位")
+                return@launch
+            }
+            
+            authRepository.login(mobile, password)
+                .onSuccess {
+                    _loginState.value = LoginState.Success(UiConstants.MSG_LOGIN_SUCCESS)
+                }
+                .onFailure { e ->
+                    _loginState.value = LoginState.Error(e.message ?: UiConstants.MSG_LOGIN_FAILED)
+                }
+        }
+    }
+}

+ 23 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/LoginViewModelFactory.kt

@@ -0,0 +1,23 @@
+package com.narutohuo.xindazhou.user.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.narutohuo.xindazhou.user.repository.AuthRepository
+
+/**
+ * LoginViewModel工厂类
+ */
+class LoginViewModelFactory(
+    private val application: Application
+) : ViewModelProvider.Factory {
+    
+    @Suppress("UNCHECKED_CAST")
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+        if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
+            val authRepository = AuthRepository()
+            return LoginViewModel(application, authRepository) as T
+        }
+        throw IllegalArgumentException("Unknown ViewModel class")
+    }
+}

+ 68 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/RegisterViewModel.kt

@@ -0,0 +1,68 @@
+package com.narutohuo.xindazhou.user.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import com.narutohuo.xindazhou.user.repository.AuthRepository
+import com.narutohuo.xindazhou.user.ui.constant.UiConstants
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+
+/**
+ * 注册状态
+ */
+sealed class RegisterState {
+    object Idle : RegisterState()
+    object Loading : RegisterState()
+    data class Success(val message: String) : RegisterState()
+    data class Error(val message: String) : RegisterState()
+}
+
+/**
+ * 注册ViewModel
+ */
+class RegisterViewModel(
+    application: Application,
+    private val authRepository: AuthRepository
+) : AndroidViewModel(application) {
+    
+    companion object {
+        private const val MIN_PASSWORD_LENGTH = 6
+        private const val MAX_PASSWORD_LENGTH = 16
+    }
+    
+    private val _registerState = MutableStateFlow<RegisterState>(RegisterState.Idle)
+    val registerState: StateFlow<RegisterState> = _registerState
+    
+    /**
+     * 注册
+     * 
+     * @param mobile 手机号
+     * @param password 密码
+     */
+    fun register(mobile: String, password: String) {
+        viewModelScope.launch {
+            _registerState.value = RegisterState.Loading
+            
+            // 输入验证
+            if (mobile.isBlank()) {
+                _registerState.value = RegisterState.Error("手机号不能为空")
+                return@launch
+            }
+            
+            if (password.length < MIN_PASSWORD_LENGTH || password.length > MAX_PASSWORD_LENGTH) {
+                _registerState.value = RegisterState.Error("密码长度应为${MIN_PASSWORD_LENGTH}-${MAX_PASSWORD_LENGTH}位")
+                return@launch
+            }
+            
+            authRepository.register(mobile, password)
+                .onSuccess {
+                    _registerState.value = RegisterState.Success(UiConstants.MSG_REGISTER_SUCCESS)
+                }
+                .onFailure { e ->
+                    _registerState.value = RegisterState.Error(e.message ?: UiConstants.MSG_REGISTER_FAILED)
+                }
+        }
+    }
+}

+ 23 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/RegisterViewModelFactory.kt

@@ -0,0 +1,23 @@
+package com.narutohuo.xindazhou.user.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.narutohuo.xindazhou.user.repository.AuthRepository
+
+/**
+ * RegisterViewModel工厂类
+ */
+class RegisterViewModelFactory(
+    private val application: Application
+) : ViewModelProvider.Factory {
+    
+    @Suppress("UNCHECKED_CAST")
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+        if (modelClass.isAssignableFrom(RegisterViewModel::class.java)) {
+            val authRepository = AuthRepository()
+            return RegisterViewModel(application, authRepository) as T
+        }
+        throw IllegalArgumentException("Unknown ViewModel class")
+    }
+}

+ 184 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/UserViewModel.kt

@@ -0,0 +1,184 @@
+package com.narutohuo.xindazhou.user.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import com.narutohuo.xindazhou.socketio.model.SocketIOResponse
+import com.narutohuo.xindazhou.user.repository.SocketIORepository
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.launch
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * 用户页面状态
+ */
+data class UserUiState(
+    val isConnected: Boolean = false,
+    val logs: List<String> = emptyList()
+)
+
+/**
+ * 用户ViewModel
+ * 
+ * 负责管理 SocketIO 连接状态、日志列表、报警消息等业务逻辑
+ */
+class UserViewModel(
+    application: Application,
+    private val socketIORepository: SocketIORepository = SocketIORepository()
+) : AndroidViewModel(application) {
+    
+    private val dateFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
+    
+    private val _uiState = MutableStateFlow(UserUiState())
+    val uiState: StateFlow<UserUiState> = _uiState
+    
+    private val _alarmMessage = MutableStateFlow<SocketIOResponse?>(null)
+    val alarmMessage: SharedFlow<SocketIOResponse?> = _alarmMessage.asSharedFlow()
+    
+    private val _errorMessage = MutableStateFlow<String?>(null)
+    val errorMessage: SharedFlow<String?> = _errorMessage.asSharedFlow()
+    
+    init {
+        // 观察连接状态
+        observeConnectionState()
+        // 观察日志消息
+        observeLogMessage()
+        // 观察车辆控制响应
+        observeVehicleControlResponse()
+        // 观察车辆报警
+        observeVehicleAlarm()
+        // 初始化连接状态
+        updateConnectionStatus()
+    }
+    
+    /**
+     * 连接 SocketIO
+     */
+    fun connect() {
+        viewModelScope.launch {
+            addLog("正在连接SocketIO服务器...")
+            socketIORepository.connect()
+                .onSuccess {
+                    addLog("连接请求已发送")
+                }
+                .onFailure { e ->
+                    val errorMsg = "连接失败:${e.message}"
+                    addLog(errorMsg)
+                    addLog("异常详情:${e.javaClass.simpleName}")
+                    _errorMessage.value = errorMsg
+                }
+        }
+    }
+    
+    /**
+     * 断开 SocketIO 连接
+     */
+    fun disconnect() {
+        viewModelScope.launch {
+            socketIORepository.disconnect()
+                .onSuccess {
+                    addLog("已断开连接")
+                }
+                .onFailure { e ->
+                    val errorMsg = "断开连接失败:${e.message}"
+                    addLog(errorMsg)
+                    _errorMessage.value = errorMsg
+                }
+            updateConnectionStatus()
+        }
+    }
+    
+    /**
+     * 发送寻车指令
+     */
+    fun sendFindVehicleCommand() {
+        viewModelScope.launch {
+            socketIORepository.sendVehicleControl("find_vehicle", 1L)
+                .onSuccess {
+                    addLog("📤 发送寻车指令:command=find_vehicle")
+                }
+                .onFailure { e ->
+                    val errorMsg = e.message ?: "发送失败"
+                    addLog("错误:$errorMsg")
+                    _errorMessage.value = errorMsg
+                }
+        }
+    }
+    
+    /**
+     * 观察连接状态
+     */
+    private fun observeConnectionState() {
+        viewModelScope.launch {
+            socketIORepository.connectionState.collect { isConnected ->
+                _uiState.value = _uiState.value.copy(isConnected = isConnected)
+            }
+        }
+    }
+    
+    /**
+     * 观察日志消息
+     */
+    private fun observeLogMessage() {
+        viewModelScope.launch {
+            socketIORepository.logMessage.collect { message ->
+                addLog(message)
+            }
+        }
+    }
+    
+    /**
+     * 观察车辆控制响应
+     */
+    private fun observeVehicleControlResponse() {
+        viewModelScope.launch {
+            socketIORepository.vehicleControlResponse.collect { response ->
+                // 响应已在 logMessage 中处理,这里可以添加其他业务逻辑
+            }
+        }
+    }
+    
+    /**
+     * 观察车辆报警
+     */
+    private fun observeVehicleAlarm() {
+        viewModelScope.launch {
+            socketIORepository.vehicleAlarm.collect { response ->
+                val time = dateFormat.format(Date(response.timestamp))
+                addLog("   时间: $time")
+                _alarmMessage.value = response
+            }
+        }
+    }
+    
+    /**
+     * 更新连接状态
+     */
+    private fun updateConnectionStatus() {
+        _uiState.value = _uiState.value.copy(
+            isConnected = socketIORepository.isConnected()
+        )
+    }
+    
+    /**
+     * 添加日志
+     */
+    private fun addLog(message: String) {
+        val time = dateFormat.format(Date())
+        val logEntry = "[$time] $message"
+        _uiState.value = _uiState.value.copy(
+            logs = _uiState.value.logs + logEntry
+        )
+    }
+    
+    /**
+     * 清除错误消息
+     */
+    fun clearErrorMessage() {
+        _errorMessage.value = null
+    }
+}

+ 23 - 0
app/src/main/java/com/narutohuo/xindazhou/user/ui/viewmodel/UserViewModelFactory.kt

@@ -0,0 +1,23 @@
+package com.narutohuo.xindazhou.user.ui.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.narutohuo.xindazhou.user.repository.SocketIORepository
+
+/**
+ * UserViewModel工厂类
+ */
+class UserViewModelFactory(
+    private val application: Application
+) : ViewModelProvider.Factory {
+    
+    @Suppress("UNCHECKED_CAST")
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+        if (modelClass.isAssignableFrom(UserViewModel::class.java)) {
+            val socketIORepository = SocketIORepository()
+            return UserViewModel(application, socketIORepository) as T
+        }
+        throw IllegalArgumentException("Unknown ViewModel class")
+    }
+}

+ 910 - 0
app/src/main/java/com/narutohuo/xindazhou/vehicle/ui/VehicleFragment.kt

@@ -0,0 +1,910 @@
+package com.narutohuo.xindazhou.vehicle.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.EditText
+import android.widget.RadioButton
+import android.widget.Switch
+import android.widget.TextView
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import com.narutohuo.xindazhou.R
+import com.narutohuo.xindazhou.ble.api.BLEService
+import com.narutohuo.xindazhou.ble.callback.DataCallback
+import com.narutohuo.xindazhou.ble.config.BLEConstants
+import com.narutohuo.xindazhou.ble.factory.BLEServiceFactory
+import com.narutohuo.xindazhou.ble.model.AppControlInstruction
+import com.narutohuo.xindazhou.ble.model.BLECommand
+import com.narutohuo.xindazhou.ble.model.BLEDevice
+import com.narutohuo.xindazhou.ble.model.BLEResponse
+import com.narutohuo.xindazhou.ble.model.SystemControlInstruction
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+
+/**
+ * 车辆Fragment
+ * 
+ * 主要功能:
+ * 1. 蓝牙连接管理
+ * 2. 实时状态显示
+ * 3. 快捷控制(设撤防、上下电、寻车、锁控制)
+ * 4. 系统控制(各种开关、时间设置、氛围灯等)
+ * 5. 系统设置(钥匙学码、灵敏度、报警设置等)
+ * 
+ * 蓝牙协议说明:
+ * - 服务UUID: 0000adb0-0000-1000-8000-00805f9b34fb
+ * - Notify特征值: 0000adb1-0000-1000-8000-00805f9b34fb
+ * - Write特征值: 0000adb2-0000-1000-8000-00805f9b34fb
+ * 
+ * 功能码:
+ * - 0x01: 握手
+ * - 0x02: 应用控制
+ * - 0x03: 系统控制
+ * - 0x04: 系统查询
+ * - 0x05: 系统设置
+ * - 0x06: MTU设置值查询
+ */
+class VehicleFragment : Fragment() {
+
+    // 蓝牙服务
+    private lateinit var bleService: BLEService
+    
+    // 当前连接的设备(可以从用户设置或车辆列表获取)
+    private var currentBleDevice: BLEDevice? = null
+    
+    // 当前设防状态(用于切换)
+    private var isDefenseOn = false
+    // 当前上电状态(用于切换)
+    private var isPowerOn = false
+
+    // 蓝牙连接状态
+    private lateinit var tvBluetoothStatus: TextView
+    private lateinit var btnConnectBluetooth: Button
+
+    // 实时状态
+    private lateinit var tvDefenseStatus: TextView
+    private lateinit var tvPowerStatus: TextView
+    private lateinit var tvDoorLockStatus: TextView
+    private lateinit var tvBatteryLevel: TextView
+    private lateinit var btnQueryVehicleInfo: Button
+
+    // 快捷控制
+    private lateinit var btnDefense: Button
+    private lateinit var btnPower: Button
+    private lateinit var btnFindCar: Button
+    private lateinit var btnSeatLock: Button
+    private lateinit var btnHandlebarLock: Button
+    private lateinit var btnTrunkLock: Button
+
+    // 系统控制 - 开关
+    private lateinit var switchInductionUnlock: Switch
+    private lateinit var switchTheftLock: Switch
+    private lateinit var switchSeatSensor: Switch
+    private lateinit var switchVehicleSound: Switch
+    private lateinit var switchAutoHeadlight: Switch
+    private lateinit var switchAtmosphereLight: Switch
+    private lateinit var switchVoiceBroadcast: Switch
+    private lateinit var switchFollowMeHome: Switch
+    private lateinit var switchABS: Switch
+    private lateinit var switchTCS: Switch
+
+    // 系统控制 - 时间设置
+    private lateinit var etAutoPowerOffTime: EditText
+    private lateinit var btnSetAutoPowerOffTime: Button
+    private lateinit var etAutoDefenseTime: EditText
+    private lateinit var btnSetAutoDefenseTime: Button
+    private lateinit var etEnterPTime: EditText
+    private lateinit var btnSetEnterPTime: Button
+
+    // 系统控制 - 其他设置
+    private lateinit var etBluetoothSpeakerVolume: EditText
+    private lateinit var btnSetBluetoothSpeakerVolume: Button
+    private lateinit var etLowBatteryThreshold: EditText
+    private lateinit var btnSetLowBatteryThreshold: Button
+    private lateinit var etAtmosphereLightR: EditText
+    private lateinit var etAtmosphereLightG: EditText
+    private lateinit var etAtmosphereLightB: EditText
+    private lateinit var btnSetAtmosphereLightColor: Button
+    private lateinit var btnCollectRSSI: Button
+    private lateinit var btnResetTripMileage: Button
+
+    // 系统设置
+    private lateinit var btnKeyLearning: Button
+    private lateinit var btnSetVibrationSensitivity: Button
+    private lateinit var switchAlarmReport: Switch
+    private lateinit var btnSetTiltAlarmThreshold: Button
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_vehicle, container, false)
+    }
+
+    private var rootView: View? = null
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        rootView = view
+
+        // 初始化蓝牙服务
+        bleService = BLEServiceFactory.create(requireContext())
+        
+        initViews(view)
+        setupClickListeners()
+        setupDataListener()
+        updateConnectionStatus()
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        rootView = null
+        // 清理数据监听
+        bleService.setDataReceivedListener(object : DataCallback {
+            override fun onDataReceived(data: ByteArray) {
+                // 空实现,避免内存泄漏
+            }
+        })
+    }
+
+    private fun initViews(view: View) {
+        // 蓝牙连接状态
+        tvBluetoothStatus = view.findViewById(R.id.tvBluetoothStatus)
+        btnConnectBluetooth = view.findViewById(R.id.btnConnectBluetooth)
+
+        // 实时状态
+        tvDefenseStatus = view.findViewById(R.id.tvDefenseStatus)
+        tvPowerStatus = view.findViewById(R.id.tvPowerStatus)
+        tvDoorLockStatus = view.findViewById(R.id.tvDoorLockStatus)
+        tvBatteryLevel = view.findViewById(R.id.tvBatteryLevel)
+        btnQueryVehicleInfo = view.findViewById(R.id.btnQueryVehicleInfo)
+
+        // 快捷控制
+        btnDefense = view.findViewById(R.id.btnDefense)
+        btnPower = view.findViewById(R.id.btnPower)
+        btnFindCar = view.findViewById(R.id.btnFindCar)
+        btnSeatLock = view.findViewById(R.id.btnSeatLock)
+        btnHandlebarLock = view.findViewById(R.id.btnHandlebarLock)
+        btnTrunkLock = view.findViewById(R.id.btnTrunkLock)
+
+        // 系统控制 - 开关
+        switchInductionUnlock = view.findViewById(R.id.switchInductionUnlock)
+        switchTheftLock = view.findViewById(R.id.switchTheftLock)
+        switchSeatSensor = view.findViewById(R.id.switchSeatSensor)
+        switchVehicleSound = view.findViewById(R.id.switchVehicleSound)
+        switchAutoHeadlight = view.findViewById(R.id.switchAutoHeadlight)
+        switchAtmosphereLight = view.findViewById(R.id.switchAtmosphereLight)
+        switchVoiceBroadcast = view.findViewById(R.id.switchVoiceBroadcast)
+        switchFollowMeHome = view.findViewById(R.id.switchFollowMeHome)
+        switchABS = view.findViewById(R.id.switchABS)
+        switchTCS = view.findViewById(R.id.switchTCS)
+
+        // 系统控制 - 时间设置
+        etAutoPowerOffTime = view.findViewById(R.id.etAutoPowerOffTime)
+        btnSetAutoPowerOffTime = view.findViewById(R.id.btnSetAutoPowerOffTime)
+        etAutoDefenseTime = view.findViewById(R.id.etAutoDefenseTime)
+        btnSetAutoDefenseTime = view.findViewById(R.id.btnSetAutoDefenseTime)
+        etEnterPTime = view.findViewById(R.id.etEnterPTime)
+        btnSetEnterPTime = view.findViewById(R.id.btnSetEnterPTime)
+
+        // 系统控制 - 其他设置
+        etBluetoothSpeakerVolume = view.findViewById(R.id.etBluetoothSpeakerVolume)
+        btnSetBluetoothSpeakerVolume = view.findViewById(R.id.btnSetBluetoothSpeakerVolume)
+        etLowBatteryThreshold = view.findViewById(R.id.etLowBatteryThreshold)
+        btnSetLowBatteryThreshold = view.findViewById(R.id.btnSetLowBatteryThreshold)
+        etAtmosphereLightR = view.findViewById(R.id.etAtmosphereLightR)
+        etAtmosphereLightG = view.findViewById(R.id.etAtmosphereLightG)
+        etAtmosphereLightB = view.findViewById(R.id.etAtmosphereLightB)
+        btnSetAtmosphereLightColor = view.findViewById(R.id.btnSetAtmosphereLightColor)
+        btnCollectRSSI = view.findViewById(R.id.btnCollectRSSI)
+        btnResetTripMileage = view.findViewById(R.id.btnResetTripMileage)
+
+        // 系统设置
+        btnKeyLearning = view.findViewById(R.id.btnKeyLearning)
+        btnSetVibrationSensitivity = view.findViewById(R.id.btnSetVibrationSensitivity)
+        switchAlarmReport = view.findViewById(R.id.switchAlarmReport)
+        btnSetTiltAlarmThreshold = view.findViewById(R.id.btnSetTiltAlarmThreshold)
+    }
+
+    /**
+     * 设置数据接收监听
+     */
+    private fun setupDataListener() {
+        bleService.setDataReceivedListener(object : DataCallback {
+            override fun onDataReceived(data: ByteArray) {
+                // 处理主动推送的数据
+                // 这里可以根据功能码和指令类型解析数据
+                activity?.runOnUiThread {
+                    // 更新UI状态
+                }
+            }
+        })
+    }
+
+    /**
+     * 更新连接状态显示
+     */
+    private fun updateConnectionStatus() {
+        if (bleService.isConnected()) {
+            tvBluetoothStatus.text = "蓝牙已连接"
+            btnConnectBluetooth.text = "断开"
+        } else {
+            tvBluetoothStatus.text = "蓝牙未连接"
+            btnConnectBluetooth.text = "连接"
+        }
+    }
+
+    private fun setupClickListeners() {
+        // 蓝牙连接
+        btnConnectBluetooth.setOnClickListener {
+            if (bleService.isConnected()) {
+                // 断开连接
+                bleService.disconnect()
+                updateConnectionStatus()
+                Toast.makeText(context, "已断开连接", Toast.LENGTH_SHORT).show()
+            } else {
+                // 连接设备
+                // TODO: 从用户设置或车辆列表获取设备信息
+                // 这里需要先扫描或从已保存的设备列表中选择
+                if (currentBleDevice == null) {
+                    Toast.makeText(context, "请先选择要连接的设备", Toast.LENGTH_SHORT).show()
+                    // 可以打开设备选择对话框或扫描界面
+                    return@setOnClickListener
+                }
+                
+                connectToDevice(currentBleDevice!!)
+            }
+        }
+
+        // 查询车辆信息
+        btnQueryVehicleInfo.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            bleService.queryVehicleInfo { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        val data = response.data
+                        if (data != null) {
+                            parseVehicleInfo(data)
+                            Toast.makeText(context, "查询成功", Toast.LENGTH_SHORT).show()
+                        } else {
+                            Toast.makeText(context, "查询失败: 数据为空", Toast.LENGTH_SHORT).show()
+                        }
+                    } else {
+                        Toast.makeText(context, "查询失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // ========== 快捷控制 ==========
+        // 设撤防
+        btnDefense.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val action = if (isDefenseOn) 0x00.toByte() else 0x01.toByte()
+            isDefenseOn = !isDefenseOn
+            
+            bleService.sendAppControlCommand(AppControlInstruction.SET_DEFENSE, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, if (action == 0x01.toByte()) "设防成功" else "撤防成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        isDefenseOn = !isDefenseOn // 恢复状态
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 上下电
+        btnPower.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val action = if (isPowerOn) 0x00.toByte() else 0x01.toByte()
+            isPowerOn = !isPowerOn
+            
+            bleService.sendAppControlCommand(AppControlInstruction.POWER_ON_OFF, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, if (action == 0x01.toByte()) "上电成功" else "下电成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        isPowerOn = !isPowerOn // 恢复状态
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 寻车
+        btnFindCar.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            bleService.sendAppControlCommand(AppControlInstruction.FIND_CAR, byteArrayOf(0x01)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "寻车成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "寻车失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 座桶锁
+        btnSeatLock.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            bleService.sendAppControlCommand(AppControlInstruction.SEAT_LOCK, byteArrayOf(0x01)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "座桶锁已打开", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 龙头锁
+        btnHandlebarLock.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            // 切换状态(需要根据当前状态决定)
+            val action = 0x01.toByte() // 假设当前是关闭,点击后打开
+            bleService.sendAppControlCommand(AppControlInstruction.HANDLEBAR_LOCK, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, if (action == 0x01.toByte()) "龙头锁已打开" else "龙头锁已关闭", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 尾箱锁
+        btnTrunkLock.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val action = 0x01.toByte() // 假设当前是关闭,点击后打开
+            bleService.sendAppControlCommand(AppControlInstruction.TRUNK_LOCK, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, if (action == 0x01.toByte()) "尾箱锁已打开" else "尾箱锁已关闭", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // ========== 系统控制 - 开关 ==========
+        // 感应解锁开关
+        switchInductionUnlock.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchInductionUnlock.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.SENSOR_UNLOCK, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchInductionUnlock.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 被盗锁定开关
+        switchTheftLock.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchTheftLock.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.STOLEN_LOCK, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchTheftLock.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 座椅感应开关
+        switchSeatSensor.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchSeatSensor.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.SEAT_SENSOR, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchSeatSensor.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 车辆音效开关
+        switchVehicleSound.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchVehicleSound.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.SOUND_EFFECT, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchVehicleSound.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 自动大灯开关
+        switchAutoHeadlight.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchAutoHeadlight.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.AUTO_HEADLIGHT, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchAutoHeadlight.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 氛围灯开关
+        switchAtmosphereLight.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchAtmosphereLight.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.AMBIENT_LIGHT, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchAtmosphereLight.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 语音播报开关
+        switchVoiceBroadcast.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchVoiceBroadcast.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.VOICE_BROADCAST, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchVoiceBroadcast.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 伴我回家
+        switchFollowMeHome.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchFollowMeHome.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.WALK_ME_HOME, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchFollowMeHome.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // ABS
+        switchABS.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchABS.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.ABS, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchABS.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // TCS
+        switchTCS.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchTCS.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            bleService.sendSystemControlCommand(SystemControlInstruction.TCS, byteArrayOf(action)) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchTCS.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // ========== 系统控制 - 时间设置 ==========
+        // 自动下电时间
+        btnSetAutoPowerOffTime.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val time = etAutoPowerOffTime.text.toString().toIntOrNull() ?: 300
+            if (time < 0 || time > 60000) {
+                Toast.makeText(context, "时间范围:0-60000秒", Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            val data = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(time.toShort()).array()
+            bleService.sendSystemControlCommand(SystemControlInstruction.AUTO_POWER_OFF_TIME, data) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 自动设防时间
+        btnSetAutoDefenseTime.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val time = etAutoDefenseTime.text.toString().toIntOrNull() ?: 5
+            if (time < 0 || time > 60000) {
+                Toast.makeText(context, "时间范围:0-60000秒", Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            val data = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(time.toShort()).array()
+            bleService.sendSystemControlCommand(SystemControlInstruction.AUTO_DEFENSE_TIME, data) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 进入P档时间
+        btnSetEnterPTime.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val time = etEnterPTime.text.toString().toIntOrNull() ?: 300
+            if (time < 0 || time > 60000) {
+                Toast.makeText(context, "时间范围:0-60000秒", Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            val data = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(time.toShort()).array()
+            bleService.sendSystemControlCommand(SystemControlInstruction.ENTER_P_TIME, data) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // ========== 系统控制 - 其他设置 ==========
+        // 蓝牙音箱音量
+        btnSetBluetoothSpeakerVolume.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val volume = etBluetoothSpeakerVolume.text.toString().toIntOrNull() ?: 50
+            if (volume < 0 || volume > 100) {
+                Toast.makeText(context, "音量范围:0-100%", Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            bleService.sendSystemControlCommand(SystemControlInstruction.SPEAKER_VOLUME, byteArrayOf(volume.toByte())) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 低电量报警阈值
+        btnSetLowBatteryThreshold.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val threshold = etLowBatteryThreshold.text.toString().toIntOrNull() ?: 20
+            if (threshold < 0 || threshold > 100) {
+                Toast.makeText(context, "阈值范围:0-100%", Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+            
+            bleService.sendSystemControlCommand(SystemControlInstruction.LOW_BATTERY_ALARM, byteArrayOf(threshold.toByte())) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 氛围灯颜色
+        btnSetAtmosphereLightColor.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val r = etAtmosphereLightR.text.toString().toIntOrNull()?.coerceIn(0, 255) ?: 255
+            val g = etAtmosphereLightG.text.toString().toIntOrNull()?.coerceIn(0, 255) ?: 255
+            val b = etAtmosphereLightB.text.toString().toIntOrNull()?.coerceIn(0, 255) ?: 255
+            
+            bleService.sendSystemControlCommand(SystemControlInstruction.AMBIENT_LIGHT_COLOR, byteArrayOf(r.toByte(), g.toByte(), b.toByte())) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 感应解锁RSSI信号强度采集
+        btnCollectRSSI.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            // 这里需要选择采集位置(左前方、右前方、左后方、右后方)
+            // 简化实现:采集左前方
+            bleService.sendSystemControlCommand(SystemControlInstruction.RSSI_COLLECTION, byteArrayOf(0x01)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "RSSI采集成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "采集失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 小计里程清零
+        btnResetTripMileage.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            bleService.sendSystemControlCommand(SystemControlInstruction.RESET_MILEAGE, byteArrayOf(0x01)) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "里程清零成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // ========== 系统设置 ==========
+        // 钥匙学码(功能码 0x05, 指令类型 0x01)
+        btnKeyLearning.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val command = BLECommand(
+                functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_SETTING,
+                instructionType = 0x01.toByte(),
+                applicationData = byteArrayOf(0x01) // 有效设置
+            )
+            
+            bleService.sendCommand(command) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "钥匙学码成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 震动灵敏度(功能码 0x05, 指令类型 0x02)
+        btnSetVibrationSensitivity.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val sensitivity = when {
+                rootView?.findViewById<RadioButton>(R.id.rbSensitivity1)?.isChecked == true -> 1
+                rootView?.findViewById<RadioButton>(R.id.rbSensitivity2)?.isChecked == true -> 2
+                rootView?.findViewById<RadioButton>(R.id.rbSensitivity3)?.isChecked == true -> 3
+                rootView?.findViewById<RadioButton>(R.id.rbSensitivity4)?.isChecked == true -> 4
+                rootView?.findViewById<RadioButton>(R.id.rbSensitivity5)?.isChecked == true -> 5
+                else -> 3
+            }
+            
+            val command = BLECommand(
+                functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_SETTING,
+                instructionType = 0x02.toByte(),
+                applicationData = byteArrayOf(sensitivity.toByte())
+            )
+            
+            bleService.sendCommand(command) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 报警是否上报(功能码 0x05, 指令类型 0x03)
+        switchAlarmReport.setOnCheckedChangeListener { _, isChecked ->
+            if (!checkConnection()) {
+                switchAlarmReport.isChecked = !isChecked
+                return@setOnCheckedChangeListener
+            }
+            
+            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
+            val command = BLECommand(
+                functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_SETTING,
+                instructionType = 0x03.toByte(),
+                applicationData = byteArrayOf(action)
+            )
+            
+            bleService.sendCommand(command) { response ->
+                activity?.runOnUiThread {
+                    if (!response.success) {
+                        switchAlarmReport.isChecked = !isChecked
+                        Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+
+        // 倾倒报警阈值(功能码 0x05, 指令类型 0x04)
+        btnSetTiltAlarmThreshold.setOnClickListener {
+            if (!checkConnection()) return@setOnClickListener
+            
+            val threshold = when {
+                rootView?.findViewById<RadioButton>(R.id.rbTilt50)?.isChecked == true -> 0x32.toByte()
+                rootView?.findViewById<RadioButton>(R.id.rbTilt60)?.isChecked == true -> 0x3c.toByte()
+                rootView?.findViewById<RadioButton>(R.id.rbTilt70)?.isChecked == true -> 0x46.toByte()
+                else -> 0x3c.toByte()
+            }
+            
+            val command = BLECommand(
+                functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_SETTING,
+                instructionType = 0x04.toByte(),
+                applicationData = byteArrayOf(threshold)
+            )
+            
+            bleService.sendCommand(command) { response ->
+                activity?.runOnUiThread {
+                    if (response.success) {
+                        Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
+                    } else {
+                        Toast.makeText(context, "设置失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 检查连接状态
+     */
+    private fun checkConnection(): Boolean {
+        if (!bleService.isConnected()) {
+            Toast.makeText(context, "请先连接蓝牙设备", Toast.LENGTH_SHORT).show()
+            return false
+        }
+        return true
+    }
+
+    /**
+     * 连接到设备
+     */
+    private fun connectToDevice(device: BLEDevice) {
+        btnConnectBluetooth.isEnabled = false
+        tvBluetoothStatus.text = "连接中..."
+        
+        bleService.connect(device) { response ->
+            activity?.runOnUiThread {
+                btnConnectBluetooth.isEnabled = true
+                updateConnectionStatus()
+                
+                if (response.success) {
+                    Toast.makeText(context, "连接成功", Toast.LENGTH_SHORT).show()
+                    
+                    // 连接成功后进行握手(需要用户ID,这里需要从用户信息获取)
+                    // TODO: 从用户信息获取userId和userType
+                    // val userId = getUserId() // 16字节
+                    // val userType = BLEConstants.USER_TYPE_OWNER
+                    // bleService.handshake(userId, userType) { handshakeResponse ->
+                    //     // 处理握手结果
+                    // }
+                } else {
+                    Toast.makeText(context, "连接失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                }
+            }
+        }
+    }
+
+    /**
+     * 解析车辆信息
+     */
+    private fun parseVehicleInfo(data: ByteArray) {
+        if (data.size < 84) {
+            return
+        }
+        
+        // 解析车辆信息(根据协议文档)
+        val defenseStatus = if (data[0] == 0x01.toByte()) "设防" else "撤防"
+        val powerStatus = if (data[1] == 0x01.toByte()) "上电" else "下电"
+        val doorLockStatus = if (data[2] == 0x01.toByte()) "关闭" else "打开"
+        
+        // 电池信息(byte40开始是电池1,byte48开始是电池2)
+        val battery1SOC = if (data.size > 42) data[42].toInt() and 0xFF else 0
+        val battery2SOC = if (data.size > 50) data[50].toInt() and 0xFF else 0
+        val batteryLevel = (battery1SOC + battery2SOC) / 2 // 平均电量
+        
+        // 更新UI
+        tvDefenseStatus.text = defenseStatus
+        tvPowerStatus.text = powerStatus
+        tvDoorLockStatus.text = doorLockStatus
+        tvBatteryLevel.text = "$batteryLevel%"
+        
+        // 更新开关状态
+        switchInductionUnlock.isChecked = data.size > 8 && data[8] == 0x01.toByte()
+        switchTheftLock.isChecked = data.size > 10 && data[10] == 0x01.toByte()
+        switchSeatSensor.isChecked = data.size > 11 && data[11] == 0x01.toByte()
+        switchVehicleSound.isChecked = data.size > 12 && data[12] == 0x01.toByte()
+        switchAutoHeadlight.isChecked = data.size > 13 && data[13] == 0x01.toByte()
+        switchAtmosphereLight.isChecked = data.size > 26 && data[26] == 0x01.toByte()
+        switchVoiceBroadcast.isChecked = data.size > 27 && data[27] == 0x01.toByte()
+        switchFollowMeHome.isChecked = data.size > 28 && data[28] == 0x01.toByte()
+        switchABS.isChecked = data.size > 38 && data[38] == 0x01.toByte()
+        switchTCS.isChecked = data.size > 39 && data[39] == 0x01.toByte()
+    }
+}

+ 22 - 0
app/src/main/res/layout/activity_main.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <!-- Navigation Fragment容器 -->
+    <androidx.fragment.app.FragmentContainerView
+        android:id="@+id/navHostFragment"
+        android:name="androidx.navigation.fragment.NavHostFragment"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:defaultNavHost="true"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:navGraph="@navigation/nav_graph" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 191 - 0
app/src/main/res/layout/dialog_update.xml

@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_margin="24dp"
+    app:cardCornerRadius="16dp"
+    app:cardElevation="8dp"
+    app:cardBackgroundColor="@android:color/white">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:padding="24dp">
+
+        <!-- 标题区域 -->
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:layout_marginBottom="16dp">
+
+            <ImageView
+                android:layout_width="48dp"
+                android:layout_height="48dp"
+                android:src="@android:drawable/ic_menu_upload"
+                android:tint="#4CAF50"
+                android:layout_marginEnd="12dp" />
+
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:orientation="vertical">
+
+                <TextView
+                    android:id="@+id/tvTitle"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="发现新版本"
+                    android:textSize="20sp"
+                    android:textStyle="bold"
+                    android:textColor="#212121" />
+
+                <TextView
+                    android:id="@+id/tvVersionName"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="v1.0.0"
+                    android:textSize="14sp"
+                    android:textColor="#757575"
+                    android:layout_marginTop="4dp" />
+            </LinearLayout>
+        </LinearLayout>
+
+        <!-- 版本描述 -->
+        <TextView
+            android:id="@+id/tvVersionDesc"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="新版本包含多项优化和修复"
+            android:textSize="14sp"
+            android:textColor="#424242"
+            android:layout_marginBottom="12dp"
+            android:visibility="gone" />
+
+        <!-- 更新日志 -->
+        <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:maxHeight="150dp"
+            android:layout_marginBottom="16dp"
+            android:visibility="gone"
+            android:id="@+id/svUpdateLog">
+
+            <TextView
+                android:id="@+id/tvUpdateLog"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="更新内容:\n• 修复已知问题\n• 优化用户体验"
+                android:textSize="13sp"
+                android:textColor="#616161"
+                android:background="#F5F5F5"
+                android:padding="12dp" />
+        </ScrollView>
+
+        <!-- 下载进度区域 -->
+        <LinearLayout
+            android:id="@+id/llProgress"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:visibility="gone"
+            android:layout_marginBottom="16dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:gravity="center_vertical"
+                android:layout_marginBottom="8dp">
+
+                <ProgressBar
+                    android:id="@+id/progressBar"
+                    style="?android:attr/progressBarStyleHorizontal"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:max="100"
+                    android:progress="0"
+                    android:progressTint="#4CAF50" />
+
+                <TextView
+                    android:id="@+id/tvProgress"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="0%"
+                    android:textSize="12sp"
+                    android:textColor="#757575"
+                    android:layout_marginStart="8dp"
+                    android:minWidth="40dp"
+                    android:gravity="center" />
+            </LinearLayout>
+
+            <TextView
+                android:id="@+id/tvDownloadStatus"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="正在下载..."
+                android:textSize="12sp"
+                android:textColor="#757575"
+                android:gravity="center" />
+        </LinearLayout>
+
+        <!-- 强制更新提示 -->
+        <TextView
+            android:id="@+id/tvForceUpdate"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="此版本为强制更新,必须更新后才能继续使用"
+            android:textSize="12sp"
+            android:textColor="#FF5722"
+            android:background="#FFF3E0"
+            android:padding="8dp"
+            android:gravity="center"
+            android:layout_marginBottom="16dp"
+            android:visibility="gone" />
+
+        <!-- 按钮区域 -->
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="end">
+
+            <Button
+                android:id="@+id/btnLater"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="稍后更新"
+                android:textColor="#757575"
+                android:background="?attr/selectableItemBackgroundBorderless"
+                android:paddingStart="16dp"
+                android:paddingEnd="16dp"
+                android:paddingTop="8dp"
+                android:paddingBottom="8dp"
+                android:minHeight="0dp"
+                android:minWidth="0dp"
+                android:layout_marginEnd="8dp"
+                android:visibility="gone" />
+
+            <Button
+                android:id="@+id/btnUpdate"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="立即更新"
+                android:textColor="@android:color/white"
+                android:background="#4CAF50"
+                android:paddingStart="24dp"
+                android:paddingEnd="24dp"
+                android:paddingTop="12dp"
+                android:paddingBottom="12dp"
+                android:minHeight="0dp"
+                android:minWidth="0dp"
+                android:elevation="2dp" />
+        </LinearLayout>
+    </LinearLayout>
+</androidx.cardview.widget.CardView>
+

+ 141 - 0
app/src/main/res/layout/fragment_login.xml

@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="24dp"
+    android:background="@android:color/white"
+    tools:context=".user.ui.login.LoginFragment">
+
+    <!-- Logo 或应用名称 -->
+    <TextView
+        android:id="@+id/tvAppName"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="新大洲本田"
+        android:textSize="32sp"
+        android:textStyle="bold"
+        android:textColor="@android:color/black"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="80dp" />
+
+    <TextView
+        android:id="@+id/tvSubtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="欢迎登录"
+        android:textSize="16sp"
+        android:textColor="@android:color/darker_gray"
+        app:layout_constraintTop_toBottomOf="@id/tvAppName"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="8dp" />
+
+    <!-- 手机号输入框 -->
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/tilMobile"
+        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:hint="手机号"
+        app:layout_constraintTop_toBottomOf="@id/tvSubtitle"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="48dp">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/etMobile"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="phone"
+            android:maxLines="1" />
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <!-- 密码输入框 -->
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/tilPassword"
+        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:hint="密码"
+        app:passwordToggleEnabled="true"
+        app:layout_constraintTop_toBottomOf="@id/tilMobile"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="16dp">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/etPassword"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="textPassword"
+            android:maxLines="1" />
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <!-- 登录按钮 -->
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/btnLogin"
+        android:layout_width="0dp"
+        android:layout_height="56dp"
+        android:text="登录"
+        android:textSize="16sp"
+        app:layout_constraintTop_toBottomOf="@id/tilPassword"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="32dp" />
+
+    <!-- 注册按钮 -->
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/btnRegister"
+        style="@style/Widget.MaterialComponents.Button.TextButton"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:text="还没有账号?立即注册"
+        app:layout_constraintTop_toBottomOf="@id/btnLogin"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="16dp" />
+
+    <!-- 加载指示器 -->
+    <ProgressBar
+        android:id="@+id/progressBar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        app:layout_constraintTop_toBottomOf="@id/btnLogin"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="16dp" />
+
+    <!-- 服务器配置按钮(左下角) -->
+    <ImageView
+        android:id="@+id/ivServerConfig"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:src="@android:drawable/ic_menu_preferences"
+        android:background="?attr/selectableItemBackgroundBorderless"
+        android:padding="8dp"
+        android:contentDescription="服务器配置"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        android:layout_margin="16dp"
+        android:alpha="0.6"
+        tools:ignore="ContentDescription" />
+
+    <!-- 分享按钮(右下角) -->
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+        android:id="@+id/fabShare"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@android:drawable/ic_menu_share"
+        android:contentDescription="分享测试"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_margin="16dp"
+        app:tint="@android:color/white" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
+

+ 34 - 0
app/src/main/res/layout/fragment_main.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!-- Fragment容器,用于显示各个业务模块的Fragment -->
+    <androidx.fragment.app.FragmentContainerView
+        android:id="@+id/navHostFragment"
+        android:name="androidx.navigation.fragment.NavHostFragment"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:layout_constraintBottom_toTopOf="@+id/bottomNavView"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:defaultNavHost="true"
+        app:navGraph="@navigation/main_nav_graph" />
+
+    <!-- 底部导航栏 -->
+    <com.google.android.material.bottomnavigation.BottomNavigationView
+        android:id="@+id/bottomNavView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/windowBackground"
+        app:itemIconTint="@android:color/black"
+        app:itemTextColor="@android:color/black"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:menu="@menu/bottom_navigation_menu" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
+

+ 122 - 0
app/src/main/res/layout/fragment_register.xml

@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="24dp"
+    android:background="@android:color/white"
+    tools:context=".user.ui.register.RegisterFragment">
+
+    <!-- 标题 -->
+    <TextView
+        android:id="@+id/tvTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="注册账号"
+        android:textSize="28sp"
+        android:textStyle="bold"
+        android:textColor="@android:color/black"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        android:layout_marginTop="40dp" />
+
+    <!-- 手机号输入框 -->
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/tilMobile"
+        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:hint="手机号"
+        app:layout_constraintTop_toBottomOf="@id/tvTitle"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="32dp">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/etMobile"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="phone"
+            android:maxLines="1" />
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <!-- 密码输入框 -->
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/tilPassword"
+        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:hint="密码(4-16位)"
+        app:passwordToggleEnabled="true"
+        app:layout_constraintTop_toBottomOf="@id/tilMobile"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="16dp">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/etPassword"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="textPassword"
+            android:maxLines="1" />
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <!-- 确认密码输入框 -->
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/tilConfirmPassword"
+        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:hint="确认密码"
+        app:passwordToggleEnabled="true"
+        app:layout_constraintTop_toBottomOf="@id/tilPassword"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="16dp">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/etConfirmPassword"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="textPassword"
+            android:maxLines="1" />
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <!-- 注册按钮 -->
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/btnRegister"
+        android:layout_width="0dp"
+        android:layout_height="56dp"
+        android:text="注册"
+        android:textSize="16sp"
+        app:layout_constraintTop_toBottomOf="@id/tilConfirmPassword"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="32dp" />
+
+    <!-- 返回登录按钮 -->
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/btnBackToLogin"
+        style="@style/Widget.MaterialComponents.Button.TextButton"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:text="已有账号?返回登录"
+        app:layout_constraintTop_toBottomOf="@id/btnRegister"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="16dp" />
+
+    <!-- 加载指示器 -->
+    <ProgressBar
+        android:id="@+id/progressBar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        app:layout_constraintTop_toBottomOf="@id/btnRegister"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:layout_marginTop="16dp" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
+

+ 65 - 0
app/src/main/res/layout/fragment_user_socket_test.xml

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="SocketIO 测试"
+        android:textSize="20sp"
+        android:textStyle="bold"
+        android:layout_marginBottom="16dp" />
+
+    <!-- 连接状态 -->
+    <TextView
+        android:id="@+id/tvConnectionStatus"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="连接状态:未连接"
+        android:layout_marginBottom="8dp" />
+
+    <!-- 连接/断开按钮 -->
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/btnConnect"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="连接SocketIO"
+        android:layout_marginBottom="16dp" />
+
+    <!-- 寻车按钮 -->
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/btnFindVehicle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="发送寻车指令"
+        android:layout_marginBottom="8dp"
+        android:enabled="false" />
+
+    <!-- 日志显示区域 -->
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="日志:"
+        android:textStyle="bold"
+        android:layout_marginBottom="8dp" />
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:background="@android:color/black"
+        android:padding="8dp">
+
+        <TextView
+            android:id="@+id/tvLog"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textColor="@android:color/white"
+            android:textSize="12sp"
+            android:fontFamily="monospace" />
+    </ScrollView>
+</LinearLayout>
+

+ 725 - 0
app/src/main/res/layout/fragment_vehicle.xml

@@ -0,0 +1,725 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:padding="16dp">
+
+        <!-- 蓝牙连接状态 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="4dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:padding="16dp"
+                android:gravity="center_vertical">
+
+                <TextView
+                    android:id="@+id/tvBluetoothStatus"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:text="蓝牙未连接"
+                    android:textSize="16sp"
+                    android:textStyle="bold" />
+
+                <Button
+                    android:id="@+id/btnConnectBluetooth"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="连接" />
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+        <!-- 实时状态信息 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="4dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:padding="16dp">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="实时状态"
+                    android:textSize="18sp"
+                    android:textStyle="bold"
+                    android:layout_marginBottom="12dp" />
+
+                <GridLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:columnCount="2"
+                    android:rowCount="4">
+
+                    <!-- 设防状态 -->
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="设防状态:"
+                        android:layout_marginEnd="8dp" />
+                    <TextView
+                        android:id="@+id/tvDefenseStatus"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="未知" />
+
+                    <!-- 上电状态 -->
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="上电状态:"
+                        android:layout_marginEnd="8dp" />
+                    <TextView
+                        android:id="@+id/tvPowerStatus"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="未知" />
+
+                    <!-- 门锁状态 -->
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="门锁状态:"
+                        android:layout_marginEnd="8dp" />
+                    <TextView
+                        android:id="@+id/tvDoorLockStatus"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="未知" />
+
+                    <!-- 电池电量 -->
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="电池电量:"
+                        android:layout_marginEnd="8dp" />
+                    <TextView
+                        android:id="@+id/tvBatteryLevel"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_columnWeight="1"
+                        android:text="未知" />
+                </GridLayout>
+
+                <Button
+                    android:id="@+id/btnQueryVehicleInfo"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dp"
+                    android:text="查询车辆信息" />
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+        <!-- 快捷控制 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="4dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:padding="16dp">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="快捷控制"
+                    android:textSize="18sp"
+                    android:textStyle="bold"
+                    android:layout_marginBottom="12dp" />
+
+                <!-- 第一行:设撤防、上下电、寻车 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp">
+
+                    <Button
+                        android:id="@+id/btnDefense"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:layout_marginEnd="8dp"
+                        android:text="设防" />
+
+                    <Button
+                        android:id="@+id/btnPower"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:layout_marginEnd="8dp"
+                        android:text="上电" />
+
+                    <Button
+                        android:id="@+id/btnFindCar"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="寻车" />
+                </LinearLayout>
+
+                <!-- 第二行:座桶锁、龙头锁、尾箱锁 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <Button
+                        android:id="@+id/btnSeatLock"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:layout_marginEnd="8dp"
+                        android:text="座桶锁" />
+
+                    <Button
+                        android:id="@+id/btnHandlebarLock"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:layout_marginEnd="8dp"
+                        android:text="龙头锁" />
+
+                    <Button
+                        android:id="@+id/btnTrunkLock"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="尾箱锁" />
+                </LinearLayout>
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+        <!-- 系统控制 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="4dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:padding="16dp">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="系统控制"
+                    android:textSize="18sp"
+                    android:textStyle="bold"
+                    android:layout_marginBottom="12dp" />
+
+                <!-- 开关类控制 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp">
+
+                    <Switch
+                        android:id="@+id/switchInductionUnlock"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="感应解锁" />
+
+                    <Switch
+                        android:id="@+id/switchTheftLock"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="被盗锁定" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp">
+
+                    <Switch
+                        android:id="@+id/switchSeatSensor"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="座椅感应" />
+
+                    <Switch
+                        android:id="@+id/switchVehicleSound"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="车辆音效" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp">
+
+                    <Switch
+                        android:id="@+id/switchAutoHeadlight"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="自动大灯" />
+
+                    <Switch
+                        android:id="@+id/switchAtmosphereLight"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="氛围灯" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp">
+
+                    <Switch
+                        android:id="@+id/switchVoiceBroadcast"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="语音播报" />
+
+                    <Switch
+                        android:id="@+id/switchFollowMeHome"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="伴我回家" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp">
+
+                    <Switch
+                        android:id="@+id/switchABS"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="ABS" />
+
+                    <Switch
+                        android:id="@+id/switchTCS"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="TCS" />
+                </LinearLayout>
+
+                <!-- 时间设置 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="自动下电时间(秒):" />
+
+                    <EditText
+                        android:id="@+id/etAutoPowerOffTime"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="300" />
+
+                    <Button
+                        android:id="@+id/btnSetAutoPowerOffTime"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="自动设防时间(秒):" />
+
+                    <EditText
+                        android:id="@+id/etAutoDefenseTime"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="5" />
+
+                    <Button
+                        android:id="@+id/btnSetAutoDefenseTime"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="进入P档时间(秒):" />
+
+                    <EditText
+                        android:id="@+id/etEnterPTime"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="300" />
+
+                    <Button
+                        android:id="@+id/btnSetEnterPTime"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+
+                <!-- 其他设置 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="蓝牙音箱音量(%):" />
+
+                    <EditText
+                        android:id="@+id/etBluetoothSpeakerVolume"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="50" />
+
+                    <Button
+                        android:id="@+id/btnSetBluetoothSpeakerVolume"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="低电量报警阈值(%):" />
+
+                    <EditText
+                        android:id="@+id/etLowBatteryThreshold"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="20" />
+
+                    <Button
+                        android:id="@+id/btnSetLowBatteryThreshold"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+
+                <!-- 氛围灯颜色设置 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="氛围灯颜色:" />
+
+                    <EditText
+                        android:id="@+id/etAtmosphereLightR"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="R(0-255)"
+                        android:layout_marginEnd="4dp" />
+
+                    <EditText
+                        android:id="@+id/etAtmosphereLightG"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="G(0-255)"
+                        android:layout_marginEnd="4dp" />
+
+                    <EditText
+                        android:id="@+id/etAtmosphereLightB"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:inputType="number"
+                        android:hint="B(0-255)" />
+
+                    <Button
+                        android:id="@+id/btnSetAtmosphereLightColor"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+
+                <!-- 感应解锁RSSI信号强度采集 -->
+                <Button
+                    android:id="@+id/btnCollectRSSI"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginBottom="8dp"
+                    android:text="感应解锁RSSI信号强度采集" />
+
+                <!-- 小计里程清零 -->
+                <Button
+                    android:id="@+id/btnResetTripMileage"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="小计里程清零" />
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+        <!-- 系统设置 -->
+        <androidx.cardview.widget.CardView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:cardCornerRadius="8dp"
+            app:cardElevation="4dp">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:padding="16dp">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="系统设置"
+                    android:textSize="18sp"
+                    android:textStyle="bold"
+                    android:layout_marginBottom="12dp" />
+
+                <!-- 钥匙学码 -->
+                <Button
+                    android:id="@+id/btnKeyLearning"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginBottom="8dp"
+                    android:text="钥匙学码" />
+
+                <!-- 震动灵敏度 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="震动灵敏度:" />
+
+                    <RadioGroup
+                        android:id="@+id/rgVibrationSensitivity"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="2"
+                        android:orientation="horizontal">
+
+                        <RadioButton
+                            android:id="@+id/rbSensitivity1"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="1" />
+
+                        <RadioButton
+                            android:id="@+id/rbSensitivity2"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="2" />
+
+                        <RadioButton
+                            android:id="@+id/rbSensitivity3"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="3" />
+
+                        <RadioButton
+                            android:id="@+id/rbSensitivity4"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="4" />
+
+                        <RadioButton
+                            android:id="@+id/rbSensitivity5"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="5" />
+                    </RadioGroup>
+
+                    <Button
+                        android:id="@+id/btnSetVibrationSensitivity"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+
+                <!-- 报警开关 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:layout_marginBottom="8dp"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="报警是否上报:" />
+
+                    <Switch
+                        android:id="@+id/switchAlarmReport"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1" />
+                </LinearLayout>
+
+                <!-- 倾倒报警阈值 -->
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:gravity="center_vertical">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:text="倾倒报警阈值:" />
+
+                    <RadioGroup
+                        android:id="@+id/rgTiltAlarmThreshold"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="2"
+                        android:orientation="horizontal">
+
+                        <RadioButton
+                            android:id="@+id/rbTilt50"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="50°" />
+
+                        <RadioButton
+                            android:id="@+id/rbTilt60"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="60°" />
+
+                        <RadioButton
+                            android:id="@+id/rbTilt70"
+                            android:layout_width="0dp"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:text="70°" />
+                    </RadioGroup>
+
+                    <Button
+                        android:id="@+id/btnSetTiltAlarmThreshold"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="设置" />
+                </LinearLayout>
+            </LinearLayout>
+        </androidx.cardview.widget.CardView>
+
+    </LinearLayout>
+</androidx.core.widget.NestedScrollView>
+

+ 28 - 0
app/src/main/res/menu/bottom_navigation_menu.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/vehicleFragment"
+        android:icon="@android:drawable/ic_menu_recent_history"
+        android:title="车辆" />
+    
+    <item
+        android:id="@+id/communityFragment"
+        android:icon="@android:drawable/ic_menu_myplaces"
+        android:title="社区" />
+    
+    <item
+        android:id="@+id/serviceFragment"
+        android:icon="@android:drawable/ic_menu_help"
+        android:title="服务" />
+    
+    <item
+        android:id="@+id/shopFragment"
+        android:icon="@android:drawable/ic_menu_agenda"
+        android:title="商城" />
+    
+    <item
+        android:id="@+id/userFragment"
+        android:icon="@android:drawable/ic_menu_myplaces"
+        android:title="我的" />
+</menu>
+

+ 6 - 0
app/src/main/res/mipmap-anydpi/ic_launcher.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/white"/>
+    <foreground android:drawable="@color/black"/>
+</adaptive-icon>
+

+ 6 - 0
app/src/main/res/mipmap-anydpi/ic_launcher_round.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/white"/>
+    <foreground android:drawable="@color/black"/>
+</adaptive-icon>
+

+ 43 - 0
app/src/main/res/navigation/main_nav_graph.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/main_nav_graph"
+    app:startDestination="@id/vehicleFragment">
+    
+    <!-- 车辆Fragment -->
+    <fragment
+        android:id="@+id/vehicleFragment"
+        android:name="com.narutohuo.xindazhou.vehicle.ui.VehicleFragment"
+        android:label="车辆"
+        tools:layout="@android:layout/simple_list_item_1" />
+    
+    <!-- 社区Fragment -->
+    <fragment
+        android:id="@+id/communityFragment"
+        android:name="com.narutohuo.xindazhou.community.ui.CommunityFragment"
+        android:label="社区"
+        tools:layout="@android:layout/simple_list_item_1" />
+    
+    <!-- 服务Fragment -->
+    <fragment
+        android:id="@+id/serviceFragment"
+        android:name="com.narutohuo.xindazhou.service.ui.ServiceFragment"
+        android:label="服务"
+        tools:layout="@android:layout/simple_list_item_1" />
+    
+    <!-- 商城Fragment -->
+    <fragment
+        android:id="@+id/shopFragment"
+        android:name="com.narutohuo.xindazhou.shop.ui.ShopFragment"
+        android:label="商城"
+        tools:layout="@android:layout/simple_list_item_1" />
+    
+    <!-- 我的Fragment -->
+    <fragment
+        android:id="@+id/userFragment"
+        android:name="com.narutohuo.xindazhou.user.ui.profile.UserFragment"
+        android:label="我的"
+        tools:layout="@android:layout/simple_list_item_1" />
+</navigation>
+

+ 43 - 0
app/src/main/res/navigation/nav_graph.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/nav_graph"
+    app:startDestination="@id/loginFragment">
+
+    <!-- 登录Fragment -->
+    <fragment
+        android:id="@+id/loginFragment"
+        android:name="com.narutohuo.xindazhou.user.ui.login.LoginFragment"
+        android:label="登录">
+        <action
+            android:id="@+id/action_loginFragment_to_registerFragment"
+            app:destination="@id/registerFragment" />
+        <action
+            android:id="@+id/action_loginFragment_to_mainFragment"
+            app:destination="@id/mainFragment"
+            app:popUpTo="@id/loginFragment"
+            app:popUpToInclusive="true" />
+    </fragment>
+
+    <!-- 注册Fragment -->
+    <fragment
+        android:id="@+id/registerFragment"
+        android:name="com.narutohuo.xindazhou.user.ui.register.RegisterFragment"
+        android:label="注册">
+        <action
+            android:id="@+id/action_registerFragment_to_mainFragment"
+            app:destination="@id/mainFragment"
+            app:popUpTo="@id/loginFragment"
+            app:popUpToInclusive="true" />
+    </fragment>
+
+    <!-- 主界面Fragment -->
+    <fragment
+        android:id="@+id/mainFragment"
+        android:name="com.narutohuo.xindazhou.common.main.ui.MainFragment"
+        android:label="主界面"
+        tools:layout="@layout/fragment_main" />
+
+</navigation>
+

+ 6 - 0
app/src/main/res/values/colors.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="black">#FF000000</color>
+    <color name="white">#FFFFFFFF</color>
+</resources>
+

+ 30 - 0
app/src/main/res/values/strings.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">新大洲本田</string>
+    
+    <!-- 极光推送配置 -->
+    <string name="jpush_app_key">your_jpush_appkey_here</string>
+    <string name="push_jpush_app_key">your_jpush_appkey_here</string>
+    <string name="push_jpush_channel">developer-default</string>
+    
+    <!-- 友盟分享配置 -->
+    <string name="share_umeng_app_key">your_umeng_appkey_here</string>
+    <string name="share_umeng_channel">developer-default</string>
+    
+    <!-- 微信分享配置(可选) -->
+    <string name="share_wechat_app_id">your_wechat_appid_here</string>
+    <string name="share_wechat_app_secret">your_wechat_appsecret_here</string>
+    
+    <!-- QQ 分享配置(可选) -->
+    <string name="share_qq_app_id">your_qq_appid_here</string>
+    <string name="share_qq_app_key">your_qq_appkey_here</string>
+    <!-- QQ scheme(格式:tencent + AppID,用于 AndroidManifest.xml) -->
+    <string name="qq_app_id">your_qq_appid_here</string>
+    <string name="qq_app_id_scheme">tencentyour_qq_appid_here</string>
+    
+    <!-- 微博分享配置(可选) -->
+    <string name="share_weibo_app_key">your_weibo_appkey_here</string>
+    <string name="share_weibo_app_secret">your_weibo_appsecret_here</string>
+    <string name="share_weibo_redirect_url">https://api.weibo.com/oauth2/default.html</string>
+</resources>
+

+ 13 - 0
app/src/main/res/values/themes.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="Theme.XinDaZhou" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <item name="colorPrimary">@android:color/black</item>
+        <item name="colorPrimaryVariant">@android:color/black</item>
+        <item name="colorOnPrimary">@android:color/white</item>
+        <item name="colorSecondary">@android:color/black</item>
+        <item name="colorSecondaryVariant">@android:color/black</item>
+        <item name="colorOnSecondary">@android:color/white</item>
+        <item name="android:statusBarColor">@android:color/black</item>
+    </style>
+</resources>
+

+ 12 - 0
app/src/main/res/xml/file_paths.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- 应用内部存储的 downloads 目录 -->
+    <external-files-path
+        name="downloads"
+        path="downloads/" />
+    <!-- 外部存储的下载目录 -->
+    <external-path
+        name="external_downloads"
+        path="Download/" />
+</paths>
+

+ 16 - 0
app/src/main/res/xml/network_security_config.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+    <!-- 允许对本地开发服务器的明文HTTP通信 -->
+    <domain-config cleartextTrafficPermitted="true">
+        <!-- 允许本地IP地址 -->
+        <domain includeSubdomains="true">192.168.1.107</domain>
+        <domain includeSubdomains="true">localhost</domain>
+        <domain includeSubdomains="true">127.0.0.1</domain>
+        <domain includeSubdomains="true">10.0.2.2</domain>
+        <!-- 允许所有192.168.x.x网段的本地IP(开发环境) -->
+        <domain includeSubdomains="true">192.168.0.0</domain>
+        <domain includeSubdomains="true">192.168.1.0</domain>
+        <domain includeSubdomains="true">192.168.2.0</domain>
+    </domain-config>
+</network-security-config>
+

+ 53 - 0
base-common/build.gradle

@@ -0,0 +1,53 @@
+plugins {
+    alias(libs.plugins.kotlin.android)
+    id("com.android.library")
+}
+
+android {
+    namespace = "com.narutohuo.xindazhou.common"
+    compileSdk = 36
+
+    defaultConfig {
+        minSdk = 26
+    }
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_17
+        targetCompatibility = JavaVersion.VERSION_17
+    }
+    kotlinOptions {
+        jvmTarget = "17"
+    }
+    
+    buildFeatures {
+        viewBinding = true
+    }
+}
+
+dependencies {
+    // 依赖base-core
+    implementation(project(":base-core"))
+    
+    // AndroidX Core
+    implementation(libs.androidx.core.ktx)
+    
+    // Fragment KTX (提供 DialogFragment 支持)
+    implementation("androidx.fragment:fragment-ktx:1.6.2")
+    
+    // Material Design (用于对话框UI)
+    implementation("com.google.android.material:material:1.11.0")
+    
+    // Gson for JSON parsing
+    implementation("com.google.code.gson:gson:2.10.1")
+    
+    // Retrofit for HTTP requests
+    implementation("com.squareup.retrofit2:retrofit:2.9.0")
+    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
+    
+    // OkHttp for HTTP client
+    implementation("com.squareup.okhttp3:okhttp:4.12.0")
+    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
+    
+    // 日志通过 base-core 的 ILog 接口统一管理,无需单独依赖 Timber
+}
+

+ 3 - 0
base-common/src/main/AndroidManifest.xml

@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
+

+ 78 - 0
base-common/src/main/java/com/narutohuo/xindazhou/common/config/ServerConfigManager.kt

@@ -0,0 +1,78 @@
+package com.narutohuo.xindazhou.common.config
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.narutohuo.xindazhou.core.log.ILog
+
+/**
+ * 服务器配置管理器
+ * 用于管理开发测试时的服务器地址配置
+ * 
+ * 统一配置服务器IP,然后根据不同服务类型连接不同端口:
+ * - HTTP API服务:18080(用户服务)、18082(消息服务)
+ * - SocketIO服务:9090
+ */
+object ServerConfigManager {
+    
+    private const val PREFS_NAME = "server_config"
+    private const val KEY_SERVER_IP = "server_ip"
+    private const val DEFAULT_SERVER_IP = "192.168.1.107"
+    
+    // 服务端口配置
+    private const val PORT_HTTP_USER = 18080
+    private const val PORT_HTTP_MESSAGE = 18082
+    private const val PORT_SOCKETIO = 9090
+    
+    private var prefs: SharedPreferences? = null
+    
+    /**
+     * 初始化(在Application中调用)
+     */
+    fun init(context: Context) {
+        prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
+        ILog.d("ServerConfigManager", "初始化完成,当前IP: ${getServerIp()}")
+    }
+    
+    /**
+     * 获取服务器IP地址
+     */
+    fun getServerIp(): String {
+        return prefs?.getString(KEY_SERVER_IP, DEFAULT_SERVER_IP) ?: DEFAULT_SERVER_IP
+    }
+    
+    /**
+     * 设置服务器IP地址
+     */
+    fun setServerIp(ip: String) {
+        prefs?.edit()?.putString(KEY_SERVER_IP, ip)?.apply()
+        ILog.d("ServerConfigManager", "服务器IP已更新为: $ip")
+    }
+    
+    /**
+     * 获取HTTP API服务器地址(用户服务)
+     */
+    fun getHttpServerUrl(): String {
+        val ip = getServerIp()
+        val url = "http://$ip:$PORT_HTTP_USER/app-api/"
+        ILog.d("ServerConfigManager", "HTTP服务器地址: $url")
+        return url
+    }
+    
+    /**
+     * 获取SocketIO服务器地址
+     */
+    fun getSocketIOUrl(): String {
+        val ip = getServerIp()
+        val url = "http://$ip:$PORT_SOCKETIO"
+        ILog.d("ServerConfigManager", "SocketIO服务器地址: $url")
+        return url
+    }
+    
+    /**
+     * 重置为默认IP
+     */
+    fun resetToDefault() {
+        setServerIp(DEFAULT_SERVER_IP)
+    }
+}
+

+ 74 - 0
base-common/src/main/java/com/narutohuo/xindazhou/common/dialog/ServerConfigDialog.kt

@@ -0,0 +1,74 @@
+package com.narutohuo.xindazhou.common.dialog
+
+import android.app.Dialog
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.textfield.TextInputEditText
+import com.narutohuo.xindazhou.common.R
+import com.narutohuo.xindazhou.common.config.ServerConfigManager
+
+/**
+ * 服务器配置对话框
+ * 用于开发测试时配置服务器地址
+ */
+class ServerConfigDialog : DialogFragment() {
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.dialog_server_config, container, false)
+    }
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+        val dialog = super.onCreateDialog(savedInstanceState)
+        dialog.setTitle("服务器配置")
+        return dialog
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        val etServerUrl = view.findViewById<TextInputEditText>(R.id.etServerUrl)
+        val btnSave = view.findViewById<MaterialButton>(R.id.btnSave)
+        val btnReset = view.findViewById<MaterialButton>(R.id.btnReset)
+        val btnCancel = view.findViewById<MaterialButton>(R.id.btnCancel)
+
+        // 显示当前服务器IP
+        val currentIp = ServerConfigManager.getServerIp()
+        etServerUrl?.setText(currentIp)
+        etServerUrl?.hint = "请输入服务器IP地址(如:192.168.1.107)"
+
+        // 保存按钮
+        btnSave?.setOnClickListener {
+            val ip = etServerUrl?.text?.toString()?.trim()
+            if (ip.isNullOrEmpty()) {
+                Toast.makeText(requireContext(), "服务器IP不能为空", Toast.LENGTH_SHORT).show()
+                return@setOnClickListener
+            }
+
+            ServerConfigManager.setServerIp(ip)
+            Toast.makeText(requireContext(), "服务器IP已更新,请重启应用生效", Toast.LENGTH_LONG).show()
+            dismiss()
+        }
+
+        // 重置按钮
+        btnReset?.setOnClickListener {
+            ServerConfigManager.resetToDefault()
+            etServerUrl?.setText(ServerConfigManager.getServerIp())
+            Toast.makeText(requireContext(), "已重置为默认IP", Toast.LENGTH_SHORT).show()
+        }
+
+        // 取消按钮
+        btnCancel?.setOnClickListener {
+            dismiss()
+        }
+    }
+}
+

+ 114 - 0
base-common/src/main/java/com/narutohuo/xindazhou/common/network/ApiResponseParser.kt

@@ -0,0 +1,114 @@
+package com.narutohuo.xindazhou.common.network
+
+import android.util.Log
+import retrofit2.Response
+
+/**
+ * 通用响应结果
+ * 对应后端 CommonResult<T>
+ * 
+ * 所有API响应的统一包装格式
+ */
+data class CommonResult<T>(
+    val code: Int,
+    val msg: String?,
+    val data: T?
+)
+
+/**
+ * API响应解析器
+ * 
+ * 统一处理 Retrofit Response,将 Response<CommonResult<T>> 转换为 Result<T>
+ */
+object ApiResponseParser {
+    
+    /**
+     * 业务成功码
+     */
+    private const val SUCCESS_CODE = 0
+    
+    /**
+     * 处理网络响应
+     * 
+     * @param response Retrofit Response
+     * @param tag 日志标签(用于日志记录)
+     * @param errorMessage 错误消息前缀
+     * @return Result<T> 成功返回数据,失败返回异常
+     */
+    fun <T> handleResponse(
+        response: Response<CommonResult<T>>,
+        tag: String = "ApiResponseParser",
+        errorMessage: String = "请求失败"
+    ): Result<T> {
+        return try {
+            // 1. 检查HTTP状态码
+            if (!response.isSuccessful) {
+                val errorMsg = response.message() ?: errorMessage
+                Log.w(tag, "HTTP请求失败,code=${response.code()}")
+                return Result.failure(Exception(errorMsg))
+            }
+            
+            // 2. 获取响应体
+            val commonResult = response.body() 
+                ?: return Result.failure(Exception("响应体为空"))
+            
+            // 3. 检查业务状态码
+            if (commonResult.code != SUCCESS_CODE) {
+                val errorMsg = commonResult.msg ?: "$errorMessage (code: ${commonResult.code})"
+                Log.w(tag, "业务失败,code=${commonResult.code}")
+                return Result.failure(Exception(errorMsg))
+            }
+            
+            // 4. 提取业务数据
+            val data = commonResult.data 
+                ?: return Result.failure(Exception("服务器返回数据为空"))
+            
+            Log.d(tag, "请求成功")
+            Result.success(data)
+            
+        } catch (e: Exception) {
+            Log.e(tag, "处理响应异常", e)
+            Result.failure(e)
+        }
+    }
+    
+    /**
+     * 处理网络响应(支持可空数据)
+     * 
+     * @param response Retrofit Response
+     * @param tag 日志标签
+     * @param errorMessage 错误消息前缀
+     * @return Result<T?> 成功返回数据(可能为null),失败返回异常
+     */
+    fun <T> handleNullableResponse(
+        response: Response<CommonResult<T>>,
+        tag: String = "ApiResponseParser",
+        errorMessage: String = "请求失败"
+    ): Result<T?> {
+        return try {
+            if (!response.isSuccessful) {
+                val errorMsg = response.message() ?: errorMessage
+                Log.w(tag, "HTTP请求失败,code=${response.code()}")
+                return Result.failure(Exception(errorMsg))
+            }
+            
+            val commonResult = response.body() 
+                ?: return Result.failure(Exception("响应体为空"))
+            
+            if (commonResult.code != SUCCESS_CODE) {
+                val errorMsg = commonResult.msg ?: "$errorMessage (code: ${commonResult.code})"
+                Log.w(tag, "业务失败,code=${commonResult.code}")
+                return Result.failure(Exception(errorMsg))
+            }
+            
+            // 允许data为null
+            Log.d(tag, "请求成功")
+            Result.success(commonResult.data)
+            
+        } catch (e: Exception) {
+            Log.e(tag, "处理响应异常", e)
+            Result.failure(e)
+        }
+    }
+}
+

+ 145 - 0
base-common/src/main/java/com/narutohuo/xindazhou/common/network/HttpApiClient.kt

@@ -0,0 +1,145 @@
+package com.narutohuo.xindazhou.common.network
+
+import android.util.Log
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import com.narutohuo.xindazhou.common.config.ServerConfigManager
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import java.util.concurrent.TimeUnit
+
+/**
+ * HTTP API 客户端管理类
+ * 
+ * 负责创建和管理 Retrofit 实例,统一配置
+ * 功能:
+ * - 统一配置 OkHttp Client(超时、拦截器)
+ * - 日志拦截器(Debug模式)
+ * - Token拦截器(可选,通过配置添加)
+ */
+object HttpApiClient {
+    
+    private var retrofit: Retrofit? = null
+    private var okHttpClient: OkHttpClient? = null
+    
+    /**
+     * Token获取器接口(可选,用于自动添加Token到请求头)
+     */
+    var tokenProvider: (() -> String?)? = null
+    
+    private val gson: Gson by lazy {
+        GsonBuilder()
+            .setLenient()
+            .create()
+    }
+    
+    /**
+     * 创建 OkHttp Client
+     */
+    private fun createOkHttpClient(): OkHttpClient {
+        return OkHttpClient.Builder()
+            .connectTimeout(30, TimeUnit.SECONDS)
+            .readTimeout(30, TimeUnit.SECONDS)
+            .writeTimeout(30, TimeUnit.SECONDS)
+            .addInterceptor(createLoggingInterceptor())
+            .addInterceptor(createTokenInterceptor())
+            .build()
+    }
+    
+    /**
+     * 创建日志拦截器
+     */
+    private fun createLoggingInterceptor(): HttpLoggingInterceptor {
+        val loggingInterceptor = HttpLoggingInterceptor { message ->
+            // 使用Android Log输出(base-common不依赖Timber)
+            Log.d("Retrofit", message)
+        }
+        loggingInterceptor.level = if (isDebug()) {
+            HttpLoggingInterceptor.Level.BODY
+        } else {
+            HttpLoggingInterceptor.Level.NONE
+        }
+        return loggingInterceptor
+    }
+    
+    /**
+     * 创建Token拦截器(自动添加Token到请求头)
+     */
+    private fun createTokenInterceptor(): okhttp3.Interceptor {
+        return okhttp3.Interceptor { chain ->
+            val originalRequest = chain.request()
+            
+            // 如果配置了Token提供器,自动添加Token
+            val token = tokenProvider?.invoke()
+            val requestBuilder = originalRequest.newBuilder()
+            
+            if (!token.isNullOrEmpty()) {
+                requestBuilder.header("Authorization", "Bearer $token")
+            }
+            
+            // 添加通用请求头
+            requestBuilder.header("Content-Type", "application/json")
+            requestBuilder.header("Accept", "application/json")
+            
+            chain.proceed(requestBuilder.build())
+        }
+    }
+    
+    /**
+     * 判断是否为Debug模式
+     */
+    private fun isDebug(): Boolean {
+        return try {
+            // 尝试从app模块获取BuildConfig
+            val buildConfigClass = Class.forName("com.narutohuo.xindazhou.BuildConfig")
+            val debugField = buildConfigClass.getField("DEBUG")
+            debugField.getBoolean(null)
+        } catch (e: Exception) {
+            // 如果无法获取,默认返回false(Release模式)
+            false
+        }
+    }
+    
+    /**
+     * 获取 OkHttp Client
+     */
+    fun getOkHttpClient(): OkHttpClient {
+        return okHttpClient ?: createOkHttpClient().also { okHttpClient = it }
+    }
+    
+    /**
+     * 获取 Retrofit 实例
+     * 
+     * @param baseUrl 基础URL,如果为null则使用ServerConfigManager的配置
+     * @return Retrofit 实例
+     */
+    fun getRetrofit(baseUrl: String? = null): Retrofit {
+        return retrofit ?: Retrofit.Builder()
+            .baseUrl(baseUrl ?: ServerConfigManager.getHttpServerUrl())
+            .client(getOkHttpClient())
+            .addConverterFactory(GsonConverterFactory.create(gson))
+            .build()
+            .also { retrofit = it }
+    }
+    
+    /**
+     * 创建 API 接口实例
+     * 
+     * @param baseUrl 基础URL,如果为null则使用ServerConfigManager的配置
+     * @return API 接口实例
+     */
+    inline fun <reified T> createApi(baseUrl: String? = null): T {
+        return getRetrofit(baseUrl).create(T::class.java)
+    }
+    
+    /**
+     * 重置 Retrofit 实例(用于切换服务器地址时)
+     */
+    fun reset() {
+        retrofit = null
+        okHttpClient = null
+    }
+}
+

+ 61 - 0
base-common/src/main/res/layout/dialog_server_config.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:padding="24dp">
+
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/tilServerUrl"
+        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="服务器地址">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/etServerUrl"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="textUri"
+            android:maxLines="1" />
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="示例: http://192.168.1.100:18080/app-api/"
+        android:textSize="12sp"
+        android:textColor="@android:color/darker_gray"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="16dp" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="end">
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btnCancel"
+            style="@style/Widget.MaterialComponents.Button.TextButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="取消" />
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btnReset"
+            style="@style/Widget.MaterialComponents.Button.TextButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="重置" />
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btnSave"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="保存" />
+    </LinearLayout>
+
+</LinearLayout>
+

+ 31 - 0
base-core/build.gradle

@@ -0,0 +1,31 @@
+plugins {
+    alias(libs.plugins.kotlin.android)
+    id("com.android.library")
+}
+
+android {
+    namespace = "com.narutohuo.xindazhou.core"
+    compileSdk = 36
+
+    defaultConfig {
+        minSdk = 26
+    }
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_17
+        targetCompatibility = JavaVersion.VERSION_17
+    }
+    kotlinOptions {
+        jvmTarget = "17"
+    }
+}
+
+dependencies {
+    // AndroidX Core
+    implementation(libs.androidx.core.ktx)
+    
+    // Timber for logging (默认日志实现)
+    // 如果以后不用 Timber,只需修改 TimberLog 实现类
+    implementation("com.jakewharton.timber:timber:5.0.1")
+}
+

+ 3 - 0
base-core/src/main/AndroidManifest.xml

@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
+

+ 23 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/bridge/IBridge.kt

@@ -0,0 +1,23 @@
+package com.narutohuo.xindazhou.core.bridge
+
+/**
+ * 桥接服务接口
+ * 原生与H5通信、模块间通信、事件总线管理
+ * 
+ * 所有SDK模块通过此接口进行模块间通信
+ * 实现类由app模块提供
+ */
+interface IBridge {
+    /**
+     * H5通信
+     */
+    fun callH5Method(method: String, params: String)
+    fun onH5Call(method: String, callback: (String) -> Unit)
+    
+    /**
+     * 模块间通信
+     */
+    fun postEvent(event: String, data: Any?)
+    fun subscribeEvent(event: String, callback: (Any?) -> Unit)
+}
+

+ 30 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/config/IConfig.kt

@@ -0,0 +1,30 @@
+package com.narutohuo.xindazhou.core.config
+
+/**
+ * 配置服务接口
+ * 应用配置管理、环境切换、功能开关、版本管理
+ * 
+ * 所有SDK模块通过此接口获取配置,实现类由app模块提供
+ */
+interface IConfig {
+    fun getString(key: String, defaultValue: String = ""): String
+    fun getInt(key: String, defaultValue: Int = 0): Int
+    fun getBoolean(key: String, defaultValue: Boolean = false): Boolean
+    
+    fun setString(key: String, value: String)
+    fun setInt(key: String, value: Int)
+    fun setBoolean(key: String, value: Boolean)
+    
+    /**
+     * 环境切换
+     */
+    fun getEnvironment(): String // dev, test, prod
+    fun setEnvironment(env: String)
+    
+    /**
+     * 功能开关
+     */
+    fun isFeatureEnabled(feature: String): Boolean
+    fun setFeatureEnabled(feature: String, enabled: Boolean)
+}
+

+ 31 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/executor/IExecutor.kt

@@ -0,0 +1,31 @@
+package com.narutohuo.xindazhou.core.executor
+
+/**
+ * 执行器接口
+ * 线程池管理、异步任务执行、定时任务
+ * 
+ * 所有SDK模块通过此接口执行异步任务
+ * 实现类由app模块提供
+ */
+interface IExecutor {
+    /**
+     * 在IO线程执行
+     */
+    fun executeIO(block: suspend () -> Unit)
+    
+    /**
+     * 在主线程执行
+     */
+    fun executeMain(block: () -> Unit)
+    
+    /**
+     * 延迟执行
+     */
+    fun executeDelayed(delayMillis: Long, block: () -> Unit)
+    
+    /**
+     * 取消任务
+     */
+    fun cancel(taskId: String)
+}
+

+ 204 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/log/ILog.kt

@@ -0,0 +1,204 @@
+package com.narutohuo.xindazhou.core.log
+
+/**
+ * 日志级别枚举
+ */
+enum class LogLevel {
+    DEBUG,    // 调试信息
+    INFO,     // 一般信息
+    WARN,     // 警告信息
+    ERROR     // 错误信息
+}
+
+/**
+ * 日志服务接口
+ * 统一封装日志记录、日志文件管理、日志上传、崩溃收集
+ * 
+ * 实现类:TimberLog(开发环境)、NoOpLog(生产环境)
+ */
+interface ILogger {
+    /**
+     * 调试日志
+     */
+    fun d(tag: String, message: String)
+    
+    /**
+     * 信息日志
+     */
+    fun i(tag: String, message: String)
+    
+    /**
+     * 警告日志
+     */
+    fun w(tag: String, message: String)
+    
+    /**
+     * 错误日志
+     */
+    fun e(tag: String, message: String, throwable: Throwable? = null)
+    
+    /**
+     * 按级别记录日志
+     * 
+     * @param level 日志级别
+     * @param tag 标签
+     * @param message 消息
+     * @param throwable 异常(可选)
+     */
+    fun log(level: LogLevel, tag: String, message: String, throwable: Throwable? = null)
+    
+    /**
+     * 上传日志文件
+     */
+    fun uploadLogs()
+    
+    /**
+     * 收集崩溃信息
+     */
+    fun collectCrash(throwable: Throwable)
+}
+
+/**
+ * 日志工具类(类似 Android Log 类)
+ * 
+ * 所有SDK模块通过静态方法进行日志记录
+ * 
+ * **实现选择**:
+ * - **开发环境**(Debug):使用 TimberLog(输出详细日志)
+ * - **生产环境**(Release):使用 NoOpLog(不输出日志,提升性能)
+ * 
+ * **使用示例**:
+ * ```kotlin
+ * // 1. 在 Application 中初始化(推荐)
+ * // Debug 版本自动启用日志,Release 版本自动禁用
+ * ILog.init(enableLogging = BuildConfig.DEBUG)
+ * 
+ * // 2. 静态方法调用(推荐,类似 Android Log.d())
+ * ILog.d("Tag", "调试信息")
+ * ILog.e("Tag", "错误信息", exception)
+ * 
+ * // 3. 手动控制(可选)
+ * ILog.init(enableLogging = false) // 生产环境禁用日志
+ * ILog.init(enableLogging = true)   // 开发环境启用日志
+ * ```
+ */
+object ILog {
+    @Volatile
+    private var instance: ILogger? = null
+    
+    /**
+     * 初始化日志实现(在 Application 中调用,可选)
+     * 
+     * **自动选择实现**:
+     * - 如果 `enableLogging = true`(默认):使用 TimberLog(开发环境)
+     * - 如果 `enableLogging = false`:使用 NoOpLog(生产环境,不输出日志)
+     * 
+     * **使用示例**:
+     * ```kotlin
+     * // 方式1:自动选择(推荐)
+     * // Debug 版本自动启用日志,Release 版本自动禁用
+     * ILog.init(enableLogging = BuildConfig.DEBUG)
+     * 
+     * // 方式2:手动指定实现
+     * ILog.init(com.narutohuo.xindazhou.core.log.impl.NoOpLog.getInstance()) // 生产环境
+     * ILog.init(com.narutohuo.xindazhou.core.log.impl.TimberLog.getInstance()) // 开发环境
+     * ```
+     * 
+     * @param enableLogging 是否启用日志(默认 true)
+     * @param logImpl 自定义日志实现(可选,如果指定则忽略 enableLogging 参数)
+     */
+    @JvmStatic
+    fun init(enableLogging: Boolean = true, logImpl: ILogger? = null) {
+        instance = when {
+            logImpl != null -> logImpl // 如果指定了自定义实现,优先使用
+            enableLogging -> com.narutohuo.xindazhou.core.log.impl.TimberLog.getInstance() // 启用日志
+            else -> com.narutohuo.xindazhou.core.log.impl.NoOpLog.getInstance() // 禁用日志(生产环境)
+        }
+    }
+    
+    /**
+     * 初始化日志实现(使用自定义实现)
+     * 
+     * @param logImpl 自定义日志实现
+     */
+    @JvmStatic
+    fun init(logImpl: ILogger) {
+        instance = logImpl
+    }
+    
+    /**
+     * 获取日志实现实例(单例)
+     * 
+     * 如果未初始化,默认使用 TimberLog(开发环境)
+     * 生产环境建议在 Application 中调用 init() 进行初始化
+     */
+    private fun getInstance(): ILogger {
+        if (instance == null) {
+            synchronized(this) {
+                if (instance == null) {
+                    // 默认使用 TimberLog(开发环境)
+                    // 生产环境建议在 Application 中调用 init(enableLogging = false)
+                    instance = com.narutohuo.xindazhou.core.log.impl.TimberLog.getInstance()
+                }
+            }
+        }
+        return instance!!
+    }
+    
+    /**
+     * 调试日志(静态方法)
+     */
+    @JvmStatic
+    fun d(tag: String, message: String) {
+        getInstance().d(tag, message)
+    }
+    
+    /**
+     * 信息日志(静态方法)
+     */
+    @JvmStatic
+    fun i(tag: String, message: String) {
+        getInstance().i(tag, message)
+    }
+    
+    /**
+     * 警告日志(静态方法)
+     */
+    @JvmStatic
+    fun w(tag: String, message: String) {
+        getInstance().w(tag, message)
+    }
+    
+    /**
+     * 错误日志(静态方法)
+     */
+    @JvmStatic
+    fun e(tag: String, message: String, throwable: Throwable? = null) {
+        getInstance().e(tag, message, throwable)
+    }
+    
+    /**
+     * 按级别记录日志(静态方法)
+     */
+    @JvmStatic
+    fun log(level: LogLevel, tag: String, message: String, throwable: Throwable? = null) {
+        getInstance().log(level, tag, message, throwable)
+    }
+    
+    /**
+     * 上传日志文件(静态方法)
+     */
+    @JvmStatic
+    fun uploadLogs() {
+        getInstance().uploadLogs()
+    }
+    
+    /**
+     * 收集崩溃信息(静态方法)
+     */
+    @JvmStatic
+    fun collectCrash(throwable: Throwable) {
+        getInstance().collectCrash(throwable)
+    }
+}
+

+ 66 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/log/impl/NoOpLog.kt

@@ -0,0 +1,66 @@
+package com.narutohuo.xindazhou.core.log.impl
+
+import com.narutohuo.xindazhou.core.log.ILogger
+import com.narutohuo.xindazhou.core.log.LogLevel
+
+/**
+ * 空日志实现(用于生产环境)
+ * 
+ * 所有日志方法都是空操作,不会输出任何日志
+ * 用于生产环境,避免日志输出影响性能
+ * 
+ * 使用方式:
+ * ```kotlin
+ * // 在 Application 中初始化(生产环境)
+ * ILog.init(NoOpLog.getInstance())
+ * ```
+ */
+class NoOpLog private constructor() : ILogger {
+    
+    companion object {
+        @Volatile
+        private var INSTANCE: NoOpLog? = null
+        
+        /**
+         * 获取单例实例
+         */
+        @JvmStatic
+        fun getInstance(): ILogger {
+            return INSTANCE ?: synchronized(this) {
+                INSTANCE ?: NoOpLog().also { INSTANCE = it }
+            }
+        }
+    }
+    
+    override fun d(tag: String, message: String) {
+        // 空操作,不输出日志
+    }
+    
+    override fun i(tag: String, message: String) {
+        // 空操作,不输出日志
+    }
+    
+    override fun w(tag: String, message: String) {
+        // 空操作,不输出日志
+    }
+    
+    override fun e(tag: String, message: String, throwable: Throwable?) {
+        // 空操作,不输出日志
+        // 注意:生产环境可能仍然需要收集错误,可以在这里扩展
+    }
+    
+    override fun log(level: LogLevel, tag: String, message: String, throwable: Throwable?) {
+        // 空操作,不输出日志
+    }
+    
+    override fun uploadLogs() {
+        // 空操作
+    }
+    
+    override fun collectCrash(throwable: Throwable) {
+        // 空操作
+        // 注意:生产环境可能仍然需要收集崩溃信息,可以在这里扩展
+        // 例如:上传到崩溃收集服务(Firebase Crashlytics、Bugly 等)
+    }
+}
+

+ 75 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/log/impl/TimberLog.kt

@@ -0,0 +1,75 @@
+package com.narutohuo.xindazhou.core.log.impl
+
+import com.narutohuo.xindazhou.core.log.ILogger
+import com.narutohuo.xindazhou.core.log.LogLevel
+import timber.log.Timber
+
+/**
+ * Timber 日志实现(默认实现,单例)
+ * 
+ * 封装 Timber 日志库,实现 ILog 接口
+ * 以后如果不用 Timber,只需修改此实现类,或提供新的实现类
+ * 
+ * 使用方式:
+ * ```kotlin
+ * val log: ILog = TimberLog.getInstance()
+ * ```
+ */
+class TimberLog private constructor() : ILogger {
+    
+    companion object {
+        @Volatile
+        private var INSTANCE: TimberLog? = null
+        
+        /**
+         * 获取单例实例
+         */
+        @JvmStatic
+        fun getInstance(): ILogger {
+            return INSTANCE ?: synchronized(this) {
+                INSTANCE ?: TimberLog().also { INSTANCE = it }
+            }
+        }
+    }
+    
+    override fun d(tag: String, message: String) {
+        Timber.tag(tag).d(message)
+    }
+    
+    override fun i(tag: String, message: String) {
+        Timber.tag(tag).i(message)
+    }
+    
+    override fun w(tag: String, message: String) {
+        Timber.tag(tag).w(message)
+    }
+    
+    override fun e(tag: String, message: String, throwable: Throwable?) {
+        if (throwable != null) {
+            Timber.tag(tag).e(throwable, message)
+        } else {
+            Timber.tag(tag).e(message)
+        }
+    }
+    
+    override fun log(level: LogLevel, tag: String, message: String, throwable: Throwable?) {
+        when (level) {
+            LogLevel.DEBUG -> d(tag, message)
+            LogLevel.INFO -> i(tag, message)
+            LogLevel.WARN -> w(tag, message)
+            LogLevel.ERROR -> e(tag, message, throwable)
+        }
+    }
+    
+    override fun uploadLogs() {
+        // Timber 默认不提供日志上传功能,可以在这里扩展
+        // 或者由 app 模块提供自定义实现
+    }
+    
+    override fun collectCrash(throwable: Throwable) {
+        // Timber 默认不提供崩溃收集功能,可以在这里扩展
+        // 或者由 app 模块提供自定义实现
+        Timber.e(throwable, "崩溃信息")
+    }
+}
+

+ 29 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/storage/IStorage.kt

@@ -0,0 +1,29 @@
+package com.narutohuo.xindazhou.core.storage
+
+/**
+ * 存储服务接口
+ * 统一封装键值存储、文件存储、数据库存储
+ * 
+ * 所有SDK模块通过此接口进行数据存储,实现类由app模块提供
+ */
+interface IStorage {
+    /**
+     * 键值存储
+     */
+    fun putString(key: String, value: String)
+    fun getString(key: String, defaultValue: String = ""): String
+    fun putInt(key: String, value: Int)
+    fun getInt(key: String, defaultValue: Int = 0): Int
+    fun putBoolean(key: String, value: Boolean)
+    fun getBoolean(key: String, defaultValue: Boolean = false): Boolean
+    fun remove(key: String)
+    fun clear()
+    
+    /**
+     * 文件存储
+     */
+    fun saveFile(path: String, data: ByteArray): Boolean
+    fun readFile(path: String): ByteArray?
+    fun deleteFile(path: String): Boolean
+}
+

+ 30 - 0
base-core/src/main/java/com/narutohuo/xindazhou/core/util/IUtil.kt

@@ -0,0 +1,30 @@
+package com.narutohuo.xindazhou.core.util
+
+/**
+ * 工具类接口
+ * 通用工具方法、时间处理、字符串处理、加密解密
+ * 
+ * 所有SDK模块通过此接口使用工具类
+ * 实现类由app模块提供
+ */
+interface IUtil {
+    /**
+     * 时间处理
+     */
+    fun formatTime(timestamp: Long, pattern: String): String
+    fun parseTime(timeString: String, pattern: String): Long?
+    
+    /**
+     * 字符串处理
+     */
+    fun encryptString(data: String): String
+    fun decryptString(data: String): String
+    fun md5(data: String): String
+    
+    /**
+     * 数据转换
+     */
+    fun <T> toJson(obj: T): String
+    fun <T> fromJson(json: String, clazz: Class<T>): T?
+}
+

+ 6 - 0
build.gradle

@@ -0,0 +1,6 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+    alias(libs.plugins.android.application) apply false
+    alias(libs.plugins.kotlin.android) apply false
+    alias(libs.plugins.kotlin.compose) apply false
+}

+ 30 - 0
capability-ble/build.gradle

@@ -0,0 +1,30 @@
+plugins {
+    alias(libs.plugins.kotlin.android)
+    id("com.android.library")
+}
+
+android {
+    namespace = "com.narutohuo.xindazhou.ble"
+    compileSdk = 36
+
+    defaultConfig {
+        minSdk = 26
+    }
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_17
+        targetCompatibility = JavaVersion.VERSION_17
+    }
+    kotlinOptions {
+        jvmTarget = "17"
+    }
+}
+
+dependencies {
+    // 依赖base-core(所有SDK都依赖这个)
+    implementation(project(":base-core"))
+    
+    // AndroidX Core
+    implementation(libs.androidx.core.ktx)
+}
+

+ 12 - 0
capability-ble/src/main/AndroidManifest.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- 蓝牙权限 -->
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+    <!-- Android 12+ 需要位置权限用于扫描 -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+</manifest>
+

+ 149 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/api/BLEService.kt

@@ -0,0 +1,149 @@
+package com.narutohuo.xindazhou.ble.api
+
+import com.narutohuo.xindazhou.ble.callback.*
+import com.narutohuo.xindazhou.ble.model.BLEDevice
+import com.narutohuo.xindazhou.ble.model.BLECommand
+import com.narutohuo.xindazhou.ble.model.BLEResponse
+import com.narutohuo.xindazhou.ble.model.HandshakeCommand
+
+/**
+ * BLE服务接口
+ * 
+ * 提供蓝牙低功耗(BLE)通信能力
+ * 封装新大洲本田蓝牙协议,提供高级API供业务模块调用
+ */
+interface BLEService {
+    
+    // ========== 基础连接功能 ==========
+    
+    /**
+     * 开始扫描BLE设备
+     * 
+     * @param callback 扫描结果回调,返回BLEDevice
+     */
+    fun startScan(callback: (BLEDevice) -> Unit)
+    
+    /**
+     * 停止扫描
+     */
+    fun stopScan()
+    
+    /**
+     * 连接设备
+     * 
+     * @param device 要连接的设备
+     * @param callback 连接结果回调(统一使用lambda)
+     */
+    fun connect(device: BLEDevice, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 连接设备(兼容旧接口)
+     * 
+     * @param device 要连接的设备
+     * @param callback 连接结果回调
+     */
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("connect(device) { response -> ... }"))
+    fun connect(device: BLEDevice, callback: ConnectCallback)
+    
+    /**
+     * 断开连接
+     */
+    fun disconnect()
+    
+    /**
+     * 是否已连接
+     */
+    fun isConnected(): Boolean
+    
+    // ========== 协议封装功能(高级API,业务模块直接调用) ==========
+    
+    /**
+     * 握手认证
+     * 
+     * @param userId 用户ID(16字节)
+     * @param userType 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户)
+     * @param callback 握手结果回调(统一使用lambda)
+     */
+    fun handshake(userId: ByteArray, userType: Byte, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 握手认证(兼容旧接口)
+     * 
+     * @param userId 用户ID(16字节)
+     * @param userType 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户)
+     * @param callback 握手结果回调
+     */
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("handshake(userId, userType) { response -> ... }"))
+    fun handshake(userId: ByteArray, userType: Byte, callback: HandshakeCallback)
+    
+    /**
+     * 发送指令
+     * 
+     * @param command BLE指令(包含功能码、指令类型、应用数据)
+     * @param callback 指令响应回调(统一使用lambda)
+     */
+    fun sendCommand(command: BLECommand, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 发送指令(兼容旧接口)
+     * 
+     * @param command BLE指令(包含功能码、指令类型、应用数据)
+     * @param callback 指令响应回调
+     */
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("sendCommand(command) { response -> ... }"))
+    fun sendCommand(command: BLECommand, callback: CommandCallback)
+    
+    /**
+     * 发送应用控制指令(业务模块常用)
+     * 
+     * @param instructionType 指令类型(如:设撤防、上下电、寻车等)
+     * @param data 指令参数数据
+     * @param callback 响应回调(统一使用lambda)
+     */
+    fun sendAppControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 发送系统控制指令(业务模块常用)
+     * 
+     * @param instructionType 指令类型(如:感应解锁、氛围灯等)
+     * @param data 指令参数数据
+     * @param callback 响应回调(统一使用lambda)
+     */
+    fun sendSystemControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 查询车辆信息
+     * 
+     * @param callback 响应回调(统一使用lambda),返回车辆信息数据
+     */
+    fun queryVehicleInfo(callback: (BLEResponse) -> Unit)
+    
+    // ========== 数据接收监听 ==========
+    
+    /**
+     * 设置数据接收监听器
+     * 
+     * @param listener 接收到的数据回调
+     */
+    fun setDataReceivedListener(listener: DataCallback)
+    
+    // ========== 底层功能(如果需要直接操作) ==========
+    
+    /**
+     * 发送原始数据(底层API,不推荐业务模块直接使用)
+     * 
+     * @param data 原始数据(二进制)
+     * @param callback 响应回调(统一使用lambda)
+     */
+    fun writeRawData(data: ByteArray, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 发送原始数据(兼容旧接口)
+     * 
+     * @param data 原始数据(二进制)
+     * @param callback 响应回调
+     */
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("writeRawData(data) { response -> ... }"))
+    fun writeRawData(data: ByteArray, callback: CommandCallback)
+}
+

+ 69 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/callback/BLECallback.kt

@@ -0,0 +1,69 @@
+package com.narutohuo.xindazhou.ble.callback
+
+import com.narutohuo.xindazhou.ble.model.BLEResponse
+
+/**
+ * BLE连接回调
+ */
+interface ConnectCallback {
+    /**
+     * 连接成功
+     */
+    fun onConnected()
+    
+    /**
+     * 连接失败
+     */
+    fun onFailed(error: String)
+    
+    /**
+     * 连接断开
+     */
+    fun onDisconnected()
+}
+
+/**
+ * 握手指令回调
+ */
+interface HandshakeCallback {
+    /**
+     * 握手成功
+     */
+    fun onSuccess()
+    
+    /**
+     * 握手失败
+     */
+    fun onFailed(error: String)
+}
+
+/**
+ * 指令发送回调
+ */
+interface CommandCallback {
+    /**
+     * 指令响应
+     */
+    fun onResponse(response: BLEResponse)
+    
+    /**
+     * 指令超时
+     */
+    fun onTimeout()
+    
+    /**
+     * 指令失败
+     */
+    fun onError(error: String)
+}
+
+/**
+ * 数据接收回调
+ */
+interface DataCallback {
+    /**
+     * 接收到数据
+     */
+    fun onDataReceived(data: ByteArray)
+}
+

+ 181 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/config/BLEConstants.kt

@@ -0,0 +1,181 @@
+package com.narutohuo.xindazhou.ble.config
+
+import java.util.UUID
+
+/**
+ * BLE常量定义
+ * 
+ * 根据新大洲本田蓝牙协议文档定义
+ */
+object BLEConstants {
+    
+    // ========== 蓝牙服务UUID ==========
+    
+    /**
+     * 蓝牙指令服务UUID
+     */
+    val SERVICE_UUID = UUID.fromString("0000adb0-0000-1000-8000-00805f9b34fb")
+    
+    /**
+     * Notify特征值UUID(接收数据)
+     */
+    val NOTIFY_CHARACTERISTIC_UUID = UUID.fromString("0000adb1-0000-1000-8000-00805f9b34fb")
+    
+    /**
+     * Write特征值UUID(发送数据)
+     */
+    val WRITE_CHARACTERISTIC_UUID = UUID.fromString("0000adb2-0000-1000-8000-00805f9b34fb")
+    
+    /**
+     * OTA服务UUID
+     */
+    val OTA_SERVICE_UUID = UUID.fromString("0000adb3-0000-1000-8000-00805f9b34fb")
+    
+    /**
+     * OTA Notify特征值UUID
+     */
+    val OTA_NOTIFY_CHARACTERISTIC_UUID = UUID.fromString("0000adb4-0000-1000-8000-00805f9b34fb")
+    
+    /**
+     * OTA Write特征值UUID
+     */
+    val OTA_WRITE_CHARACTERISTIC_UUID = UUID.fromString("0000adb5-0000-1000-8000-00805f9b34fb")
+    
+    // ========== 数据包结构常量 ==========
+    
+    /**
+     * 包头(固定值)
+     */
+    const val PACKET_HEAD = 0x0A.toByte()
+    
+    /**
+     * 包尾(固定值)
+     */
+    const val PACKET_TAIL = 0x0D.toByte()
+    
+    /**
+     * APP地址
+     */
+    const val ADDRESS_APP = 0x0F.toByte()
+    
+    /**
+     * 中控地址
+     */
+    const val ADDRESS_CONTROLLER = 0x05.toByte()
+    
+    /**
+     * 仪表地址
+     */
+    const val ADDRESS_DASHBOARD = 0x0A.toByte()
+    
+    /**
+     * 协议版本(v1.0)
+     */
+    const val PROTOCOL_VERSION = 0x01.toByte()
+    
+    /**
+     * Android操作系统标识
+     */
+    const val OS_ANDROID = 0x01.toByte()
+    
+    /**
+     * iOS操作系统标识
+     */
+    const val OS_IOS = 0x02.toByte()
+    
+    /**
+     * 加密标志:不加密
+     */
+    const val ENCRYPT_FLAG_NONE = 0x00.toByte()
+    
+    /**
+     * 加密标志:加密
+     */
+    const val ENCRYPT_FLAG_ENCRYPTED = 0x01.toByte()
+    
+    // ========== 功能码 ==========
+    
+    /**
+     * 功能码:握手
+     */
+    const val FUNCTION_CODE_HANDSHAKE = 0x01.toByte()
+    
+    /**
+     * 功能码:应用控制
+     */
+    const val FUNCTION_CODE_APP_CONTROL = 0x02.toByte()
+    
+    /**
+     * 功能码:系统控制
+     */
+    const val FUNCTION_CODE_SYSTEM_CONTROL = 0x03.toByte()
+    
+    /**
+     * 功能码:系统查询
+     */
+    const val FUNCTION_CODE_SYSTEM_QUERY = 0x04.toByte()
+    
+    /**
+     * 功能码:系统设置
+     */
+    const val FUNCTION_CODE_SYSTEM_SETTING = 0x05.toByte()
+    
+    /**
+     * 功能码:MTU查询
+     */
+    const val FUNCTION_CODE_MTU_QUERY = 0x06.toByte()
+    
+    // ========== 用户类型 ==========
+    
+    /**
+     * 用户类型:最高权限
+     */
+    const val USER_TYPE_HIGHEST = 0x01.toByte()
+    
+    /**
+     * 用户类型:车主
+     */
+    const val USER_TYPE_OWNER = 0x02.toByte()
+    
+    /**
+     * 用户类型:分享用户
+     */
+    const val USER_TYPE_SHARED = 0x03.toByte()
+    
+    // ========== 加密相关 ==========
+    
+    /**
+     * AES密钥前缀
+     */
+    const val AES_KEY_PREFIX = "2025SDH+"
+    
+    /**
+     * AES密钥长度(16字节)
+     */
+    const val AES_KEY_LENGTH = 16
+    
+    /**
+     * AES加密算法
+     */
+    const val AES_ALGORITHM = "AES/ECB/PKCS7Padding"
+    
+    // ========== 超时时间 ==========
+    
+    /**
+     * 默认超时时间(毫秒)
+     */
+    const val DEFAULT_TIMEOUT_MS = 2000L
+    
+    /**
+     * 握手超时时间(毫秒)
+     */
+    const val HANDSHAKE_TIMEOUT_MS = 3000L
+    
+    // ========== 连接策略 ==========
+    
+    /**
+     * 连接成功后握手超时时间(秒)
+     */
+    const val HANDSHAKE_TIMEOUT_SECONDS = 3
+}
+

+ 42 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/factory/BLEServiceFactory.kt

@@ -0,0 +1,42 @@
+package com.narutohuo.xindazhou.ble.factory
+
+import android.content.Context
+import com.narutohuo.xindazhou.ble.api.BLEService
+import com.narutohuo.xindazhou.ble.impl.BLEServiceImpl
+
+/**
+ * BLE服务工厂类
+ * 
+ * 提供统一的获取BLE服务实例的方式
+ * 支持单例模式和依赖注入
+ */
+object BLEServiceFactory {
+    
+    /**
+     * 创建或获取BLE服务实例(单例)
+     * 
+     * @param context 上下文
+     * @return BLEService实例(单例)
+     */
+    fun create(context: Context): BLEService {
+        return BLEServiceImpl.getInstance(context)
+    }
+    
+    /**
+     * 检查BLE服务是否已初始化
+     * 
+     * @return 如果已初始化返回true,否则返回false
+     */
+    fun isInitialized(): Boolean {
+        // 通过反射或内部方法检查INSTANCE是否已初始化
+        // 注意:这是一个简化的实现,实际使用时建议通过依赖注入管理
+        return try {
+            val field = BLEServiceImpl::class.java.getDeclaredField("INSTANCE")
+            field.isAccessible = true
+            field.get(null) != null
+        } catch (e: Exception) {
+            false
+        }
+    }
+}
+

+ 915 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/impl/BLEServiceImpl.kt

@@ -0,0 +1,915 @@
+package com.narutohuo.xindazhou.ble.impl
+
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGatt
+import android.bluetooth.BluetoothGattCallback
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor
+import android.bluetooth.BluetoothManager
+import android.bluetooth.BluetoothProfile
+import android.bluetooth.le.BluetoothLeScanner
+import android.bluetooth.le.ScanCallback
+import android.bluetooth.le.ScanFilter
+import android.bluetooth.le.ScanResult
+import android.bluetooth.le.ScanSettings
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import com.narutohuo.xindazhou.ble.api.BLEService
+import com.narutohuo.xindazhou.ble.callback.*
+import com.narutohuo.xindazhou.ble.config.BLEConstants
+import com.narutohuo.xindazhou.ble.model.BLEDevice
+import com.narutohuo.xindazhou.ble.model.BLECommand
+import com.narutohuo.xindazhou.ble.model.BLEResponse
+import com.narutohuo.xindazhou.ble.model.BLEEncryptedData
+import com.narutohuo.xindazhou.ble.util.BLECrypto
+import com.narutohuo.xindazhou.ble.util.BLEPacketBuilder
+import com.narutohuo.xindazhou.ble.util.BLEPacketParser
+import com.narutohuo.xindazhou.ble.util.BLEPacketSplitter
+import java.util.UUID
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * BLE服务实现类(单例模式)
+ * 
+ * 封装新大洲本田蓝牙协议,提供高级API供业务模块调用
+ * 
+ * 使用单例模式的原因:
+ * 1. BLE连接是全局唯一的(一个设备同时只能有一个连接)
+ * 2. 多个界面(Activity/Fragment)需要共享同一个连接状态
+ * 3. 避免重复连接、资源浪费
+ * 
+ * 使用方式:
+ * ```kotlin
+ * // 在任何界面中获取单例
+ * val bleService = BLEServiceImpl.getInstance(context)
+ * 
+ * // 或者通过依赖注入(推荐)
+ * ```
+ */
+class BLEServiceImpl private constructor(
+    private val context: Context
+) : BLEService {
+    
+    companion object {
+        @Volatile
+        private var INSTANCE: BLEServiceImpl? = null
+        
+        /**
+         * 获取BLE服务单例
+         * 
+         * @param context 上下文(ApplicationContext或ActivityContext),第一次调用时必需,后续可选
+         * @return BLEService单例实例
+         */
+        @JvmStatic
+        fun getInstance(context: Context? = null): BLEServiceImpl {
+            return INSTANCE ?: synchronized(this) {
+                INSTANCE ?: run {
+                    if (context == null) {
+                        throw IllegalStateException("Context is required for first initialization. Call getInstance(context) first.")
+                    }
+                    BLEServiceImpl(context.applicationContext).also { INSTANCE = it }
+                }
+            }
+        }
+        
+        /**
+         * 销毁单例(用于测试或需要重新初始化时)
+         */
+        @JvmStatic
+        fun destroyInstance() {
+            INSTANCE?.disconnect()
+            INSTANCE = null
+        }
+    }
+    
+    private val tag = "BLEService"
+    private var bluetoothAdapter: BluetoothAdapter? = null
+    private var bluetoothLeScanner: BluetoothLeScanner? = null
+    private var currentDevice: BLEDevice? = null
+    private var bluetoothGatt: BluetoothGatt? = null
+    private var encryptKey: ByteArray? = null
+    private var dataReceivedListener: DataCallback? = null
+    
+    // 连接状态
+    private var connectionState = ConnectionState.DISCONNECTED
+    
+    // 扫描相关
+    private var scanCallback: ScanCallback? = null
+    private var scanResultCallback: ((BLEDevice) -> Unit)? = null
+    
+    // 数据发送相关
+    private val pendingCommands = ConcurrentHashMap<Int, PendingCommand>()
+    private val commandQueue = mutableListOf<Int>() // 命令队列(FIFO),用于匹配响应
+    private val commandToBusinessId = ConcurrentHashMap<Int, Int>() // 命令hash -> businessId
+    private val businessIdGenerator = AtomicInteger(0x2605d501) // 业务ID生成器
+    private val commandIdCounter = AtomicInteger(0) // 命令ID计数器
+    private val handler = Handler(Looper.getMainLooper())
+    
+    // 分包相关
+    private val splitPackets = ConcurrentHashMap<Int, MutableMap<Int, ByteArray>>() // businessId -> (packetIndex -> data)
+    
+    // 特征值
+    private var writeCharacteristic: BluetoothGattCharacteristic? = null
+    private var notifyCharacteristic: BluetoothGattCharacteristic? = null
+    
+    private val packetBuilder = BLEPacketBuilder()
+    private val packetParser = BLEPacketParser()
+    private val packetSplitter = BLEPacketSplitter()
+    
+    /**
+     * 连接状态枚举
+     */
+    enum class ConnectionState {
+        DISCONNECTED,
+        CONNECTING,
+        CONNECTED,
+        DISCONNECTING
+    }
+    
+    /**
+     * 待发送命令
+     */
+    private data class PendingCommand(
+        val command: BLECommand,
+        val callback: (BLEResponse) -> Unit,
+        val timeoutRunnable: Runnable
+    )
+    
+    init {
+        val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager
+        bluetoothAdapter = bluetoothManager?.adapter
+        bluetoothLeScanner = bluetoothAdapter?.bluetoothLeScanner
+    }
+    
+    // ========== 基础连接功能 ==========
+    
+    override fun startScan(callback: (BLEDevice) -> Unit) {
+        Log.d(tag, "startScan: 开始扫描BLE设备")
+        
+        if (bluetoothAdapter == null || !bluetoothAdapter!!.isEnabled) {
+            Log.e(tag, "startScan: 蓝牙未启用")
+            return
+        }
+        
+        if (bluetoothLeScanner == null) {
+            Log.e(tag, "startScan: 无法获取BluetoothLeScanner")
+            return
+        }
+        
+        scanResultCallback = callback
+        
+        scanCallback = object : ScanCallback() {
+            override fun onScanResult(callbackType: Int, result: ScanResult) {
+                val device = result.device
+                val deviceName = device.name
+                
+                // 过滤设备名称(SDH-Smart-***)
+                if (deviceName != null && deviceName.startsWith("SDH-Smart-", ignoreCase = true)) {
+                    Log.d(tag, "startScan: 发现设备 ${deviceName}, address=${device.address}, rssi=${result.rssi}")
+                    
+                    val bleDevice = BLEDevice(
+                        name = deviceName,
+                        address = device.address,
+                        rssi = result.rssi,
+                        services = emptyList()
+                    )
+                    
+                    scanResultCallback?.invoke(bleDevice)
+                }
+            }
+            
+            override fun onBatchScanResults(results: MutableList<ScanResult>) {
+                results.forEach { result ->
+                    onScanResult(0, result) // 使用0作为callbackType
+                }
+            }
+            
+            override fun onScanFailed(errorCode: Int) {
+                Log.e(tag, "startScan: 扫描失败, errorCode=$errorCode")
+                scanResultCallback = null
+            }
+        }
+        
+        // 配置扫描设置
+        val scanSettings = ScanSettings.Builder()
+            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+            .build()
+        
+        // 开始扫描
+        try {
+            bluetoothLeScanner!!.startScan(null, scanSettings, scanCallback)
+            Log.d(tag, "startScan: 扫描已启动")
+        } catch (e: SecurityException) {
+            Log.e(tag, "startScan: 权限不足", e)
+        } catch (e: Exception) {
+            Log.e(tag, "startScan: 扫描启动失败", e)
+        }
+    }
+    
+    override fun stopScan() {
+        Log.d(tag, "stopScan: 停止扫描")
+        
+        scanCallback?.let { callback ->
+            try {
+                bluetoothLeScanner?.stopScan(callback)
+                Log.d(tag, "stopScan: 扫描已停止")
+            } catch (e: SecurityException) {
+                Log.e(tag, "stopScan: 权限不足", e)
+            } catch (e: Exception) {
+                Log.e(tag, "stopScan: 停止扫描失败", e)
+            }
+        }
+        
+        scanCallback = null
+        scanResultCallback = null
+    }
+    
+    override fun connect(device: BLEDevice, callback: (BLEResponse) -> Unit) {
+        Log.d(tag, "connect: 连接设备 ${device.address}")
+        
+        if (connectionState == ConnectionState.CONNECTING || connectionState == ConnectionState.CONNECTED) {
+            Log.w(tag, "connect: 已有连接在进行中或已连接")
+            callback(BLEResponse(success = false, errorMessage = "已有连接在进行中或已连接"))
+            return
+        }
+        
+        currentDevice = device
+        connectionState = ConnectionState.CONNECTING
+        
+        // 生成加密密钥
+        val macBytes = parseMacAddress(device.address)
+        encryptKey = BLECrypto.generateAESKey(macBytes)
+        
+        // 获取BluetoothDevice对象
+        val bluetoothDevice = try {
+            bluetoothAdapter?.getRemoteDevice(device.address)
+        } catch (e: IllegalArgumentException) {
+            Log.e(tag, "connect: 无效的MAC地址 ${device.address}", e)
+            connectionState = ConnectionState.DISCONNECTED
+            callback(BLEResponse(success = false, errorMessage = "无效的MAC地址"))
+            return
+        }
+        
+        if (bluetoothDevice == null) {
+            Log.e(tag, "connect: 无法获取BluetoothDevice")
+            connectionState = ConnectionState.DISCONNECTED
+            callback(BLEResponse(success = false, errorMessage = "无法获取BluetoothDevice"))
+            return
+        }
+        
+        // 连接设备
+        try {
+            bluetoothGatt = bluetoothDevice.connectGatt(
+                context,
+                false, // autoConnect = false,使用直接连接
+                gattCallback
+            )
+            
+            // 设置连接超时(10秒)
+            handler.postDelayed({
+                if (connectionState == ConnectionState.CONNECTING) {
+                    Log.e(tag, "connect: 连接超时")
+                    disconnect()
+                    callback(BLEResponse(success = false, errorMessage = "连接超时"))
+                }
+            }, 10000)
+            
+        } catch (e: SecurityException) {
+            Log.e(tag, "connect: 权限不足", e)
+            connectionState = ConnectionState.DISCONNECTED
+            callback(BLEResponse(success = false, errorMessage = "权限不足: ${e.message}"))
+        } catch (e: Exception) {
+            Log.e(tag, "connect: 连接失败", e)
+            connectionState = ConnectionState.DISCONNECTED
+            callback(BLEResponse(success = false, errorMessage = "连接失败: ${e.message}"))
+        }
+        
+        // 注意:连接成功会在gattCallback中回调
+        // 这里需要保存callback,在连接成功后调用
+        connectionCallback = callback
+    }
+    
+    // 连接回调(临时保存,连接成功后调用)
+    private var connectionCallback: ((BLEResponse) -> Unit)? = null
+    
+    // Gatt回调
+    private val gattCallback = object : BluetoothGattCallback() {
+        override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
+            Log.d(tag, "onConnectionStateChange: status=$status, newState=$newState")
+            
+            when (newState) {
+                BluetoothProfile.STATE_CONNECTED -> {
+                    Log.d(tag, "onConnectionStateChange: 已连接")
+                    connectionState = ConnectionState.CONNECTED
+                    
+                    // 发现服务
+                    try {
+                        val discovered = gatt.discoverServices()
+                        if (!discovered) {
+                            Log.e(tag, "onConnectionStateChange: 服务发现失败")
+                            disconnect()
+                            connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "服务发现失败"))
+                            connectionCallback = null
+                        }
+                    } catch (e: SecurityException) {
+                        Log.e(tag, "onConnectionStateChange: 权限不足", e)
+                        disconnect()
+                        connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "权限不足: ${e.message}"))
+                        connectionCallback = null
+                    }
+                }
+                
+                BluetoothProfile.STATE_DISCONNECTED -> {
+                    Log.d(tag, "onConnectionStateChange: 已断开连接")
+                    connectionState = ConnectionState.DISCONNECTED
+                    bluetoothGatt = null
+                    writeCharacteristic = null
+                    notifyCharacteristic = null
+                }
+            }
+        }
+        
+        override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
+            Log.d(tag, "onServicesDiscovered: status=$status")
+            
+            if (status != BluetoothGatt.GATT_SUCCESS) {
+                Log.e(tag, "onServicesDiscovered: 服务发现失败, status=$status")
+                disconnect()
+                connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "服务发现失败: status=$status"))
+                connectionCallback = null
+                return
+            }
+            
+            // 查找服务和特征值
+            val service = gatt.getService(BLEConstants.SERVICE_UUID)
+            if (service == null) {
+                Log.e(tag, "onServicesDiscovered: 未找到服务 ${BLEConstants.SERVICE_UUID}")
+                disconnect()
+                connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "未找到服务"))
+                connectionCallback = null
+                return
+            }
+            
+            // 获取Write特征值
+            writeCharacteristic = service.getCharacteristic(BLEConstants.WRITE_CHARACTERISTIC_UUID)
+            if (writeCharacteristic == null) {
+                Log.e(tag, "onServicesDiscovered: 未找到Write特征值")
+                disconnect()
+                connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "未找到Write特征值"))
+                connectionCallback = null
+                return
+            }
+            
+            // 获取Notify特征值
+            notifyCharacteristic = service.getCharacteristic(BLEConstants.NOTIFY_CHARACTERISTIC_UUID)
+            if (notifyCharacteristic == null) {
+                Log.e(tag, "onServicesDiscovered: 未找到Notify特征值")
+                disconnect()
+                connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "未找到Notify特征值"))
+                connectionCallback = null
+                return
+            }
+            
+            // 启用Notify
+            try {
+                val enabled = gatt.setCharacteristicNotification(notifyCharacteristic, true)
+                if (!enabled) {
+                    Log.e(tag, "onServicesDiscovered: 启用Notify失败")
+                    disconnect()
+                    connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "启用Notify失败"))
+                    connectionCallback = null
+                    return
+                }
+                
+                // 写入Descriptor以启用通知
+                val descriptor = notifyCharacteristic!!.getDescriptor(
+                    UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
+                )
+                descriptor?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
+                gatt.writeDescriptor(descriptor)
+                
+                Log.d(tag, "onServicesDiscovered: 服务发现成功,Notify已启用")
+                
+                // 连接成功
+                connectionCallback?.invoke(BLEResponse(success = true))
+                connectionCallback = null
+                
+            } catch (e: SecurityException) {
+                Log.e(tag, "onServicesDiscovered: 权限不足", e)
+                disconnect()
+                connectionCallback?.invoke(BLEResponse(success = false, errorMessage = "权限不足: ${e.message}"))
+                connectionCallback = null
+            }
+        }
+        
+        override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
+            val data = characteristic.value
+            Log.d(tag, "onCharacteristicChanged: 接收到数据 ${data.size} bytes")
+            
+            // 处理数据接收
+            handleDataReceived(data)
+        }
+        
+        override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
+            Log.d(tag, "onCharacteristicWrite: status=$status")
+            
+            if (status != BluetoothGatt.GATT_SUCCESS) {
+                Log.e(tag, "onCharacteristicWrite: 写入失败, status=$status")
+            }
+        }
+    }
+    
+    // 兼容旧接口
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("connect(device) { response -> ... }"))
+    override fun connect(device: BLEDevice, callback: ConnectCallback) {
+        connect(device) { response ->
+            if (response.success) {
+                callback.onConnected()
+            } else {
+                callback.onFailed(response.errorMessage ?: "连接失败")
+            }
+        }
+    }
+    
+    override fun disconnect() {
+        Log.d(tag, "disconnect: 断开连接")
+        
+        connectionState = ConnectionState.DISCONNECTING
+        
+        // 取消所有待发送的命令
+        pendingCommands.values.forEach { pending ->
+            handler.removeCallbacks(pending.timeoutRunnable)
+        }
+        pendingCommands.clear()
+        synchronized(commandQueue) {
+            commandQueue.clear()
+        }
+        commandToBusinessId.clear()
+        splitPackets.clear()
+        
+        // 关闭Gatt连接
+        try {
+            bluetoothGatt?.disconnect()
+            bluetoothGatt?.close()
+        } catch (e: Exception) {
+            Log.e(tag, "disconnect: 断开连接失败", e)
+        }
+        
+        bluetoothGatt = null
+        currentDevice = null
+        encryptKey = null
+        writeCharacteristic = null
+        notifyCharacteristic = null
+        connectionState = ConnectionState.DISCONNECTED
+    }
+    
+    override fun isConnected(): Boolean {
+        return connectionState == ConnectionState.CONNECTED && bluetoothGatt != null
+    }
+    
+    // ========== 协议封装功能(高级API) ==========
+    
+    override fun handshake(userId: ByteArray, userType: Byte, callback: (BLEResponse) -> Unit) {
+        Log.d(tag, "handshake: userId=${userId.size}bytes, userType=$userType")
+        
+        if (encryptKey == null) {
+            callback(BLEResponse(success = false, errorMessage = "未连接设备或密钥未生成"))
+            return
+        }
+        
+        // 构建握手指令
+        val command = BLECommand(
+            functionCode = BLEConstants.FUNCTION_CODE_HANDSHAKE,
+            instructionType = userType,
+            applicationData = userId // 16字节USERID
+        )
+        
+        // 发送指令
+        sendCommand(command, callback)
+    }
+    
+    // 兼容旧接口
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("handshake(userId, userType) { response -> ... }"))
+    override fun handshake(userId: ByteArray, userType: Byte, callback: HandshakeCallback) {
+        handshake(userId, userType) { response ->
+            if (response.success) {
+                callback.onSuccess()
+            } else {
+                callback.onFailed(response.errorMessage ?: "握手失败")
+            }
+        }
+    }
+    
+    override fun sendCommand(command: BLECommand, callback: (BLEResponse) -> Unit) {
+        Log.d(tag, "sendCommand: functionCode=${command.functionCode}, instructionType=${command.instructionType}")
+        
+        if (!isConnected()) {
+            callback(BLEResponse(success = false, errorMessage = "未连接设备"))
+            return
+        }
+        
+        if (encryptKey == null) {
+            callback(BLEResponse(success = false, errorMessage = "未连接设备或密钥未生成"))
+            return
+        }
+        
+        if (writeCharacteristic == null) {
+            callback(BLEResponse(success = false, errorMessage = "Write特征值未初始化"))
+            return
+        }
+        
+        // 构建数据包
+        val packet = packetBuilder.buildPacket(command, encryptKey!!)
+        
+        // 获取MTU(默认23,Android BLE最小MTU)
+        // 注意:getMtu() 方法在某些Android版本可能不可用,使用默认值
+        val mtu = 23 // Android BLE默认MTU
+        
+        // 检查是否需要分包(MTU - 3字节ATT头)
+        val maxDataSize = mtu - 3
+        if (packet.size > maxDataSize) {
+            // 需要分包
+            Log.d(tag, "sendCommand: 数据包大小 ${packet.size} > MTU $maxDataSize,需要分包")
+            sendSplitPacket(packet, maxDataSize, callback)
+        } else {
+            // 直接发送
+            sendSinglePacket(packet, callback)
+        }
+    }
+    
+    /**
+     * 发送单个数据包
+     */
+    private fun sendSinglePacket(packet: ByteArray, callback: (BLEResponse) -> Unit) {
+        // 使用时间戳和计数器生成唯一ID
+        val commandId = (System.currentTimeMillis() xor (commandIdCounter.getAndIncrement().toLong())).toInt()
+        
+        // 创建超时任务
+        val timeoutRunnable = Runnable {
+            pendingCommands.remove(commandId)
+            commandQueue.remove(commandId)
+            callback(BLEResponse(success = false, errorMessage = "指令超时"))
+        }
+        
+        // 保存待发送命令
+        pendingCommands[commandId] = PendingCommand(
+            command = BLECommand(0, 0, byteArrayOf()), // 占位,实际不需要
+            callback = callback,
+            timeoutRunnable = timeoutRunnable
+        )
+        
+        // 加入队列
+        synchronized(commandQueue) {
+            commandQueue.add(commandId)
+        }
+        
+        // 设置超时(2秒)
+        handler.postDelayed(timeoutRunnable, BLEConstants.DEFAULT_TIMEOUT_MS)
+        
+        // 发送数据
+        try {
+            writeCharacteristic!!.value = packet
+            val success = bluetoothGatt!!.writeCharacteristic(writeCharacteristic)
+            
+            if (!success) {
+                handler.removeCallbacks(timeoutRunnable)
+                pendingCommands.remove(commandId)
+                synchronized(commandQueue) {
+                    commandQueue.remove(commandId)
+                }
+                callback(BLEResponse(success = false, errorMessage = "写入特征值失败"))
+            }
+        } catch (e: SecurityException) {
+            handler.removeCallbacks(timeoutRunnable)
+            pendingCommands.remove(commandId)
+            synchronized(commandQueue) {
+                commandQueue.remove(commandId)
+            }
+            callback(BLEResponse(success = false, errorMessage = "权限不足: ${e.message}"))
+        } catch (e: Exception) {
+            handler.removeCallbacks(timeoutRunnable)
+            pendingCommands.remove(commandId)
+            synchronized(commandQueue) {
+                commandQueue.remove(commandId)
+            }
+            callback(BLEResponse(success = false, errorMessage = "发送失败: ${e.message}"))
+        }
+    }
+    
+    /**
+     * 发送分包数据
+     */
+    private fun sendSplitPacket(packet: ByteArray, maxDataSize: Int, callback: (BLEResponse) -> Unit) {
+        val businessId = generateBusinessId()
+        val packetHash = packet.contentHashCode()
+        
+        // 保存命令和业务ID的映射
+        commandToBusinessId[packetHash] = businessId
+        
+        val splitPackets = packetSplitter.splitPacket(packet, maxDataSize, businessId)
+        
+        Log.d(tag, "sendSplitPacket: 分包数量=${splitPackets.size}, businessId=$businessId")
+        
+        // 创建超时任务
+        val timeoutRunnable = Runnable {
+            this.splitPackets.remove(businessId)
+            pendingCommands.remove(businessId)
+            commandToBusinessId.remove(packetHash)
+            callback(BLEResponse(success = false, errorMessage = "分包发送超时"))
+        }
+        
+        // 保存待发送命令
+        pendingCommands[businessId] = PendingCommand(
+            command = BLECommand(0, 0, byteArrayOf()),
+            callback = callback,
+            timeoutRunnable = timeoutRunnable
+        )
+        
+        // 初始化分包存储
+        this.splitPackets[businessId] = mutableMapOf()
+        
+        // 设置超时(分包需要更长时间)
+        handler.postDelayed(timeoutRunnable, BLEConstants.DEFAULT_TIMEOUT_MS * splitPackets.size)
+        
+        // 依次发送分包
+        sendSplitPacketRecursive(splitPackets, 0, businessId)
+    }
+    
+    /**
+     * 递归发送分包
+     */
+    private fun sendSplitPacketRecursive(packets: List<ByteArray>, index: Int, businessId: Int) {
+        if (index >= packets.size) {
+            // 所有分包已发送,等待响应
+            return
+        }
+        
+        val packet = packets[index]
+        
+        try {
+            writeCharacteristic!!.value = packet
+            val success = bluetoothGatt!!.writeCharacteristic(writeCharacteristic)
+            
+            if (success) {
+                // 发送下一个分包(延迟50ms,避免发送过快)
+                handler.postDelayed({
+                    sendSplitPacketRecursive(packets, index + 1, businessId)
+                }, 50)
+            } else {
+                // 发送失败
+                val pending = pendingCommands[businessId]
+                if (pending != null) {
+                    handler.removeCallbacks(pending.timeoutRunnable)
+                }
+                splitPackets.remove(businessId)
+                pendingCommands.remove(businessId)?.callback?.invoke(
+                    BLEResponse(success = false, errorMessage = "分包发送失败")
+                )
+            }
+        } catch (e: Exception) {
+            val pending = pendingCommands[businessId]
+            if (pending != null) {
+                handler.removeCallbacks(pending.timeoutRunnable)
+            }
+            splitPackets.remove(businessId)
+            pendingCommands.remove(businessId)?.callback?.invoke(
+                BLEResponse(success = false, errorMessage = "分包发送异常: ${e.message}")
+            )
+        }
+    }
+    
+    /**
+     * 处理接收到的数据
+     */
+    private fun handleDataReceived(data: ByteArray) {
+        // 判断是否是分包数据(检查包头和业务ID)
+        if (data.isNotEmpty() && data[0] == 0x0A.toByte() && data.size >= 5) {
+            // 可能是分包数据
+            val businessId = (data[1].toInt() and 0xFF) or
+                            ((data[2].toInt() and 0xFF) shl 8) or
+                            ((data[3].toInt() and 0xFF) shl 16) or
+                            ((data[4].toInt() and 0xFF) shl 24)
+            
+            // 检查是否是分包协议(业务ID最后一位表示业务类型:0x01=请求,0x02=响应)
+            if ((businessId and 0xFF) == 0x02) {
+                // 这是分包响应,需要组包
+                handleSplitPacketResponse(data, businessId)
+                return
+            }
+        }
+        
+        // 普通数据包,直接解析
+        if (encryptKey == null) {
+            Log.e(tag, "handleDataReceived: 加密密钥未初始化")
+            return
+        }
+        
+        val encryptedData = packetParser.parsePacket(data, encryptKey!!)
+        if (encryptedData == null) {
+            Log.e(tag, "handleDataReceived: 数据包解析失败")
+            return
+        }
+        
+        // 使用FIFO队列匹配响应(假设响应按顺序返回)
+        // 注意:这种方法在并发场景下可能不够精确,但对于大多数场景已经足够
+        var found = false
+        synchronized(commandQueue) {
+            if (commandQueue.isNotEmpty()) {
+                val commandId = commandQueue.removeAt(0)
+                val pending = pendingCommands.remove(commandId)
+                
+                if (pending != null) {
+                    handler.removeCallbacks(pending.timeoutRunnable)
+                    
+                    val response = BLEResponse(
+                        success = true,
+                        data = encryptedData.applicationData
+                    )
+                    pending.callback(response)
+                    found = true
+                }
+            }
+        }
+        
+        if (!found) {
+            // 没有对应的回调,可能是主动推送的数据
+            Log.d(tag, "handleDataReceived: 接收到主动推送数据")
+            dataReceivedListener?.onDataReceived(encryptedData.applicationData)
+        }
+    }
+    
+    /**
+     * 处理分包响应
+     */
+    private fun handleSplitPacketResponse(data: ByteArray, businessId: Int) {
+        // 解析分包数据
+        if (data.size < 11) {
+            Log.e(tag, "handleSplitPacketResponse: 分包数据长度不足")
+            return
+        }
+        
+        val totalPackets = (data[5].toInt() and 0xFF) or ((data[6].toInt() and 0xFF) shl 8)
+        val packetIndex = (data[7].toInt() and 0xFF) or ((data[8].toInt() and 0xFF) shl 8)
+        val dataLength = (data[9].toInt() and 0xFF) or ((data[10].toInt() and 0xFF) shl 8)
+        
+        // 提取数据(跳过包头、业务ID、总包数、包序号、数据长度,共11字节)
+        val packetData = data.sliceArray(11 until 11 + dataLength)
+        
+        // 保存分包数据
+        val packets = splitPackets.getOrPut(businessId) { mutableMapOf() }
+        packets[packetIndex] = packetData
+        
+        // 检查是否所有分包都已接收
+        if (packets.size == totalPackets) {
+            // 组包
+            val combinedData = packetSplitter.combinePackets(packets)
+            
+            // 解析完整数据包
+            if (encryptKey != null) {
+                val encryptedData = packetParser.parsePacket(combinedData, encryptKey!!)
+                if (encryptedData != null) {
+                    // 查找对应的回调
+                    val pending = pendingCommands.remove(businessId)
+                    if (pending != null) {
+                        handler.removeCallbacks(pending.timeoutRunnable)
+                        val response = BLEResponse(
+                            success = true,
+                            data = encryptedData.applicationData
+                        )
+                        pending.callback(response)
+                    }
+                }
+            }
+            
+            // 清理
+            splitPackets.remove(businessId)
+        }
+    }
+    
+    
+    /**
+     * 生成业务ID
+     */
+    private fun generateBusinessId(): Int {
+        // 业务ID格式:0x2605d501 + 最后一位表示业务类型(0x01=请求)
+        val id = businessIdGenerator.getAndIncrement()
+        // 确保最后一位是0x01(请求)
+        return if ((id and 0xFF) != 0x01) {
+            val newId = (id and 0xFFFFFF00.toInt()) or 0x01
+            businessIdGenerator.set(newId)
+            newId
+        } else {
+            id
+        }
+    }
+    
+    // 兼容旧接口
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("sendCommand(command) { response -> ... }"))
+    override fun sendCommand(command: BLECommand, callback: CommandCallback) {
+        sendCommand(command) { response ->
+            if (response.success) {
+                callback.onResponse(response)
+            } else {
+                if (response.errorMessage?.contains("超时") == true || response.errorMessage?.contains("timeout") == true) {
+                    callback.onTimeout()
+                } else {
+                    callback.onError(response.errorMessage ?: "指令失败")
+                }
+            }
+        }
+    }
+    
+    override fun sendAppControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit) {
+        val command = BLECommand(
+            functionCode = BLEConstants.FUNCTION_CODE_APP_CONTROL,
+            instructionType = instructionType,
+            applicationData = data
+        )
+        sendCommand(command, callback)
+    }
+    
+    override fun sendSystemControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit) {
+        val command = BLECommand(
+            functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_CONTROL,
+            instructionType = instructionType,
+            applicationData = data
+        )
+        sendCommand(command, callback)
+    }
+    
+    override fun queryVehicleInfo(callback: (BLEResponse) -> Unit) {
+        val command = BLECommand(
+            functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_QUERY,
+            instructionType = 0x01.toByte(), // 查询车辆信息
+            applicationData = byteArrayOf(0x01) // 有效查询
+        )
+        sendCommand(command, callback)
+    }
+    
+    override fun setDataReceivedListener(listener: DataCallback) {
+        this.dataReceivedListener = listener
+        Log.d(tag, "setDataReceivedListener: 设置数据接收监听器")
+    }
+    
+    override fun writeRawData(data: ByteArray, callback: (BLEResponse) -> Unit) {
+        Log.d(tag, "writeRawData: 发送原始数据 ${data.size} bytes")
+        
+        if (!isConnected()) {
+            callback(BLEResponse(success = false, errorMessage = "未连接设备"))
+            return
+        }
+        
+        if (writeCharacteristic == null) {
+            callback(BLEResponse(success = false, errorMessage = "Write特征值未初始化"))
+            return
+        }
+        
+        try {
+            writeCharacteristic!!.value = data
+            val success = bluetoothGatt!!.writeCharacteristic(writeCharacteristic)
+            
+            if (success) {
+                // 原始数据发送成功(不等待响应)
+                callback(BLEResponse(success = true))
+            } else {
+                callback(BLEResponse(success = false, errorMessage = "写入特征值失败"))
+            }
+        } catch (e: SecurityException) {
+            callback(BLEResponse(success = false, errorMessage = "权限不足: ${e.message}"))
+        } catch (e: Exception) {
+            callback(BLEResponse(success = false, errorMessage = "发送失败: ${e.message}"))
+        }
+    }
+    
+    // 兼容旧接口
+    @Deprecated("使用 lambda 回调方式", ReplaceWith("writeRawData(data) { response -> ... }"))
+    override fun writeRawData(data: ByteArray, callback: CommandCallback) {
+        writeRawData(data) { response ->
+            if (response.success) {
+                callback.onResponse(response)
+            } else {
+                if (response.errorMessage?.contains("超时") == true || response.errorMessage?.contains("timeout") == true) {
+                    callback.onTimeout()
+                } else {
+                    callback.onError(response.errorMessage ?: "发送失败")
+                }
+            }
+        }
+    }
+    
+    // ========== 工具方法 ==========
+    
+    /**
+     * 解析MAC地址为字节数组
+     */
+    private fun parseMacAddress(macAddress: String): ByteArray {
+        val parts = macAddress.split(":")
+        return ByteArray(6) { i ->
+            parts[i].toInt(16).toByte()
+        }
+    }
+}

+ 79 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLECommand.kt

@@ -0,0 +1,79 @@
+package com.narutohuo.xindazhou.ble.model
+
+/**
+ * BLE指令模型
+ * 
+ * 封装业务层需要发送的指令
+ */
+data class BLECommand(
+    /**
+     * 功能码
+     * 0x01=握手, 0x02=应用控制, 0x03=系统控制, 0x04=系统查询, 0x05=系统设置
+     */
+    val functionCode: Byte,
+    
+    /**
+     * 指令类型
+     */
+    val instructionType: Byte,
+    
+    /**
+     * 应用数据
+     */
+    val applicationData: ByteArray
+)
+
+/**
+ * 握手指令参数
+ */
+data class HandshakeCommand(
+    /**
+     * 用户ID(16字节)
+     */
+    val userId: ByteArray,
+    
+    /**
+     * 用户类型
+     * 0x01=最高权限, 0x02=车主, 0x03=分享用户
+     */
+    val userType: Byte
+)
+
+/**
+ * 应用控制指令类型
+ */
+object AppControlInstruction {
+    const val SET_DEFENSE = 0x01.toByte()      // 设撤防
+    const val POWER_ON_OFF = 0x02.toByte()     // 上下电
+    const val FIND_CAR = 0x03.toByte()         // 寻车
+    const val SEAT_LOCK = 0x04.toByte()        // 座桶锁
+    const val HANDLEBAR_LOCK = 0x05.toByte()  // 龙头锁
+    const val TRUNK_LOCK = 0x06.toByte()       // 尾箱锁
+}
+
+/**
+ * 系统控制指令类型
+ */
+object SystemControlInstruction {
+    const val SENSOR_UNLOCK = 0x01.toByte()           // 感应解锁开关
+    const val RSSI_COLLECTION = 0x02.toByte()         // RSSI信号强度采集
+    const val REMOVE_SHARE_USER = 0x03.toByte()       // 删除分享用户
+    const val STOLEN_LOCK = 0x04.toByte()             // 被盗锁定开关
+    const val SEAT_SENSOR = 0x05.toByte()             // 座椅感应开关
+    const val SOUND_EFFECT = 0x06.toByte()            // 车辆音效开关
+    const val AUTO_HEADLIGHT = 0x07.toByte()         // 自动大灯开关
+    const val AUTO_POWER_OFF_TIME = 0x08.toByte()     // 自动下电时间
+    const val AUTO_DEFENSE_TIME = 0x09.toByte()      // 自动设防时间
+    const val AMBIENT_LIGHT = 0x10.toByte()           // 氛围灯开关
+    const val AMBIENT_LIGHT_COLOR = 0x11.toByte()     // 氛围灯颜色
+    const val RESET_MILEAGE = 0x12.toByte()           // 小计里程清零
+    const val VOICE_BROADCAST = 0x13.toByte()         // 语音播报开关
+    const val WALK_ME_HOME = 0x14.toByte()            // 伴我回家
+    const val SPEAKER_VOLUME = 0x15.toByte()          // 蓝牙音箱
+    const val DELAYED_CHARGING = 0x16.toByte()        // 延时充电时间
+    const val LOW_BATTERY_ALARM = 0x1F.toByte()       // 低电量报警阈值
+    const val ENTER_P_TIME = 0x20.toByte()            // 进入P档时间
+    const val ABS = 0x21.toByte()                     // ABS
+    const val TCS = 0x22.toByte()                     // TCS
+}
+

+ 29 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEDevice.kt

@@ -0,0 +1,29 @@
+package com.narutohuo.xindazhou.ble.model
+
+import java.util.UUID
+
+/**
+ * BLE设备信息
+ */
+data class BLEDevice(
+    /**
+     * 设备名称
+     */
+    val name: String?,
+    
+    /**
+     * MAC地址
+     */
+    val address: String,
+    
+    /**
+     * 信号强度(RSSI)
+     */
+    val rssi: Int,
+    
+    /**
+     * 服务UUID列表
+     */
+    val services: List<UUID> = emptyList()
+)
+

+ 85 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEPacket.kt

@@ -0,0 +1,85 @@
+package com.narutohuo.xindazhou.ble.model
+
+/**
+ * BLE数据包模型
+ * 
+ * 根据新大洲本田蓝牙协议文档定义的数据包结构
+ */
+data class BLEPacket(
+    /**
+     * 包头(固定0x0A)
+     */
+    val head: Byte = 0x0A,
+    
+    /**
+     * 地址(APP=0x0F, 中控=0x05, 仪表=0x0A)
+     */
+    val address: Byte,
+    
+    /**
+     * 协议版本(v1.0 = 0x01)
+     */
+    val protocolVersion: Byte = 0x01,
+    
+    /**
+     * 时区(单位:小时)
+     */
+    val timezone: Byte,
+    
+    /**
+     * 加密标志(0x00不加密,0x01加密)
+     */
+    val encryptFlag: Byte = 0x01,
+    
+    /**
+     * 操作系统(Android=0x01, iOS=0x02)
+     */
+    val osType: Byte = 0x01,
+    
+    /**
+     * 数据长度(2字节)
+     */
+    val dataLength: Int,
+    
+    /**
+     * 数据加密区(时间戳 + 功能码 + 指令类型 + 应用数据)
+     */
+    val encryptedData: ByteArray,
+    
+    /**
+     * 校验(异或校验)
+     */
+    val checksum: Byte,
+    
+    /**
+     * 包尾(固定0x0D)
+     */
+    val tail: Byte = 0x0D
+)
+
+/**
+ * 数据加密区内容
+ */
+data class BLEEncryptedData(
+    /**
+     * 时间戳(4字节)
+     */
+    val timestamp: Long,
+    
+    /**
+     * 功能码(1字节)
+     * 0x01=握手, 0x02=应用控制, 0x03=系统控制, 0x04=系统查询, 0x05=系统设置
+     */
+    val functionCode: Byte,
+    
+    /**
+     * 指令类型(1字节)
+     */
+    val instructionType: Byte,
+    
+    /**
+     * 应用数据(可变长度)
+     */
+    val applicationData: ByteArray
+)
+

+ 61 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEResponse.kt

@@ -0,0 +1,61 @@
+package com.narutohuo.xindazhou.ble.model
+
+/**
+ * BLE响应模型(统一结构)
+ * 
+ * 遵循统一设计:success, data, errorCode, errorMessage, timestamp
+ */
+data class BLEResponse(
+    /**
+     * 是否成功
+     */
+    val success: Boolean,
+    
+    /**
+     * 响应数据(二进制格式)
+     */
+    val data: ByteArray? = null,
+    
+    /**
+     * 错误码(如果有错误)
+     */
+    val errorCode: Int? = null,
+    
+    /**
+     * 错误消息(如果有错误)
+     */
+    val errorMessage: String? = null,
+    
+    /**
+     * 时间戳
+     */
+    val timestamp: Long = System.currentTimeMillis()
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as BLEResponse
+
+        if (success != other.success) return false
+        if (data != null) {
+            if (other.data == null) return false
+            if (!data.contentEquals(other.data)) return false
+        } else if (other.data != null) return false
+        if (errorCode != other.errorCode) return false
+        if (errorMessage != other.errorMessage) return false
+        if (timestamp != other.timestamp) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = success.hashCode()
+        result = 31 * result + (data?.contentHashCode() ?: 0)
+        result = 31 * result + (errorCode ?: 0)
+        result = 31 * result + (errorMessage?.hashCode() ?: 0)
+        result = 31 * result + timestamp.hashCode()
+        return result
+    }
+}
+

+ 73 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLECrypto.kt

@@ -0,0 +1,73 @@
+package com.narutohuo.xindazhou.ble.util
+
+import com.narutohuo.xindazhou.ble.config.BLEConstants
+import javax.crypto.Cipher
+import javax.crypto.spec.SecretKeySpec
+
+/**
+ * BLE加密工具类
+ * 
+ * 实现AES-128 ECB PKCS7加密/解密
+ * 根据新大洲本田蓝牙协议文档
+ */
+object BLECrypto {
+    
+    /**
+     * 生成AES密钥
+     * 
+     * @param deviceMac 设备MAC地址(6字节)
+     * @return AES密钥(16字节)
+     */
+    fun generateAESKey(deviceMac: ByteArray): ByteArray {
+        val keyString = BLEConstants.AES_KEY_PREFIX + deviceMac.joinToString("") { 
+            "%02X".format(it) 
+        }
+        // 取前16字节作为密钥
+        val keyBytes = keyString.toByteArray(Charsets.UTF_8)
+        return if (keyBytes.size >= BLEConstants.AES_KEY_LENGTH) {
+            keyBytes.sliceArray(0 until BLEConstants.AES_KEY_LENGTH)
+        } else {
+            // 如果不足16字节,用0填充
+            ByteArray(BLEConstants.AES_KEY_LENGTH) { 
+                if (it < keyBytes.size) keyBytes[it] else 0x00
+            }
+        }
+    }
+    
+    /**
+     * 加密数据
+     * 
+     * @param data 原始数据
+     * @param key AES密钥(16字节)
+     * @return 加密后的数据
+     */
+    fun encrypt(data: ByteArray, key: ByteArray): ByteArray {
+        try {
+            val cipher = Cipher.getInstance(BLEConstants.AES_ALGORITHM)
+            val secretKey = SecretKeySpec(key, "AES")
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey)
+            return cipher.doFinal(data)
+        } catch (e: Exception) {
+            throw RuntimeException("BLE加密失败", e)
+        }
+    }
+    
+    /**
+     * 解密数据
+     * 
+     * @param data 加密的数据
+     * @param key AES密钥(16字节)
+     * @return 解密后的数据
+     */
+    fun decrypt(data: ByteArray, key: ByteArray): ByteArray {
+        try {
+            val cipher = Cipher.getInstance(BLEConstants.AES_ALGORITHM)
+            val secretKey = SecretKeySpec(key, "AES")
+            cipher.init(Cipher.DECRYPT_MODE, secretKey)
+            return cipher.doFinal(data)
+        } catch (e: Exception) {
+            throw RuntimeException("BLE解密失败", e)
+        }
+    }
+}
+

+ 116 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketBuilder.kt

@@ -0,0 +1,116 @@
+package com.narutohuo.xindazhou.ble.util
+
+import com.narutohuo.xindazhou.ble.config.BLEConstants
+import com.narutohuo.xindazhou.ble.model.BLECommand
+import com.narutohuo.xindazhou.ble.model.BLEEncryptedData
+import java.util.TimeZone
+
+/**
+ * BLE数据包构建器
+ * 
+ * 负责构建符合新大洲本田蓝牙协议的数据包
+ * 封装数据包结构、加密、校验等细节
+ */
+class BLEPacketBuilder {
+    
+    /**
+     * 构建数据包
+     * 
+     * @param command BLE指令
+     * @param encryptKey 加密密钥(16字节)
+     * @return 完整的数据包(ByteArray)
+     */
+    fun buildPacket(command: BLECommand, encryptKey: ByteArray): ByteArray {
+        // 1. 构建数据加密区
+        val timestamp = System.currentTimeMillis() / 1000 // 秒级时间戳
+        val encryptedData = BLEEncryptedData(
+            timestamp = timestamp,
+            functionCode = command.functionCode,
+            instructionType = command.instructionType,
+            applicationData = command.applicationData
+        )
+        
+        // 2. 序列化数据加密区
+        val encryptedDataBytes = serializeEncryptedData(encryptedData)
+        
+        // 3. 加密数据
+        val encryptedBytes = BLECrypto.encrypt(encryptedDataBytes, encryptKey)
+        
+        // 4. 构建完整数据包
+        val packet = mutableListOf<Byte>()
+        
+        // 包头
+        packet.add(BLEConstants.PACKET_HEAD)
+        
+        // 地址
+        packet.add(BLEConstants.ADDRESS_APP)
+        
+        // 协议版本
+        packet.add(BLEConstants.PROTOCOL_VERSION)
+        
+        // 时区
+        val timezone = (TimeZone.getDefault().rawOffset / (1000 * 60 * 60)).toByte()
+        packet.add(timezone)
+        
+        // 加密标志
+        packet.add(BLEConstants.ENCRYPT_FLAG_ENCRYPTED)
+        
+        // 操作系统
+        packet.add(BLEConstants.OS_ANDROID)
+        
+        // 数据长度(2字节,小端序)
+        val dataLength = encryptedBytes.size
+        packet.add((dataLength and 0xFF).toByte())
+        packet.add(((dataLength shr 8) and 0xFF).toByte())
+        
+        // 数据加密区
+        packet.addAll(encryptedBytes.toList())
+        
+        // 校验(异或校验,包头至校验前一位)
+        val checksum = calculateChecksum(packet)
+        packet.add(checksum)
+        
+        // 包尾
+        packet.add(BLEConstants.PACKET_TAIL)
+        
+        return packet.toByteArray()
+    }
+    
+    /**
+     * 序列化数据加密区
+     */
+    private fun serializeEncryptedData(data: BLEEncryptedData): ByteArray {
+        val result = mutableListOf<Byte>()
+        
+        // 时间戳(4字节,小端序)
+        val timestamp = data.timestamp.toInt()
+        result.add((timestamp and 0xFF).toByte())
+        result.add(((timestamp shr 8) and 0xFF).toByte())
+        result.add(((timestamp shr 16) and 0xFF).toByte())
+        result.add(((timestamp shr 24) and 0xFF).toByte())
+        
+        // 功能码
+        result.add(data.functionCode)
+        
+        // 指令类型
+        result.add(data.instructionType)
+        
+        // 应用数据
+        result.addAll(data.applicationData.toList())
+        
+        return result.toByteArray()
+    }
+    
+    /**
+     * 计算异或校验
+     */
+    private fun calculateChecksum(packet: List<Byte>): Byte {
+        var checksum = 0x00
+        // 从地址开始(跳过包头),到校验位前一位
+        for (i in 1 until packet.size) {
+            checksum = checksum xor packet[i].toInt()
+        }
+        return checksum.toByte()
+    }
+}
+

+ 94 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketParser.kt

@@ -0,0 +1,94 @@
+package com.narutohuo.xindazhou.ble.util
+
+import com.narutohuo.xindazhou.ble.config.BLEConstants
+import com.narutohuo.xindazhou.ble.model.BLEEncryptedData
+
+/**
+ * BLE数据包解析器
+ * 
+ * 负责解析从设备接收的数据包
+ * 处理解密、校验、数据提取等
+ */
+class BLEPacketParser {
+    
+    /**
+     * 解析数据包
+     * 
+     * @param packet 接收到的数据包
+     * @param encryptKey 解密密钥(16字节)
+     * @return 解析后的数据加密区内容
+     */
+    fun parsePacket(packet: ByteArray, encryptKey: ByteArray): BLEEncryptedData? {
+        // 1. 校验包头包尾
+        if (packet.isEmpty() || packet[0] != BLEConstants.PACKET_HEAD) {
+            return null
+        }
+        if (packet[packet.size - 1] != BLEConstants.PACKET_TAIL) {
+            return null
+        }
+        
+        // 2. 提取数据长度
+        val dataLength = (packet[6].toInt() and 0xFF) or 
+                        ((packet[7].toInt() and 0xFF) shl 8)
+        
+        // 3. 提取加密数据
+        val encryptedData = packet.sliceArray(8 until 8 + dataLength)
+        
+        // 4. 校验校验位
+        val checksum = packet[packet.size - 2]
+        if (!verifyChecksum(packet, checksum)) {
+            return null
+        }
+        
+        // 5. 解密数据
+        val decryptedData = BLECrypto.decrypt(encryptedData, encryptKey)
+        
+        // 6. 解析数据加密区
+        return parseEncryptedData(decryptedData)
+    }
+    
+    /**
+     * 解析数据加密区
+     */
+    private fun parseEncryptedData(data: ByteArray): BLEEncryptedData {
+        var offset = 0
+        
+        // 时间戳(4字节,小端序)
+        val timestamp = (data[offset].toInt() and 0xFF) or
+                       ((data[offset + 1].toInt() and 0xFF) shl 8) or
+                       ((data[offset + 2].toInt() and 0xFF) shl 16) or
+                       ((data[offset + 3].toInt() and 0xFF) shl 24)
+        offset += 4
+        
+        // 功能码
+        val functionCode = data[offset]
+        offset += 1
+        
+        // 指令类型
+        val instructionType = data[offset]
+        offset += 1
+        
+        // 应用数据
+        val applicationData = data.sliceArray(offset until data.size)
+        
+        return BLEEncryptedData(
+            timestamp = timestamp.toLong(),
+            functionCode = functionCode,
+            instructionType = instructionType,
+            applicationData = applicationData
+        )
+    }
+    
+    /**
+     * 校验校验位
+     */
+    private fun verifyChecksum(packet: ByteArray, expectedChecksum: Byte): Boolean {
+        var checksum = 0x00
+        // 从地址开始(跳过包头),到校验位前一位
+        for (i in 1 until packet.size - 2) {
+            checksum = checksum xor packet[i].toInt()
+        }
+        return checksum.toByte() == expectedChecksum
+    }
+}
+

+ 110 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketSplitter.kt

@@ -0,0 +1,110 @@
+package com.narutohuo.xindazhou.ble.util
+
+/**
+ * BLE分包处理器
+ * 
+ * 处理数据包的分包和组包
+ * 根据新大洲本田蓝牙协议文档的分包协议
+ */
+class BLEPacketSplitter {
+    
+    /**
+     * 分包数据
+     * 
+     * @param data 原始数据
+     * @param mtu MTU大小(最大传输单元)
+     * @param businessId 业务ID(4字节)
+     * @return 分包后的数据包列表
+     */
+    fun splitPacket(data: ByteArray, mtu: Int, businessId: Int): List<ByteArray> {
+        val packets = mutableListOf<ByteArray>()
+        val totalPackets = (data.size + mtu - 1) / mtu
+        
+        for (i in 0 until totalPackets) {
+            val start = i * mtu
+            val end = minOf(start + mtu, data.size)
+            val packetData = data.sliceArray(start until end)
+            
+            val packet = buildSplitPacket(
+                businessId = businessId,
+                totalPackets = totalPackets,
+                packetIndex = i,
+                data = packetData
+            )
+            
+            packets.add(packet)
+        }
+        
+        return packets
+    }
+    
+    /**
+     * 构建分包数据包
+     */
+    private fun buildSplitPacket(
+        businessId: Int,
+        totalPackets: Int,
+        packetIndex: Int,
+        data: ByteArray
+    ): ByteArray {
+        val packet = mutableListOf<Byte>()
+        
+        // 包头(0x0A)
+        packet.add(0x0A.toByte())
+        
+        // 业务ID(4字节,小端序)
+        packet.add((businessId and 0xFF).toByte())
+        packet.add(((businessId shr 8) and 0xFF).toByte())
+        packet.add(((businessId shr 16) and 0xFF).toByte())
+        packet.add(((businessId shr 24) and 0xFF).toByte())
+        
+        // 总包数(2字节,小端序)
+        packet.add((totalPackets and 0xFF).toByte())
+        packet.add(((totalPackets shr 8) and 0xFF).toByte())
+        
+        // 包序号(2字节,小端序)
+        packet.add((packetIndex and 0xFF).toByte())
+        packet.add(((packetIndex shr 8) and 0xFF).toByte())
+        
+        // 数据长度(2字节,小端序)
+        val dataLength = data.size
+        packet.add((dataLength and 0xFF).toByte())
+        packet.add(((dataLength shr 8) and 0xFF).toByte())
+        
+        // 数据区
+        packet.addAll(data.toList())
+        
+        // 应答状态(0x01=ACK)
+        packet.add(0x01.toByte())
+        
+        // 包校验(异或校验)
+        var checksum = 0x00
+        for (i in 1 until packet.size) {
+            checksum = checksum xor packet[i].toInt()
+        }
+        packet.add(checksum.toByte())
+        
+        // 包尾(0x0D)
+        packet.add(0x0D.toByte())
+        
+        return packet.toByteArray()
+    }
+    
+    /**
+     * 组包数据
+     * 
+     * @param packets 接收到的分包数据(Map<包序号, 数据>)
+     * @return 组包后的完整数据
+     */
+    fun combinePackets(packets: Map<Int, ByteArray>): ByteArray {
+        val sortedPackets = packets.toSortedMap()
+        val result = mutableListOf<Byte>()
+        
+        sortedPackets.values.forEach { packetData ->
+            result.addAll(packetData.toList())
+        }
+        
+        return result.toByteArray()
+    }
+}
+

+ 137 - 0
capability-ble/业务模块调用示例.md

@@ -0,0 +1,137 @@
+# BLE SDK业务模块调用示例
+
+## 📋 设计说明
+
+BLE SDK封装了新大洲本田蓝牙协议的所有细节,业务模块(特别是`module-vehicle`)可以直接调用高级API,不需要了解:
+- ❌ 数据包结构(包头、包尾、校验等)
+- ❌ 加密解密过程
+- ❌ 分包处理逻辑
+- ❌ UUID、功能码等底层细节
+
+## 🎯 业务模块调用示例
+
+### 1. 连接和握手
+
+```kotlin
+// 在module-vehicle中
+val bleService: BLEService = BLEServiceImpl(context)
+
+// 扫描设备
+bleService.startScan { device ->
+    if (device.name.startsWith("SDH-Smart")) {
+        // 连接设备
+        bleService.connect(device, object : ConnectCallback {
+            override fun onConnected() {
+                // 连接成功,进行握手
+                val userId = getUserID() // 16字节
+                val userType = BLEConstants.USER_TYPE_OWNER // 车主
+                
+                bleService.handshake(userId, userType, object : HandshakeCallback {
+                    override fun onSuccess() {
+                        // 握手成功,可以发送指令了
+                    }
+                    
+                    override fun onFailed(error: String) {
+                        // 握手失败
+                    }
+                })
+            }
+            
+            override fun onFailed(error: String) {
+                // 连接失败
+            }
+            
+            override fun onDisconnected() {
+                // 连接断开
+            }
+        })
+    }
+}
+```
+
+### 2. 发送应用控制指令(设撤防)
+
+```kotlin
+// 设防
+bleService.sendAppControlCommand(
+    AppControlInstruction.SET_DEFENSE,
+    byteArrayOf(0x01), // 0x01=设防,0x00=撤防
+    object : CommandCallback {
+        override fun onResponse(response: BLEResponse) {
+            if (response.success) {
+                // 设防成功
+            }
+        }
+        
+        override fun onTimeout() {
+            // 超时
+        }
+        
+        override fun onError(error: String) {
+            // 错误
+        }
+    }
+)
+```
+
+### 3. 发送系统控制指令(氛围灯)
+
+```kotlin
+// 开启氛围灯,设置颜色RGB(255, 0, 0)
+val colorData = byteArrayOf(0xFF.toByte(), 0x00, 0x00) // R, G, B
+
+bleService.sendSystemControlCommand(
+    SystemControlInstruction.AMBIENT_LIGHT_COLOR,
+    colorData,
+    object : CommandCallback {
+        override fun onResponse(response: BLEResponse) {
+            // 处理响应
+        }
+        
+        override fun onTimeout() { }
+        override fun onError(error: String) { }
+    }
+)
+```
+
+### 4. 查询车辆信息
+
+```kotlin
+bleService.queryVehicleInfo(object : CommandCallback {
+    override fun onResponse(response: BLEResponse) {
+        if (response.success && response.data != null) {
+            // 解析车辆信息(76字节数据)
+            val vehicleInfo = parseVehicleInfo(response.data!!)
+        }
+    }
+    
+    override fun onTimeout() { }
+    override fun onError(error: String) { }
+})
+```
+
+### 5. 接收实时数据
+
+```kotlin
+// 设置数据接收监听器
+bleService.setDataReceivedListener(object : DataCallback {
+    override fun onDataReceived(data: ByteArray) {
+        // 解析实时数据(车辆状态、电池信息等)
+        val vehicleStatus = parseVehicleStatus(data)
+    }
+})
+```
+
+## ✅ 封装优势
+
+1. **业务模块简单**:不需要了解协议细节,直接调用高级API
+2. **协议集中管理**:所有协议相关代码都在BLE SDK中
+3. **易于维护**:协议变更只需修改BLE SDK
+4. **类型安全**:使用常量定义(AppControlInstruction、SystemControlInstruction等)
+
+## 📝 注意事项
+
+- BLE SDK负责协议封装,业务模块负责业务逻辑
+- 响应数据(BLEResponse)在业务模块的Repository层转换为统一的业务模型
+- 业务模块不需要知道数据包结构、加密方式等细节
+

+ 496 - 0
capability-ble/使用说明-单例模式.md

@@ -0,0 +1,496 @@
+# 能力层 SDK 使用说明(单例模式)
+
+## 📋 为什么用单例?
+
+- 连接/服务是全局唯一的(BLE、Socket.IO、推送等)
+- 多个界面需要共享同一个连接状态
+- 避免重复连接、浪费资源
+
+## 🎯 推荐使用方式(本项目)
+
+### 方式1:直接获取单例(最简单,推荐)
+
+所有能力层都使用 `getInstance()` 获取单例:
+
+```kotlin
+// BLE服务(第一次调用需要context,后续不需要)
+val bleService = BLEServiceImpl.getInstance(this)  // 或 getInstance(context)
+
+// Socket.IO服务(不需要context)
+val socketService = SocketIOServiceImpl.getInstance()
+
+// 推送服务(不需要context,但initialize方法需要)
+val pushService = PushServiceImpl.getInstance()
+
+// 二维码服务(不需要context,但scanQRCode方法需要Activity)
+val qrCodeService = QRCodeServiceImpl.getInstance()
+
+// 分享服务(不需要context,但share方法需要Activity)
+val shareService = ShareServiceImpl.getInstance()
+
+// NFC服务(不需要context,但initialize方法需要Activity)
+val nfcService = NFCServiceImpl.getInstance()
+```
+
+**说明**:
+- BLE服务:第一次调用`getInstance(context)`时需要context(用于获取BluetoothManager),后续调用可以不带context
+- 其他服务:`getInstance()`不需要context,但具体方法(如initialize、scanQRCode等)可能需要Activity
+
+### 方式2:依赖注入(如果项目用了Dagger/Hilt)
+
+```kotlin
+@Module
+@InstallIn(SingletonComponent::class)
+object CapabilityModule {
+    @Provides @Singleton
+    fun provideBLEService(@ApplicationContext context: Context) = BLEServiceImpl.getInstance(context)
+    
+    @Provides @Singleton
+    fun provideSocketIOService() = SocketIOServiceImpl.getInstance()
+    
+    @Provides @Singleton
+    fun providePushService() = PushServiceImpl.getInstance()
+}
+
+// 在Activity中注入
+@Inject lateinit var bleService: BLEService
+@Inject lateinit var socketService: SocketIOService
+```
+
+## 📝 各能力层使用示例
+
+### 1. BLE服务(capability-ble)
+
+```kotlin
+class VehicleControlActivity : AppCompatActivity() {
+    private val bleService = BLEServiceImpl.getInstance(this)
+    
+    fun connectDevice(device: BLEDevice) {
+        // 统一使用lambda回调
+        bleService.connect(device) { response ->
+            if (response.success) {
+                // 连接成功
+            } else {
+                // 连接失败
+                val error = response.errorMessage
+            }
+        }
+    }
+    
+    fun lockCar() {
+        bleService.sendAppControlCommand(
+            AppControlInstruction.SET_DEFENSE,
+            byteArrayOf(0x01)
+        ) { response ->
+            if (response.success) {
+                // 设防成功
+                val data = response.data  // ByteArray?
+            } else {
+                // 设防失败
+                val error = response.errorMessage
+            }
+        }
+    }
+}
+```
+
+### 2. Socket.IO服务(capability-socketio)
+
+```kotlin
+class MessageActivity : AppCompatActivity() {
+    private val socketService = SocketIOServiceImpl.getInstance()
+    
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        
+        // 初始化并连接
+        socketService.init("ws://server.com", token)
+        socketService.connect()
+        
+        // 监听消息
+        socketService.on("message") { response ->
+            // 处理消息
+        }
+        
+        // 发送消息
+        socketService.emit("send_message", data)
+    }
+}
+```
+
+### 3. 推送服务(capability-push)
+
+```kotlin
+class MainActivity : AppCompatActivity() {
+    private val pushService = PushServiceImpl.getInstance()
+    
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        
+        // 初始化
+        pushService.initialize(this)
+        
+        // 设置别名
+        pushService.setAlias(userId)
+        
+        // 监听推送消息
+        pushService.setMessageListener { message ->
+            // 处理推送消息
+        }
+        
+        // 注册推送
+        pushService.register()
+    }
+}
+```
+
+### 4. 二维码服务(capability-qrcode)
+
+```kotlin
+class ScanActivity : AppCompatActivity() {
+    private val qrCodeService = QRCodeServiceImpl.getInstance()
+    
+    fun scanQRCode() {
+        qrCodeService.scanQRCode(this) { response ->
+            if (response.success) {
+                // 处理扫码结果(统一使用data字段)
+                val content = response.data  // String?(二维码内容)
+            } else {
+                // 扫码失败
+                val error = response.errorMessage
+            }
+        }
+    }
+    
+    fun generateQRCode(content: String): Bitmap? {
+        return qrCodeService.generateQRCode(content, 300)
+    }
+}
+```
+
+### 5. 分享服务(capability-share)
+
+```kotlin
+class ShareActivity : AppCompatActivity() {
+    private val shareService = ShareServiceImpl.getInstance()
+    
+    fun shareToWeChat() {
+        val content = ShareContent(
+            title = "标题",
+            description = "内容",
+            imageUrl = "https://...",
+            url = "https://..."
+        )
+        
+        shareService.shareToWeChat(this, content) { response ->
+            if (response.success) {
+                // 分享成功(统一使用data字段)
+                val platform = response.data  // SharePlatform?
+            } else {
+                // 分享失败
+                val error = response.errorMessage
+            }
+        }
+    }
+}
+```
+
+### 6. NFC服务(capability-nfc)
+
+```kotlin
+class NFCActivity : AppCompatActivity() {
+    private val nfcService = NFCServiceImpl.getInstance()
+    
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        
+        // 初始化(需要Activity)
+        nfcService.initialize(this)
+        
+        // 检查NFC支持
+        if (nfcService.isNFCSupported()) {
+            // 读取NFC标签
+            nfcService.readTag { response ->
+                if (response.success) {
+                    // 处理NFC数据
+                }
+            }
+        }
+    }
+}
+```
+
+## ✅ 使用要点
+
+1. **所有界面获取的都是同一个实例**
+   ```kotlin
+   // 界面1
+   val service1 = XxxServiceImpl.getInstance()
+   
+   // 界面2
+   val service2 = XxxServiceImpl.getInstance()
+   
+   // service1 和 service2 是同一个对象
+   ```
+
+2. **连接状态在所有界面共享**
+   ```kotlin
+   // 界面1:连接
+   socketService.connect()
+   
+   // 界面2:直接使用(无需重新连接)
+   if (socketService.isConnected()) {
+       socketService.emit("event", data)
+   }
+   ```
+
+3. **不需要手动销毁**
+   - 单例在应用生命周期内一直存在
+   - 不需要在Activity的`onDestroy()`中销毁
+   - 需要断开连接时调用对应的`disconnect()`方法
+
+## 📨 响应处理说明
+
+### 1. BLE服务响应处理
+
+BLE服务统一使用lambda回调处理响应:
+
+```kotlin
+// 连接响应(统一使用lambda)
+bleService.connect(device) { response ->
+    if (response.success) {
+        // 连接成功
+    } else {
+        // 连接失败
+        val error = response.errorMessage
+    }
+}
+
+// 指令响应(统一使用lambda)
+bleService.sendAppControlCommand(
+    AppControlInstruction.SET_DEFENSE,
+    byteArrayOf(0x01)
+) { response ->
+    if (response.success) {
+        // 指令成功,response.data包含响应数据(ByteArray)
+        val data = response.data
+    } else {
+        // 指令失败
+        val error = response.errorMessage
+    }
+}
+
+// 数据接收监听(实时数据)
+bleService.setDataReceivedListener(object : DataCallback {
+    override fun onDataReceived(data: ByteArray) {
+        // 接收到实时数据(车辆状态、电池信息等)
+        // 需要解析数据包
+    }
+})
+```
+
+**响应数据格式**(统一结构):
+- `BLEResponse.success`: 是否成功
+- `BLEResponse.data`: 响应数据(ByteArray?,需要根据协议解析)
+- `BLEResponse.errorCode`: 错误码(可选)
+- `BLEResponse.errorMessage`: 错误消息(可选)
+- `BLEResponse.timestamp`: 时间戳
+
+### 2. Socket.IO服务响应处理
+
+Socket.IO使用事件监听和回调处理响应:
+
+```kotlin
+// 监听事件(接收消息)
+socketService.on("vehicle_status") { response ->
+    // response.event: 事件名称
+    // response.data: JSON字符串
+    // response.timestamp: 时间戳
+    
+    val jsonData = JSONObject(response.data)
+    // 解析数据
+}
+
+// 发送消息(不需要响应回调,单向发送)
+socketService.emit("control_command", commandData)
+
+// 如果需要响应,可以监听对应的事件
+socketService.on("command_response") { response ->
+    // 处理响应
+}
+```
+
+**响应数据格式**:
+- `SocketIOResponse.event`: 事件名称(String)
+- `SocketIOResponse.data`: 数据(JSON字符串)
+- `SocketIOResponse.timestamp`: 时间戳(Long)
+
+### 3. 推送服务响应处理
+
+推送服务使用监听器处理消息:
+
+```kotlin
+// 设置消息监听器
+pushService.setMessageListener { message ->
+    // message.title: 推送标题
+    // message.content: 推送内容
+    // message.extras: 额外数据(Map<String, String>)
+    
+    // 处理推送消息
+    showNotification(message.title, message.content)
+}
+
+// 其他操作(setAlias、setTags等)通常不需要响应回调
+pushService.setAlias(userId)
+pushService.setTags(listOf("tag1", "tag2"))
+```
+
+**响应数据格式**:
+- `PushMessage.title`: 推送标题
+- `PushMessage.content`: 推送内容
+- `PushMessage.extras`: 额外数据(Map)
+
+### 4. 二维码服务响应处理
+
+二维码服务使用回调处理响应(统一结构):
+
+```kotlin
+// 扫码响应
+qrCodeService.scanQRCode(this) { response ->
+    if (response.success) {
+        // 扫码成功(统一使用data字段)
+        val content = response.data  // String?(二维码内容)
+    } else {
+        // 扫码失败
+        val error = response.errorMessage
+    }
+}
+
+// 识别图片中的二维码
+qrCodeService.recognizeQRCode(bitmap) { response ->
+    if (response.success) {
+        val content = response.data  // String?
+    } else {
+        val error = response.errorMessage
+    }
+}
+```
+
+**响应数据格式**(统一结构):
+- `QRCodeResponse.success`: 是否成功
+- `QRCodeResponse.data`: 二维码内容(String?)
+- `QRCodeResponse.errorCode`: 错误码(可选)
+- `QRCodeResponse.errorMessage`: 错误消息(可选)
+- `QRCodeResponse.timestamp`: 时间戳
+
+### 5. 分享服务响应处理
+
+分享服务使用回调处理响应(统一结构):
+
+```kotlin
+shareService.shareToWeChat(this, content) { response ->
+    if (response.success) {
+        // 分享成功(统一使用data字段)
+        val platform = response.data  // SharePlatform?
+        Toast.makeText(this, "分享成功", Toast.LENGTH_SHORT).show()
+    } else {
+        // 分享失败
+        val error = response.errorMessage
+        Toast.makeText(this, "分享失败: $error", Toast.LENGTH_SHORT).show()
+    }
+}
+```
+
+**响应数据格式**(统一结构):
+- `ShareResponse.success`: 是否成功
+- `ShareResponse.data`: 分享平台(SharePlatform?)
+- `ShareResponse.errorCode`: 错误码(可选)
+- `ShareResponse.errorMessage`: 错误消息(可选)
+- `ShareResponse.timestamp`: 时间戳
+
+### 6. NFC服务响应处理
+
+NFC服务使用回调处理响应(统一结构):
+
+```kotlin
+// 读取NFC标签
+nfcService.readTag { response ->
+    if (response.success) {
+        // 读取成功(统一使用data字段)
+        val data = response.data  // ByteArray?
+    } else {
+        // 读取失败
+        val error = response.errorMessage
+    }
+}
+
+// 写入NFC标签
+nfcService.writeTag(data) { response ->
+    if (response.success) {
+        // 写入成功
+    } else {
+        val error = response.errorMessage
+    }
+}
+
+// 设置标签发现监听器(实时监听)
+nfcService.setTagDiscoveredListener { response ->
+    // NFC标签靠近时触发
+    if (response.success) {
+        val data = response.data  // ByteArray?
+    }
+}
+```
+
+**响应数据格式**(统一结构):
+- `NFCResponse.success`: 是否成功
+- `NFCResponse.data`: 数据(ByteArray?)
+- `NFCResponse.errorCode`: 错误码(可选)
+- `NFCResponse.errorMessage`: 错误消息(可选)
+- `NFCResponse.timestamp`: 时间戳
+
+## ⚠️ 注意事项
+
+### 响应处理通用原则(统一模式)
+
+1. **统一响应结构**:所有能力层(除Socket.IO)都使用相同的响应结构
+   ```kotlin
+   data class XxxResponse(
+       val success: Boolean,
+       val data: T? = null,              // 数据类型不同
+       val errorCode: Int? = null,
+       val errorMessage: String? = null,
+       val timestamp: Long = System.currentTimeMillis()
+   )
+   ```
+
+2. **统一回调方式**:所有能力层都使用lambda回调
+   ```kotlin
+   service.xxx(...) { response ->
+       if (response.success) {
+           val data = response.data
+       } else {
+           val error = response.errorMessage
+       }
+   }
+   ```
+
+3. **异步回调**:所有响应都是异步的,不要在主线程中阻塞等待
+
+4. **错误处理**:始终检查`success`字段,处理失败情况
+
+5. **数据解析**:
+   - BLE/NFC:响应数据是`ByteArray?`,需要根据协议文档解析
+   - QRCode:响应数据是`String?`(二维码内容)
+   - Share:响应数据是`SharePlatform?`(分享平台)
+   - Socket.IO:响应数据是JSON字符串,需要解析
+
+6. **生命周期**:注意在Activity/Fragment销毁时取消监听,避免内存泄漏
+
+### 各服务特殊注意事项
+
+- **BLE服务**:传入的Context会自动转换为ApplicationContext,避免内存泄漏
+- **Socket.IO服务**:连接状态在所有界面共享,注意事件监听的注册和注销(使用`off()`方法)
+- **推送服务**:通常在Application中初始化一次即可,消息监听器全局有效
+- **NFC服务**:需要Activity上下文,单例内部会管理当前Activity
+- **测试**:可以调用`XxxServiceImpl.destroyInstance()`重置单例

+ 30 - 0
capability-nfc/build.gradle

@@ -0,0 +1,30 @@
+plugins {
+    alias(libs.plugins.kotlin.android)
+    id("com.android.library")
+}
+
+android {
+    namespace = "com.narutohuo.xindazhou.nfc"
+    compileSdk = 36
+
+    defaultConfig {
+        minSdk = 26
+    }
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_17
+        targetCompatibility = JavaVersion.VERSION_17
+    }
+    kotlinOptions {
+        jvmTarget = "17"
+    }
+}
+
+dependencies {
+    // 依赖base-core(所有SDK都依赖这个)
+    implementation(project(":base-core"))
+    
+    // AndroidX Core
+    implementation(libs.androidx.core.ktx)
+}
+

+ 13 - 0
capability-nfc/src/main/AndroidManifest.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- NFC权限 -->
+    <uses-permission android:name="android.permission.NFC" />
+    <!-- Android 10+ 需要前台服务权限 -->
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    
+    <!-- NFC功能声明 -->
+    <uses-feature
+        android:name="android.hardware.nfc"
+        android:required="false" />
+</manifest>
+

+ 64 - 0
capability-nfc/src/main/java/com/narutohuo/xindazhou/nfc/api/NFCService.kt

@@ -0,0 +1,64 @@
+package com.narutohuo.xindazhou.nfc.api
+
+import android.app.Activity
+import com.narutohuo.xindazhou.nfc.model.NFCResponse
+
+/**
+ * NFC服务接口
+ * 
+ * 提供NFC通信能力
+ * 用于车钥匙等功能
+ */
+interface NFCService {
+    
+    /**
+     * 初始化NFC服务
+     * 
+     * @param activity Activity上下文
+     */
+    fun initialize(activity: Activity)
+    
+    /**
+     * 检查设备是否支持NFC
+     * 
+     * @return true表示支持,false表示不支持
+     */
+    fun isNFCSupported(): Boolean
+    
+    /**
+     * 检查NFC是否已启用
+     * 
+     * @return true表示已启用,false表示未启用
+     */
+    fun isNFCEnabled(): Boolean
+    
+    /**
+     * 启用NFC(跳转到系统设置)
+     * 
+     * @param activity Activity上下文
+     */
+    fun enableNFC(activity: Activity)
+    
+    /**
+     * 读取NFC标签
+     * 
+     * @param callback 读取结果回调,返回NFCResponse
+     */
+    fun readTag(callback: (NFCResponse) -> Unit)
+    
+    /**
+     * 写入NFC标签
+     * 
+     * @param data 要写入的数据
+     * @param callback 写入结果回调,返回NFCResponse
+     */
+    fun writeTag(data: ByteArray, callback: (NFCResponse) -> Unit)
+    
+    /**
+     * 设置NFC标签发现监听器
+     * 
+     * @param listener 标签发现回调
+     */
+    fun setTagDiscoveredListener(listener: (NFCResponse) -> Unit)
+}
+

+ 107 - 0
capability-nfc/src/main/java/com/narutohuo/xindazhou/nfc/impl/NFCServiceImpl.kt

@@ -0,0 +1,107 @@
+package com.narutohuo.xindazhou.nfc.impl
+
+import android.app.Activity
+import android.content.Intent
+import android.nfc.NfcAdapter
+import android.nfc.NfcManager
+import android.provider.Settings
+import android.util.Log
+import com.narutohuo.xindazhou.nfc.api.NFCService
+import com.narutohuo.xindazhou.nfc.model.NFCResponse
+
+/**
+ * NFC服务实现类(单例模式)
+ * 
+ * 使用单例方便管理,多个界面可以共享同一个NFC服务
+ * 注意:NFC需要Activity上下文,但单例内部会管理当前Activity
+ * 
+ * 注意:具体实现需要根据业务需求完善
+ * 当前为基础框架,具体逻辑待实现
+ */
+class NFCServiceImpl private constructor() : NFCService {
+    
+    companion object {
+        @Volatile
+        private var INSTANCE: NFCServiceImpl? = null
+        
+        /**
+         * 获取NFC服务单例
+         */
+        @JvmStatic
+        fun getInstance(): NFCServiceImpl {
+            return INSTANCE ?: synchronized(this) {
+                INSTANCE ?: NFCServiceImpl().also { INSTANCE = it }
+            }
+        }
+        
+        /**
+         * 销毁单例(用于测试)
+         */
+        @JvmStatic
+        fun destroyInstance() {
+            INSTANCE = null
+        }
+    }
+    
+    private val tag = "NFCService"
+    private var currentActivity: Activity? = null
+    private var nfcAdapter: NfcAdapter? = null
+    private var tagDiscoveredListener: ((NFCResponse) -> Unit)? = null
+    
+    override fun initialize(activity: Activity) {
+        Log.d(tag, "initialize: NFC服务初始化")
+        this.currentActivity = activity
+        val nfcManager = activity.getSystemService(Activity.NFC_SERVICE) as? NfcManager
+        nfcAdapter = nfcManager?.defaultAdapter
+        // TODO: 初始化NFC相关配置
+    }
+    
+    override fun isNFCSupported(): Boolean {
+        val supported = nfcAdapter != null
+        Log.d(tag, "isNFCSupported: $supported")
+        return supported
+    }
+    
+    override fun isNFCEnabled(): Boolean {
+        val enabled = nfcAdapter?.isEnabled == true
+        Log.d(tag, "isNFCEnabled: $enabled")
+        return enabled
+    }
+    
+    override fun enableNFC(activity: Activity) {
+        Log.d(tag, "enableNFC: 跳转到NFC设置")
+        this.currentActivity = activity
+        activity.startActivity(Intent(Settings.ACTION_NFC_SETTINGS))
+    }
+    
+    override fun readTag(callback: (NFCResponse) -> Unit) {
+        Log.d(tag, "readTag: 读取NFC标签(待实现)")
+        // TODO: 实现NFC标签读取逻辑
+        callback(
+            NFCResponse(
+                success = false,
+                data = null,
+                errorMessage = "Not implemented"
+            )
+        )
+    }
+    
+    override fun writeTag(data: ByteArray, callback: (NFCResponse) -> Unit) {
+        Log.d(tag, "writeTag: 写入NFC标签 ${data.size} bytes(待实现)")
+        // TODO: 实现NFC标签写入逻辑
+        callback(
+            NFCResponse(
+                success = false,
+                data = null,
+                errorMessage = "Not implemented"
+            )
+        )
+    }
+    
+    override fun setTagDiscoveredListener(listener: (NFCResponse) -> Unit) {
+        this.tagDiscoveredListener = listener
+        Log.d(tag, "setTagDiscoveredListener: 设置NFC标签发现监听器")
+        // TODO: 实现NFC标签发现监听
+    }
+}
+

+ 61 - 0
capability-nfc/src/main/java/com/narutohuo/xindazhou/nfc/model/NFCResponse.kt

@@ -0,0 +1,61 @@
+package com.narutohuo.xindazhou.nfc.model
+
+/**
+ * NFC响应模型(统一结构)
+ * 
+ * 遵循统一设计:success, data, errorCode, errorMessage, timestamp
+ */
+data class NFCResponse(
+    /**
+     * 是否成功
+     */
+    val success: Boolean,
+    
+    /**
+     * 响应数据(读取的数据)
+     */
+    val data: ByteArray? = null,
+    
+    /**
+     * 错误码(如果有错误)
+     */
+    val errorCode: Int? = null,
+    
+    /**
+     * 错误消息(如果有错误)
+     */
+    val errorMessage: String? = null,
+    
+    /**
+     * 时间戳
+     */
+    val timestamp: Long = System.currentTimeMillis()
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as NFCResponse
+
+        if (success != other.success) return false
+        if (data != null) {
+            if (other.data == null) return false
+            if (!data.contentEquals(other.data)) return false
+        } else if (other.data != null) return false
+        if (errorCode != other.errorCode) return false
+        if (errorMessage != other.errorMessage) return false
+        if (timestamp != other.timestamp) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = success.hashCode()
+        result = 31 * result + (data?.contentHashCode() ?: 0)
+        result = 31 * result + (errorCode ?: 0)
+        result = 31 * result + (errorMessage?.hashCode() ?: 0)
+        result = 31 * result + timestamp.hashCode()
+        return result
+    }
+}
+

+ 47 - 0
capability-push/build.gradle

@@ -0,0 +1,47 @@
+plugins {
+    alias(libs.plugins.kotlin.android)
+    id("com.android.library")
+}
+
+android {
+    namespace = "com.narutohuo.xindazhou.push"
+    compileSdk = 36
+
+    defaultConfig {
+        minSdk = 26
+    }
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_17
+        targetCompatibility = JavaVersion.VERSION_17
+    }
+    kotlinOptions {
+        jvmTarget = "17"
+    }
+}
+
+repositories {
+    flatDir {
+        dirs 'libs'
+    }
+}
+
+dependencies {
+    // 依赖base-core(所有SDK都依赖这个)
+    implementation(project(":base-core"))
+    
+    // AndroidX Core
+    implementation(libs.androidx.core.ktx)
+    
+    // 日志通过 base-core 的 ILog 接口统一管理,无需单独依赖 Timber
+    
+    // Gson for JSON parsing (used by BroadcastReceiver)
+    implementation("com.google.code.gson:gson:2.10.1")
+    
+    // 极光推送SDK(使用本地下载的 AAR 文件)
+    // 注意:需要在极光推送官网注册应用获取 AppKey,并在 AndroidManifest.xml 中配置
+    // 文件已手动下载到 libs/ 目录
+    implementation(name: 'jpush-5.9.0', ext: 'aar')
+    implementation(name: 'jcore-5.2.0', ext: 'aar')
+}
+

二進制
capability-push/libs/jcore-5.2.0.aar


二進制
capability-push/libs/jcore-android-5.2.0.jar


二進制
capability-push/libs/jpush-5.9.0.aar


二進制
capability-push/libs/jpush-android-5.9.0.jar


+ 0 - 0
capability-push/src/main/AndroidManifest.xml


部分文件因文件數量過多而無法顯示