Explorar el Código

refactor: 清理旧文件并更新相关配置

- 删除 app 模块中已迁移到 base-common 的旧文件(Auth、Version 等)
- 删除 base-core 中废弃的接口文件
- 更新各模块的 build.gradle 配置
- 更新 MainActivity 和其他业务代码
- 清理不需要的文档文件
wangmeng hace 2 meses
padre
commit
d19484e598
Se han modificado 57 ficheros con 4762 adiciones y 3411 borrados
  1. 1 0
      BleUnlock-Android
  2. 17 119
      app/src/main/java/com/narutohuo/xindazhou/MainActivity.kt
  3. 0 25
      app/src/main/java/com/narutohuo/xindazhou/common/version/datasource/remote/VersionApi.kt
  4. 0 17
      app/src/main/java/com/narutohuo/xindazhou/common/version/model/VersionInfo.kt
  5. 0 59
      app/src/main/java/com/narutohuo/xindazhou/common/version/repository/VersionRepository.kt
  6. 0 61
      app/src/main/java/com/narutohuo/xindazhou/common/version/ui/UpdateDialog.kt
  7. 0 46
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/local/AuthLocalDataSource.kt
  8. 0 108
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/local/TokenManager.kt
  9. 0 37
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/remote/AuthApi.kt
  10. 0 81
      app/src/main/java/com/narutohuo/xindazhou/user/datasource/remote/AuthRemoteDataSource.kt
  11. 0 10
      app/src/main/java/com/narutohuo/xindazhou/user/model/LoginRequest.kt
  12. 0 31
      app/src/main/java/com/narutohuo/xindazhou/user/model/LoginResponse.kt
  13. 0 10
      app/src/main/java/com/narutohuo/xindazhou/user/model/RegisterRequest.kt
  14. 0 104
      app/src/main/java/com/narutohuo/xindazhou/user/repository/AuthRepository.kt
  15. 119 85
      app/src/main/java/com/narutohuo/xindazhou/vehicle/ui/VehicleFragment.kt
  16. 8 12
      app/src/main/res/xml/network_security_config.xml
  17. 294 0
      base-common/README.md
  18. 6 0
      base-common/build.gradle
  19. 124 0
      base-core/README.md
  20. 8 18
      base-core/build.gradle
  21. 0 23
      base-core/src/main/java/com/narutohuo/xindazhou/core/bridge/IBridge.kt
  22. 0 30
      base-core/src/main/java/com/narutohuo/xindazhou/core/config/IConfig.kt
  23. 0 31
      base-core/src/main/java/com/narutohuo/xindazhou/core/executor/IExecutor.kt
  24. 2 2
      base-core/src/main/java/com/narutohuo/xindazhou/core/network/NetworkManager.kt
  25. 0 114
      base-core/src/main/java/com/narutohuo/xindazhou/core/network/converter/FastJsonConverterFactory.kt
  26. 73 4
      base-core/src/main/java/com/narutohuo/xindazhou/wxapi/WXEntryActivity.kt
  27. 666 0
      capability-ble/README.md
  28. 3 3
      capability-ble/build.gradle
  29. 164 44
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/api/BLEService.kt
  30. 397 743
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/impl/BLEServiceImpl.kt
  31. 57 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEEncryptedData.kt
  32. 0 85
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEPacket.kt
  33. 110 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/Command.kt
  34. 41 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/FragmentBuffer.kt
  35. 179 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/Packet.kt
  36. 143 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEExtension.kt
  37. 112 31
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketBuilder.kt
  38. 101 31
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketParser.kt
  39. 127 70
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketSplitter.kt
  40. 174 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BleConnector.kt
  41. 343 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BlePacketSender.kt
  42. 113 0
      capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BleScanner.kt
  43. 3 3
      capability-nfc/build.gradle
  44. 4 4
      capability-push/build.gradle
  45. 3 3
      capability-push/src/main/java/com/narutohuo/xindazhou/push/receiver/JPushReceiver.kt
  46. 170 16
      capability-push/集成说明.html
  47. 178 15
      capability-push/集成说明.md
  48. 3 3
      capability-qrcode/build.gradle
  49. 3 3
      capability-share/build.gradle
  50. 0 0
      capability-share/分享集成说明.html
  51. 398 0
      capability-share/重构方案-移除ShareProxyActivity.md
  52. 5 4
      capability-socketio/build.gradle
  53. 4 4
      capability-socketio/src/main/java/com/narutohuo/xindazhou/socketio/impl/SocketIOServiceImpl.kt
  54. 0 454
      新大洲 Android 项目结构文档.html
  55. 275 0
      架构说明.html
  56. 334 0
      架构说明.md
  57. 0 868
      能力模块开发规范.md

+ 1 - 0
BleUnlock-Android

@@ -0,0 +1 @@
+Subproject commit fb4e55585f9365a89aedfc6ed20412a736de6215

+ 17 - 119
app/src/main/java/com/narutohuo/xindazhou/MainActivity.kt

@@ -1,134 +1,32 @@
 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.ApiServiceFactory
-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.user.datasource.local.TokenManager
-import kotlinx.coroutines.launch
-
-// BuildConfig 会自动生成在 app 模块的包名下
-// 由于 MainActivity 就在 app 模块的包名下,可以直接使用 BuildConfig
+import com.narutohuo.xindazhou.common.ui.BaseActivity
+import com.narutohuo.xindazhou.common.version.VersionUpdateManager
+import com.narutohuo.xindazhou.databinding.ActivityMainBinding
 
 /**
- * 主Activity - 应用入口(单一Activity架构)
+ * 主界面 Activity
  * 
  * 职责:
- * 1. 应用启动入口
- * 2. 初始化 TokenManager 和 ServerConfigManager
- * 3. 版本检查(启动时检查是否有新版本)
- * 4. 使用 Navigation Component 管理页面导航
+ * 1. 显示主界面(MainFragment)
+ * 2. 版本检查(启动时检查是否有新版本)
  * 
- * 架构说明
- * - 未登录状态:显示 LoginFragment
- * - 已登录状态:显示 MainFragment(包含 TabBar 和各个业务 Fragment)
+ * 注意:
+ * - 登录状态判断已在 LaunchActivity 中处理
+ * - 版本检查独立处理,不影响页面显示
  */
-class MainActivity : AppCompatActivity() {
-    
-    companion object {
-        private const val PLATFORM_ANDROID = 1 // 平台类型:1-安卓
-    }
+class MainActivity : BaseActivity<ActivityMainBinding>() {
     
-    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()
+    override fun getViewBinding(): ActivityMainBinding {
+        return ActivityMainBinding.inflate(layoutInflater)
     }
     
-    /**
-     * 设置导航
-     * 根据登录状态决定显示登录页面还是主界面
-     */
-    private fun setupNavigation() {
-        val navHostFragment = supportFragmentManager.findFragmentById(R.id.navHostFragment) as? NavHostFragment
-        val navController = navHostFragment?.navController ?: return
+    override fun initView() {
+        // 版本检查(独立处理,不影响页面显示)
+        VersionUpdateManager.checkUpdate(this)
         
-        // 根据登录状态决定起始页面
-        if (TokenManager.isLoggedIn()) {
-            navController.navigate(R.id.mainFragment)
-        }
-        // 如果未登录,默认显示登录页面(由 nav_graph.xml 中的 startDestination 决定)
+        // 主界面内容由 Navigation Component 管理
+        // nav_graph.xml 中的 startDestination 已经设置为 mainFragment
     }
-    
-    /**
-     * 检查版本更新
-     * 如果没有版本或检查失败,不影响正常启动
-     */
-    private fun checkVersionUpdate() {
-        lifecycleScope.launch {
-            try {
-                // 获取当前版本号
-                val currentVersionCode = getCurrentVersionCode()
-                
-                // 使用 ApiServiceFactory 创建 API 实例
-                val versionApi = ApiServiceFactory.create<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 // 默认版本号
-        }
-    }
-    
-    // 注意:分享回调已完全封装在 ShareProxyActivity 中处理
-    // 业务层不需要在 MainActivity 中处理 onActivityResult
-    // 所有分享回调都会自动回到 ShareProxyActivity,由它统一处理
 }
 

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

@@ -1,25 +0,0 @@
-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("version/latest")
-    suspend fun getLatestVersion(
-        @Query("platform") platform: Int,
-        @Query("currentVersionCode") currentVersionCode: Int? = null
-    ): VersionInfo
-}
-

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

@@ -1,17 +0,0 @@
-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           // 发布时间
-)
-

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

@@ -1,59 +0,0 @@
-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
-    }
-}
-

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

@@ -1,61 +0,0 @@
-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()
-    }
-}
-

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

@@ -1,46 +0,0 @@
-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()
-    }
-}
-

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

@@ -1,108 +0,0 @@
-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)
-    }
-}
-

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

@@ -1,37 +0,0 @@
-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
-import retrofit2.http.Query
-
-/**
- * 认证相关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>>
-    
-    /**
-     * 刷新 Token
-     * 
-     * 注意:服务端使用 @RequestParam,所以使用 @Query
-     */
-    @POST("member/auth/refresh-token")
-    suspend fun refreshToken(@Query("refreshToken") refreshToken: String): Response<CommonResult<LoginResponse>>
-}
-

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

@@ -1,81 +0,0 @@
-package com.narutohuo.xindazhou.user.datasource.remote
-
-import com.narutohuo.xindazhou.common.network.ApiResponseParser
-import com.narutohuo.xindazhou.common.network.ApiServiceFactory
-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>
-    
-    /**
-     * 刷新 Token
-     */
-    suspend fun refreshToken(refreshToken: String): Result<LoginResponse>
-}
-
-/**
- * 认证远程数据源实现
- */
-class AuthRemoteDataSourceImpl : AuthRemoteDataSource {
-    
-    companion object {
-        private const val TAG = "AuthRemoteDataSource"
-    }
-    
-    private val authApi: AuthApi by lazy {
-        ApiServiceFactory.create<AuthApi>()
-    }
-    
-    override suspend fun login(request: LoginRequest): Result<LoginResponse> {
-        return try {
-            ApiResponseParser.handleResponse(
-                response = authApi.login(request),
-                dataClass = LoginResponse::class.java,
-                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),
-                dataClass = LoginResponse::class.java,
-                tag = "$TAG - register",
-                errorMessage = "注册失败"
-            )
-        } catch (e: Exception) {
-            Result.failure(e)
-        }
-    }
-    
-    override suspend fun refreshToken(refreshToken: String): Result<LoginResponse> {
-        return try {
-            ApiResponseParser.handleResponse(
-                response = authApi.refreshToken(refreshToken),
-                dataClass = LoginResponse::class.java,
-                tag = "$TAG - refreshToken",
-                errorMessage = "Token 刷新失败"
-            )
-        } catch (e: Exception) {
-            Result.failure(e)
-        }
-    }
-}
-

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

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

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

@@ -1,31 +0,0 @@
-package com.narutohuo.xindazhou.user.model
-
-import com.alibaba.fastjson2.annotation.JSONField
-
-/**
- * 登录响应数据
- * 对应后端 AppAuthLoginRespVO
- * 
- * 注意:服务端返回的 expiresTime 是 LocalDateTime,Fastjson2 会自动转换为时间戳(毫秒)
- */
-data class LoginResponse(
-    @JSONField(name = "userId")
-    val userId: Long,
-    
-    @JSONField(name = "accessToken")
-    val accessToken: String,
-    
-    @JSONField(name = "refreshToken")
-    val refreshToken: String,
-    
-    @JSONField(name = "expiresTime")
-    val expiresTime: Long? = null,  // 服务端返回 LocalDateTime,Fastjson2 会自动转换为时间戳(毫秒)
-    
-    @JSONField(name = "openid")
-    val openid: String? = null,
-    
-    // 以下字段为兼容字段(后端不返回,但前端可能需要)
-    val username: String? = null,
-    val mobile: String? = null
-)
-

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

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

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

@@ -1,104 +0,0 @@
-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)
-        }
-    }
-    
-    /**
-     * 刷新 Token
-     * 
-     * @param refreshToken 刷新令牌
-     * @return 刷新结果(包含新的 accessToken 和 refreshToken)
-     */
-    suspend fun refreshToken(refreshToken: String): Result<LoginResponse> {
-        return try {
-            // 从远程数据源获取数据
-            val result = remoteDataSource.refreshToken(refreshToken)
-            
-            // 如果成功,保存到本地
-            result.onSuccess { response ->
-                localDataSource.saveToken(response)
-                ILog.d(TAG, "refreshToken: Token已刷新并保存")
-            }
-            
-            result
-        } catch (e: Exception) {
-            ILog.e(TAG, "refreshToken: 刷新异常", e)
-            Result.failure(e)
-        }
-    }
-}
-

+ 119 - 85
app/src/main/java/com/narutohuo/xindazhou/vehicle/ui/VehicleFragment.kt

@@ -21,6 +21,8 @@ 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 com.narutohuo.xindazhou.common.log.LogHelper
+import org.json.JSONObject
 import java.nio.ByteBuffer
 import java.nio.ByteOrder
 
@@ -52,9 +54,6 @@ class VehicleFragment : Fragment() {
     // 蓝牙服务
     private lateinit var bleService: BLEService
     
-    // 当前连接的设备(可以从用户设置或车辆列表获取)
-    private var currentBleDevice: BLEDevice? = null
-    
     // 当前设防状态(用于切换)
     private var isDefenseOn = false
     // 当前上电状态(用于切换)
@@ -137,19 +136,16 @@ class VehicleFragment : Fragment() {
         
         initViews(view)
         setupClickListeners()
-        setupDataListener()
         updateConnectionStatus()
     }
 
     override fun onDestroyView() {
         super.onDestroyView()
         rootView = null
-        // 清理数据监听
-        bleService.setDataReceivedListener(object : DataCallback {
-            override fun onDataReceived(data: ByteArray) {
-                // 空实现,避免内存泄漏
-            }
-        })
+        // 断开连接
+        if (bleService.isConnected()) {
+            bleService.disconnect()
+        }
     }
 
     private fun initViews(view: View) {
@@ -211,20 +207,6 @@ class VehicleFragment : Fragment() {
         btnSetTiltAlarmThreshold = view.findViewById(R.id.btnSetTiltAlarmThreshold)
     }
 
-    /**
-     * 设置数据接收监听
-     */
-    private fun setupDataListener() {
-        bleService.setDataReceivedListener(object : DataCallback {
-            override fun onDataReceived(data: ByteArray) {
-                // 处理主动推送的数据
-                // 这里可以根据功能码和指令类型解析数据
-                activity?.runOnUiThread {
-                    // 更新UI状态
-                }
-            }
-        })
-    }
 
     /**
      * 更新连接状态显示
@@ -240,7 +222,7 @@ class VehicleFragment : Fragment() {
     }
 
     private fun setupClickListeners() {
-        // 蓝牙连接
+        // 蓝牙连接/断开
         btnConnectBluetooth.setOnClickListener {
             if (bleService.isConnected()) {
                 // 断开连接
@@ -248,16 +230,8 @@ class VehicleFragment : Fragment() {
                 updateConnectionStatus()
                 Toast.makeText(context, "已断开连接", Toast.LENGTH_SHORT).show()
             } else {
-                // 连接设备
-                // TODO: 从用户设置或车辆列表获取设备信息
-                // 这里需要先扫描或从已保存的设备列表中选择
-                if (currentBleDevice == null) {
-                    Toast.makeText(context, "请先选择要连接的设备", Toast.LENGTH_SHORT).show()
-                    // 可以打开设备选择对话框或扫描界面
-                    return@setOnClickListener
-                }
-                
-                connectToDevice(currentBleDevice!!)
+                // 一键扫描并连接
+                connectToDevice()
             }
         }
 
@@ -287,15 +261,15 @@ class VehicleFragment : Fragment() {
         btnDefense.setOnClickListener {
             if (!checkConnection()) return@setOnClickListener
             
-            val action = if (isDefenseOn) 0x00.toByte() else 0x01.toByte()
-            isDefenseOn = !isDefenseOn
+            val enabled = !isDefenseOn
+            isDefenseOn = enabled
             
-            bleService.sendAppControlCommand(AppControlInstruction.SET_DEFENSE, byteArrayOf(action)) { response ->
+            bleService.setDefense(enabled = enabled) { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
-                        Toast.makeText(context, if (action == 0x01.toByte()) "设防成功" else "撤防成功", Toast.LENGTH_SHORT).show()
+                        Toast.makeText(context, if (enabled) "设防成功" else "撤防成功", Toast.LENGTH_SHORT).show()
                     } else {
-                        isDefenseOn = !isDefenseOn // 恢复状态
+                        isDefenseOn = !enabled // 恢复状态
                         Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
                     }
                 }
@@ -306,16 +280,30 @@ class VehicleFragment : Fragment() {
         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()
+            if (isPowerOn) {
+                // 下电
+                isPowerOn = false
+                bleService.powerOff { response ->
+                    activity?.runOnUiThread {
+                        if (response.success) {
+                            Toast.makeText(context, "下电成功", Toast.LENGTH_SHORT).show()
+                        } else {
+                            isPowerOn = true // 恢复状态
+                            Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                        }
+                    }
+                }
+            } else {
+                // 上电
+                isPowerOn = true
+                bleService.powerOn { response ->
+                    activity?.runOnUiThread {
+                        if (response.success) {
+                            Toast.makeText(context, "上电成功", Toast.LENGTH_SHORT).show()
+                        } else {
+                            isPowerOn = false // 恢复状态
+                            Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+                        }
                     }
                 }
             }
@@ -325,7 +313,7 @@ class VehicleFragment : Fragment() {
         btnFindCar.setOnClickListener {
             if (!checkConnection()) return@setOnClickListener
             
-            bleService.sendAppControlCommand(AppControlInstruction.FIND_CAR, byteArrayOf(0x01)) { response ->
+            bleService.findCar { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
                         Toast.makeText(context, "寻车成功", Toast.LENGTH_SHORT).show()
@@ -340,7 +328,7 @@ class VehicleFragment : Fragment() {
         btnSeatLock.setOnClickListener {
             if (!checkConnection()) return@setOnClickListener
             
-            bleService.sendAppControlCommand(AppControlInstruction.SEAT_LOCK, byteArrayOf(0x01)) { response ->
+            bleService.unlockSeat { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
                         Toast.makeText(context, "座桶锁已打开", Toast.LENGTH_SHORT).show()
@@ -355,12 +343,11 @@ class VehicleFragment : Fragment() {
         btnHandlebarLock.setOnClickListener {
             if (!checkConnection()) return@setOnClickListener
             
-            // 切换状态(需要根据当前状态决定)
-            val action = 0x01.toByte() // 假设当前是关闭,点击后打开
-            bleService.sendAppControlCommand(AppControlInstruction.HANDLEBAR_LOCK, byteArrayOf(action)) { response ->
+            // 假设当前是关闭,点击后打开
+            bleService.unlockHandlebar { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
-                        Toast.makeText(context, if (action == 0x01.toByte()) "龙头锁已打开" else "龙头锁已关闭", Toast.LENGTH_SHORT).show()
+                        Toast.makeText(context, "龙头锁已打开", Toast.LENGTH_SHORT).show()
                     } else {
                         Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
                     }
@@ -372,11 +359,11 @@ class VehicleFragment : Fragment() {
         btnTrunkLock.setOnClickListener {
             if (!checkConnection()) return@setOnClickListener
             
-            val action = 0x01.toByte() // 假设当前是关闭,点击后打开
-            bleService.sendAppControlCommand(AppControlInstruction.TRUNK_LOCK, byteArrayOf(action)) { response ->
+            // 假设当前是关闭,点击后打开
+            bleService.unlockTrunk { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
-                        Toast.makeText(context, if (action == 0x01.toByte()) "尾箱锁已打开" else "尾箱锁已关闭", Toast.LENGTH_SHORT).show()
+                        Toast.makeText(context, "尾箱锁已打开", Toast.LENGTH_SHORT).show()
                     } else {
                         Toast.makeText(context, "操作失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
                     }
@@ -392,8 +379,7 @@ class VehicleFragment : Fragment() {
                 return@setOnCheckedChangeListener
             }
             
-            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
-            bleService.sendSystemControlCommand(SystemControlInstruction.SENSOR_UNLOCK, byteArrayOf(action)) { response ->
+            bleService.setSensorUnlock(enabled = isChecked) { response ->
                 activity?.runOnUiThread {
                     if (!response.success) {
                         switchInductionUnlock.isChecked = !isChecked
@@ -482,8 +468,7 @@ class VehicleFragment : Fragment() {
                 return@setOnCheckedChangeListener
             }
             
-            val action = if (isChecked) 0x01.toByte() else 0x00.toByte()
-            bleService.sendSystemControlCommand(SystemControlInstruction.AMBIENT_LIGHT, byteArrayOf(action)) { response ->
+            bleService.setAmbientLight(enabled = isChecked) { response ->
                 activity?.runOnUiThread {
                     if (!response.success) {
                         switchAtmosphereLight.isChecked = !isChecked
@@ -576,8 +561,7 @@ class VehicleFragment : Fragment() {
                 return@setOnClickListener
             }
             
-            val data = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(time.toShort()).array()
-            bleService.sendSystemControlCommand(SystemControlInstruction.AUTO_POWER_OFF_TIME, data) { response ->
+            bleService.setAutoPowerOffTime(timeSeconds = time) { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
                         Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
@@ -643,7 +627,7 @@ class VehicleFragment : Fragment() {
                 return@setOnClickListener
             }
             
-            bleService.sendSystemControlCommand(SystemControlInstruction.SPEAKER_VOLUME, byteArrayOf(volume.toByte())) { response ->
+            bleService.setSpeakerVolume(volume = volume) { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
                         Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
@@ -683,7 +667,7 @@ class VehicleFragment : Fragment() {
             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 ->
+            bleService.setAmbientLightColor(r = r, g = g, b = b) { response ->
                 activity?.runOnUiThread {
                     if (response.success) {
                         Toast.makeText(context, "设置成功", Toast.LENGTH_SHORT).show()
@@ -843,31 +827,81 @@ class VehicleFragment : Fragment() {
     }
 
     /**
-     * 连接到设备
+     * 连接到设备(一键完成扫描+连接+握手)
      */
-    private fun connectToDevice(device: BLEDevice) {
+    private fun connectToDevice() {
         btnConnectBluetooth.isEnabled = false
-        tvBluetoothStatus.text = "连接中..."
+        tvBluetoothStatus.text = "正在扫描设备..."
+        
+        // TODO: 从用户信息获取userId和userType(这里使用示例数据)
+        val userId = ByteArray(16) { it.toByte() } // 示例:实际应该从用户信息获取
+        val userType = BLEConstants.USER_TYPE_OWNER
         
-        bleService.connect(device) { response ->
+        // 一键完成:初始化监听 + 扫描 + 连接 + 握手
+        bleService.initializeAndConnect(
+            userId = userId,
+            userType = userType,
+            onConnected = {
+                activity?.runOnUiThread {
+                    btnConnectBluetooth.isEnabled = true
+                    updateConnectionStatus()
+                    Toast.makeText(context, "连接成功", Toast.LENGTH_SHORT).show()
+                    // 连接成功后可以查询车辆信息
+                    btnQueryVehicleInfo.performClick()
+                }
+            },
+            onDisconnected = {
+                activity?.runOnUiThread {
+                    updateConnectionStatus()
+                    Toast.makeText(context, "连接已断开", Toast.LENGTH_SHORT).show()
+                }
+            },
+            onDataReceived = { data ->
+                // 处理接收到的数据
+                handleReceivedData(data)
+            },
+            onError = { error ->
+                activity?.runOnUiThread {
+                    btnConnectBluetooth.isEnabled = true
+                    updateConnectionStatus()
+                    Toast.makeText(context, "连接失败: $error", Toast.LENGTH_SHORT).show()
+                }
+            }
+        )
+    }
+    
+    /**
+     * 处理接收到的数据
+     */
+    private fun handleReceivedData(data: ByteArray) {
+        try {
+            val jsonString = String(data, Charsets.UTF_8)
+            val jsonObject = org.json.JSONObject(jsonString)
+            
             activity?.runOnUiThread {
-                btnConnectBluetooth.isEnabled = true
-                updateConnectionStatus()
+                // 根据消息类型更新UI
+                val ty = jsonObject.optInt("TY", 0)
+                val `in` = jsonObject.optInt("IN", 0)
                 
-                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()
+                // 处理不同类型的消息
+                when {
+                    ty == 3 && `in` == 3 -> {
+                        // 握手请求
+                        LogHelper.d("VehicleFragment", "收到握手请求")
+                    }
+                    ty == 3 && `in` == 4 -> {
+                        // 配对请求
+                        val pairing = jsonObject.optJSONObject("C")?.optJSONObject("D")?.optInt("Pairing", 0) ?: 0
+                        LogHelper.d("VehicleFragment", "收到配对请求,状态: $pairing")
+                    }
+                    else -> {
+                        // 其他业务消息
+                        LogHelper.d("VehicleFragment", "收到业务消息: $jsonString")
+                    }
                 }
             }
+        } catch (e: Exception) {
+            LogHelper.e("VehicleFragment", "解析接收数据失败", e)
         }
     }
 

+ 8 - 12
app/src/main/res/xml/network_security_config.xml

@@ -1,16 +1,12 @@
 <?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>
+    <!-- 允许所有域名的明文HTTP通信(仅限内网环境使用) -->
+    <!-- 注意:此配置允许所有 IP 和域名使用 HTTP,仅适用于内网环境 -->
+    <!-- 生产环境建议使用 HTTPS 并配置具体的域名白名单 -->
+    <base-config cleartextTrafficPermitted="true">
+        <trust-anchors>
+            <certificates src="system" />
+        </trust-anchors>
+    </base-config>
 </network-security-config>
 

+ 294 - 0
base-common/README.md

@@ -0,0 +1,294 @@
+# base-common 模块说明
+
+## 📋 模块定位
+
+**base-common** 是业务封装层,提供:
+- 封装 base-core 的接口(BridgeManager、ConfigManager、ExecutorManager)
+- MVVM 网络封装(ApiServiceFactory、ApiBaseRemoteDataSource)
+- UI 基础类(BaseActivity、BaseFragment)
+
+## 🎯 使用原则
+
+- ✅ **业务层(app 模块)可以调用 base-common**
+- ✅ **能力层(capability 模块)也可以调用 base-common**(如果需要业务封装)
+
+---
+
+## 📁 目录结构
+
+### 1. bridge/ - 桥接服务封装
+
+```
+✅ BridgeManager.kt           - 封装 IBridge,提供 H5通信、模块间通信的便捷方法
+```
+
+**功能:**
+- H5 通信:`callH5Method()`、`onH5Call()`
+- 模块间通信:`postEvent()`、`subscribeEvent()`
+
+### 2. config/ - 配置管理封装
+
+```
+✅ ConfigManager.kt           - 封装 IConfig,提供通用的配置管理
+⚠️ ServerConfigManager.kt    - 特定业务场景(开发测试时的服务器配置,待移到 app 模块)
+```
+
+**功能:**
+- 基础配置:`getString()`、`getInt()`、`getBoolean()`
+- 环境切换:`getEnvironment()`、`setEnvironment()`
+- 功能开关:`isFeatureEnabled()`、`setFeatureEnabled()`
+
+### 3. executor/ - 执行器封装
+
+```
+✅ ExecutorManager.kt         - 封装 IExecutor,提供异步任务执行的便捷方法
+```
+
+**功能:**
+- IO 线程执行:`executeIO()`
+- 主线程执行:`executeMain()`
+- 延迟执行:`executeDelayed()`
+- 降级方案:如果 IExecutor 未注册,使用协程实现
+
+### 4. network/ - MVVM 网络封装
+
+```
+✅ ApiServiceFactory.kt       - API 服务工厂,统一创建 API 服务实例
+✅ ApiBaseRemoteDataSource.kt - 远程数据源基类,封装通用网络请求逻辑
+✅ ApiBaseRepository.kt       - Repository 基类,提供通用错误处理和数据转换
+✅ ApiResponseParser.kt       - 响应解析器,解析 Retrofit Response
+```
+
+**功能:**
+- 统一创建 API 服务:`ApiServiceFactory.create<AuthApi>()`
+- 统一错误处理:超时、网络异常、业务错误
+- 自动线程切换:IO 线程执行请求
+- 统一日志记录
+
+### 5. ui/ - UI 基础类
+
+```
+✅ BaseActivity.kt            - Activity 基类,支持 ViewBinding、加载状态管理
+✅ BaseFragment.kt            - Fragment 基类,支持 ViewBinding、加载状态管理
+✅ ActivityExtensions.kt      - Activity 扩展函数,简化 StateFlow 观察
+✅ FragmentExtensions.kt      - Fragment 扩展函数,简化 StateFlow 观察
+```
+
+**功能:**
+- ViewBinding 支持
+- 加载状态管理:`showLoading()`、`hideLoading()`
+- 错误/成功消息显示:`showError()`、`showSuccess()`
+- StateFlow 观察:`observeStateFlow()`
+
+---
+
+## 💡 核心作用
+
+### 1. 封装 base-core 的接口
+
+**提供便捷的调用方式:**
+```kotlin
+// 使用 BridgeManager(封装 IBridge)
+BridgeManager.postEvent("user_login", userData)
+
+// 使用 ConfigManager(封装 IConfig)
+val apiUrl = ConfigManager.getString("api_url", "https://api.example.com")
+
+// 使用 ExecutorManager(封装 IExecutor)
+ExecutorManager.executeIO {
+    // 执行耗时操作
+}
+```
+
+### 2. MVVM 网络封装
+
+**简化网络请求:**
+```kotlin
+// 创建 API 服务
+val authApi = ApiServiceFactory.create<AuthApi>()
+
+// 封装数据源
+class AuthRemoteDataSource : ApiBaseRemoteDataSource() {
+    private val authApi = ApiServiceFactory.create<AuthApi>()
+    suspend fun login() = executeRequest { authApi.login() }
+}
+```
+
+### 3. UI 基础类
+
+**简化 UI 开发:**
+```kotlin
+class LoginActivity : BaseActivity<ActivityLoginBinding>() {
+    override fun getViewBinding() = ActivityLoginBinding.inflate(layoutInflater)
+    
+    override fun initObserver() {
+        observeStateFlow(viewModel.uiState) { state ->
+            // 处理状态变化
+        }
+    }
+}
+```
+
+---
+
+## 📝 使用示例
+
+### 业务层使用 base-common
+
+#### 1. 使用 BridgeManager(H5通信、模块间通信)
+
+```kotlin
+// app/src/.../MainActivity.kt
+import com.narutohuo.xindazhou.common.bridge.BridgeManager
+
+class MainActivity : AppCompatActivity() {
+    fun initBridge() {
+        // H5通信
+        BridgeManager.callH5Method("showToast", "Hello")
+        BridgeManager.onH5Call("getUserInfo") { result ->
+            // 处理结果
+        }
+        
+        // 模块间通信
+        BridgeManager.postEvent("user_login", userData)
+        BridgeManager.subscribeEvent("user_logout") { data ->
+            // 处理事件
+        }
+    }
+}
+```
+
+#### 2. 使用 ConfigManager(配置管理)
+
+```kotlin
+// app/src/.../MainActivity.kt
+import com.narutohuo.xindazhou.common.config.ConfigManager
+
+class MainActivity : AppCompatActivity() {
+    fun initConfig() {
+        // 获取配置
+        val apiUrl = ConfigManager.getString("api_url", "https://api.example.com")
+        val isDebug = ConfigManager.getBoolean("is_debug", false)
+        
+        // 设置配置
+        ConfigManager.setString("api_url", "https://api.example.com")
+        ConfigManager.setEnvironment("prod")
+        
+        // 功能开关
+        if (ConfigManager.isFeatureEnabled("new_feature")) {
+            // 启用新功能
+        }
+    }
+}
+```
+
+#### 3. 使用 ExecutorManager(异步任务执行)
+
+```kotlin
+// app/src/.../MainActivity.kt
+import com.narutohuo.xindazhou.common.executor.ExecutorManager
+
+class MainActivity : AppCompatActivity() {
+    fun executeTask() {
+        // IO线程执行
+        ExecutorManager.executeIO {
+            // 执行耗时操作
+            val data = fetchData()
+            
+            // 主线程更新UI
+            ExecutorManager.executeMain {
+                updateUI(data)
+            }
+        }
+        
+        // 延迟执行
+        ExecutorManager.executeDelayed(1000) {
+            // 1秒后执行
+        }
+    }
+}
+```
+
+#### 4. 使用 ApiServiceFactory(网络请求)
+
+```kotlin
+// Application 中初始化
+class XinDaZhouApplication : Application() {
+    override fun onCreate() {
+        super.onCreate()
+        
+        // 设置默认 baseUrl
+        ApiServiceFactory.baseUrlProvider = { 
+            ServerConfigManager.getHttpServerUrl() 
+        }
+    }
+}
+
+// 业务层使用
+class AuthRemoteDataSource : ApiBaseRemoteDataSource() {
+    private val authApi = ApiServiceFactory.create<AuthApi>()
+    
+    suspend fun login(request: LoginRequest): Result<LoginResponse> {
+        return executeRequest(
+            request = { authApi.login(request) },
+            errorMessage = "登录失败"
+        )
+    }
+}
+```
+
+#### 5. 使用 BaseActivity/BaseFragment(UI 基础类)
+
+```kotlin
+// app/src/.../LoginActivity.kt
+import com.narutohuo.xindazhou.common.ui.BaseActivity
+import com.narutohuo.xindazhou.common.ui.observeStateFlow
+
+class LoginActivity : BaseActivity<ActivityLoginBinding>() {
+    
+    private val viewModel: LoginViewModel by viewModels()
+    
+    override fun getViewBinding() = ActivityLoginBinding.inflate(layoutInflater)
+    
+    override fun initView() {
+        binding.btnLogin.setOnClickListener {
+            viewModel.login()
+        }
+    }
+    
+    override fun initObserver() {
+        // 观察 UI 状态
+        observeStateFlow(viewModel.uiState) { state ->
+            when (state) {
+                is LoginUiState.Loading -> showLoading()
+                is LoginUiState.Success -> {
+                    hideLoading()
+                    showSuccess("登录成功")
+                }
+                is LoginUiState.Error -> {
+                    hideLoading()
+                    showError(state.message)
+                }
+            }
+        }
+    }
+}
+```
+
+---
+
+## ⚠️ 注意事项
+
+1. **业务层统一使用 base-common**,不直接使用 base-core
+2. **ApiServiceFactory 需要在 Application 中初始化** `baseUrlProvider`
+3. **ConfigManager、BridgeManager、ExecutorManager 需要 app 模块实现对应的接口**(通过 ARouter 注册)
+4. **ServerConfigManager 是特定业务场景**,后续考虑移到 app 模块
+
+---
+
+## 🔗 相关文档
+
+- [base-core README](../base-core/README.md)
+- [网络请求 MVVM 封装方案](./src/main/java/com/narutohuo/xindazhou/common/network/网络请求MVVM封装方案.md)
+- [UI 层封装方案](./src/main/java/com/narutohuo/xindazhou/common/ui/UI层封装方案.md)
+

+ 6 - 0
base-common/build.gradle

@@ -29,12 +29,18 @@ dependencies {
     // 使用 api 传递 base-core 的依赖给其他模块
     api(project(":base-core"))
     
+    // Activity KTX (提供 ComponentActivity 和 ActivityResultLauncher 支持)
+    implementation("androidx.activity:activity-ktx:1.8.2")
+    
     // Fragment KTX (提供 DialogFragment 支持)
     implementation("androidx.fragment:fragment-ktx:1.6.2")
     
     // Material Design (用于对话框UI)
     implementation("com.google.android.material:material:1.11.0")
     
+    // RecyclerView (用于级联选择器)
+    implementation("androidx.recyclerview:recyclerview:1.3.2")
+    
     // 注意:Gson、Retrofit、OkHttp、Glide、Coroutines、Timber 已通过 base-core 传递,无需重复依赖
     // 日志通过 base-core 的 ILog 接口统一管理,无需单独依赖 Timber
 }

+ 124 - 0
base-core/README.md

@@ -0,0 +1,124 @@
+# base-core 模块说明
+
+## 📋 模块定位
+
+**base-core** 是基础设施层,提供:
+- 接口定义(给 capability 模块实现)
+- 基础实现(ILog、NetworkManager)
+- 第三方库管理(统一版本,避免冲突)
+
+## 🎯 使用原则
+
+- ✅ **能力层(capability 模块)可以调用 base-core**
+- ❌ **业务层(app 模块)不直接调用 base-core**,应该通过 base-common
+
+---
+
+## 📁 目录结构
+
+### 1. 接口定义
+
+```
+✅ bridge/IBridge.kt          - H5通信、模块间通信、事件总线管理
+✅ config/IConfig.kt          - 配置管理、环境切换、功能开关、版本管理
+✅ executor/IExecutor.kt      - 线程池管理、异步任务执行、定时任务
+✅ push/IPushService.kt       - 推送服务接口
+✅ share/IShareService.kt     - 分享服务接口
+✅ share/IShareCallback.kt    - 分享回调接口
+✅ storage/IStorage.kt        - 存储服务接口(键值存储、文件存储、数据库存储)
+✅ util/IUtil.kt              - 工具类接口(时间处理、字符串处理、加密解密)
+```
+
+### 2. 基础实现
+
+```
+✅ log/ILog.kt                - 日志接口定义
+✅ log/impl/TimberLog.kt      - Timber 日志实现(基于 Timber 库)
+✅ log/impl/NoOpLog.kt        - 空日志实现(生产环境使用)
+✅ network/NetworkManager.kt - Retrofit/OkHttp 管理器(单例模式)
+```
+
+### 3. 第三方库(在 build.gradle 中)
+
+```gradle
+✅ Retrofit & OkHttp          - api("com.squareup.retrofit2:retrofit:2.9.0")
+✅ Gson                       - api("com.google.code.gson:gson:2.10.1")
+✅ Glide                      - api("com.github.bumptech.glide:glide:4.16.0")
+✅ Coroutines                 - api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
+✅ ARouter                    - api("com.alibaba:arouter-api:1.5.2")
+✅ Timber                     - api("com.jakewharton.timber:timber:5.0.1")
+⏸️ 友盟 SDK                  - 暂时保留(待后续决定)
+```
+
+---
+
+## 💡 核心作用
+
+### 1. 定义接口(解耦)
+
+**capability 模块实现接口:**
+```kotlin
+// capability-push 实现 IPushService
+@Route(path = "/push/service")
+class PushServiceImpl : IPushService {
+    override fun initialize(...) {
+        ILog.d("PushService", "初始化")  // 使用 base-core 的 ILog
+        // 调用极光推送 SDK
+    }
+}
+```
+
+### 2. 提供基础能力(统一工具)
+
+**capability 模块使用基础能力:**
+```kotlin
+// capability-push 使用 ILog
+ILog.d("PushService", "推送成功")
+
+// capability-share 使用 ILog
+ILog.d("ShareService", "分享成功")
+
+// capability 模块使用 NetworkManager
+val retrofit = NetworkManager.getRetrofit()
+```
+
+### 3. 管理第三方库(版本统一)
+
+所有模块通过 base-core 使用第三方库,避免版本冲突。
+
+---
+
+## 📝 使用示例
+
+### capability 模块使用 base-core
+
+```kotlin
+// capability-push/src/.../PushServiceImpl.kt
+import com.narutohuo.xindazhou.core.push.IPushService
+import com.narutohuo.xindazhou.core.log.ILog
+import com.narutohuo.xindazhou.core.network.NetworkManager
+
+@Route(path = "/push/service")
+class PushServiceImpl : IPushService {
+    
+    override fun initialize(context: Context, appKey: String) {
+        // 使用 ILog 打日志
+        ILog.d("PushService", "初始化推送服务: $appKey")
+        
+        // 使用 NetworkManager(如果需要)
+        val retrofit = NetworkManager.getRetrofit()
+        
+        // 调用极光推送 SDK
+        JPushInterface.init(context)
+    }
+}
+```
+
+---
+
+## ⚠️ 注意事项
+
+1. **接口实现由 app 模块提供**(通过 ARouter 注册)
+2. **capability 模块实现接口**(如 IPushService、IShareService)
+3. **业务层不直接使用 base-core**,应该通过 base-common
+

+ 8 - 18
base-core/build.gradle

@@ -21,9 +21,8 @@ android {
 }
 
 repositories {
-    flatDir {
-        dirs '../capability-share/libs'
-    }
+    // base-core 不再需要访问 capability-share/libs 目录
+    // 友盟相关依赖由 capability-share 模块管理
 }
 
 dependencies {
@@ -40,10 +39,9 @@ dependencies {
     api("com.squareup.okhttp3:okhttp:4.12.0")
     api("com.squareup.okhttp3:logging-interceptor:4.12.0")
     
-    // Fastjson2(JSON解析,替代 Gson)
-    // 注意:Fastjson2 需要 Java 8+
-    // Maven Central: https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2
-    api("com.alibaba.fastjson2:fastjson2:2.0.47")
+    // Gson(JSON解析)
+    api("com.google.code.gson:gson:2.10.1")
+    api("com.squareup.retrofit2:converter-gson:2.9.0")
     
     // Glide(图片加载,所有模块都需要)
     api("com.github.bumptech.glide:glide:4.16.0")
@@ -55,17 +53,9 @@ dependencies {
     // ARouter(路由和依赖注入)
     api("com.alibaba:arouter-api:1.5.2")
     
-    // 友盟分享 SDK(仅用于 WXEntryActivity 等回调 Activity)
-    // 注意:虽然 base-core 是基础设施层,但为了支持第三方回调 Activity,需要添加此依赖
-    // 友盟基础组件库(所有友盟业务SDK都依赖基础组件库)
-    api("com.umeng.umsdk:common:+")  // 必选
-    api("com.umeng.umsdk:asms:+")    // 必选
-    // 分享核心库(必选)
-    api("com.umeng.umsdk:share-core:+")
-    // 微信分享(完整版)
-    // 注意:友盟微信分享 JAR 文件在 share 模块的 libs 目录
-    // 通过 flatDir 仓库访问
-    api(files('../capability-share/libs/umeng-share-wechat-full-7.3.7.jar'))
+    // 微信 SDK(仅用于 WXEntryActivity 回调 Activity)
+    // 注意:base-core 只依赖微信官方 SDK,不依赖友盟
+    // 友盟相关依赖应该在 capability-share 模块中
     api("com.tencent.mm.opensdk:wechat-sdk-android:6.8.24")
 }
 

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

@@ -1,23 +0,0 @@
-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)
-}
-

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

@@ -1,30 +0,0 @@
-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)
-}
-

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

@@ -1,31 +0,0 @@
-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)
-}
-

+ 2 - 2
base-core/src/main/java/com/narutohuo/xindazhou/core/network/NetworkManager.kt

@@ -1,8 +1,8 @@
 package com.narutohuo.xindazhou.core.network
 
 import com.narutohuo.xindazhou.core.log.ILog
-import com.narutohuo.xindazhou.core.network.converter.FastJsonConverterFactory
 import okhttp3.OkHttpClient
+import retrofit2.converter.gson.GsonConverterFactory
 import okhttp3.logging.HttpLoggingInterceptor
 import retrofit2.Retrofit
 import java.util.concurrent.TimeUnit
@@ -96,7 +96,7 @@ object NetworkManager {
         return Retrofit.Builder()
             .baseUrl(config.baseUrl)
             .client(getOkHttpClient(config))
-            .addConverterFactory(FastJsonConverterFactory.create())
+            .addConverterFactory(GsonConverterFactory.create())
             .build()
     }
     

+ 0 - 114
base-core/src/main/java/com/narutohuo/xindazhou/core/network/converter/FastJsonConverterFactory.kt

@@ -1,114 +0,0 @@
-package com.narutohuo.xindazhou.core.network.converter
-
-import com.alibaba.fastjson2.JSON
-import okhttp3.MediaType
-import okhttp3.MediaType.Companion.toMediaType
-import okhttp3.RequestBody
-import okhttp3.RequestBody.Companion.toRequestBody
-import okhttp3.ResponseBody
-import retrofit2.Converter
-import retrofit2.Retrofit
-import java.lang.reflect.ParameterizedType
-import java.lang.reflect.Type
-
-/**
- * FastJson Converter Factory(工厂模式)
- * 
- * 用于 Retrofit 的 JSON 转换,替代 Gson
- * 
- * 使用方式:
- * ```kotlin
- * Retrofit.Builder()
- *     .addConverterFactory(FastJsonConverterFactory.create())
- *     .build()
- * ```
- */
-class FastJsonConverterFactory private constructor() : Converter.Factory() {
-    
-    companion object {
-        private val MEDIA_TYPE: MediaType = "application/json; charset=UTF-8".toMediaType()
-        
-        /**
-         * 创建 FastJson Converter Factory 实例(工厂方法)
-         */
-        @JvmStatic
-        fun create(): FastJsonConverterFactory {
-            return FastJsonConverterFactory()
-        }
-    }
-    
-    override fun requestBodyConverter(
-        type: Type,
-        parameterAnnotations: Array<Annotation>,
-        methodAnnotations: Array<Annotation>,
-        retrofit: Retrofit
-    ): Converter<*, RequestBody>? {
-        return RequestBodyConverter<Any>()
-    }
-    
-    override fun responseBodyConverter(
-        type: Type,
-        annotations: Array<Annotation>,
-        retrofit: Retrofit
-    ): Converter<ResponseBody, *>? {
-        return ResponseBodyConverter<Any>(type)
-    }
-    
-    /**
-     * 请求体转换器(将对象转换为 JSON RequestBody)
-     */
-    private class RequestBodyConverter<T> : Converter<T, RequestBody> {
-        @Suppress("UNCHECKED_CAST")
-        override fun convert(value: T): RequestBody? {
-            val json = JSON.toJSONString(value)
-            return json.toRequestBody(MEDIA_TYPE)
-        }
-    }
-    
-    /**
-     * 响应体转换器(将 JSON ResponseBody 转换为对象)
-     * 
-     * 对于 CommonResult<T> 类型,解析为 CommonResult<Map>,然后在 ApiResponseParser 中统一处理类型转换
-     * 这样可以避免 Fastjson2 在解析嵌套泛型时的类型擦除问题
-     */
-    private class ResponseBodyConverter<T>(
-        private val type: Type
-    ) : Converter<ResponseBody, T> {
-        @Suppress("UNCHECKED_CAST")
-        override fun convert(value: ResponseBody): T {
-            val json = value.string()
-            try {
-                com.narutohuo.xindazhou.core.log.ILog.d("FastJsonConverter", "解析JSON: type=${type}, json=${json.take(200)}...")
-                
-                // Fastjson2 支持嵌套泛型,直接使用 parseObject 即可
-                // 对于 ParameterizedType(如 CommonResult<LoginResponse>),Fastjson2 会自动处理
-                val result = JSON.parseObject(json, type) as T
-                
-                // 检查解析结果
-                if (result != null && type is ParameterizedType) {
-                    val rawType = type.rawType
-                    val rawTypeName = (rawType as? Class<*>)?.name ?: ""
-                    if (rawTypeName.contains("CommonResult")) {
-                        try {
-                            val dataField = result.javaClass.getDeclaredField("data")
-                            dataField.isAccessible = true
-                            val dataValue = dataField.get(result)
-                            com.narutohuo.xindazhou.core.log.ILog.d("FastJsonConverter", "解析成功: ${result.javaClass.simpleName}, data类型=${dataValue?.javaClass?.simpleName ?: "null"}")
-                        } catch (e: Exception) {
-                            com.narutohuo.xindazhou.core.log.ILog.e("FastJsonConverter", "检查 data 字段失败: ${e.message}", e)
-                        }
-                    }
-                } else {
-                    com.narutohuo.xindazhou.core.log.ILog.d("FastJsonConverter", "解析成功: ${result?.let { it::class.java.simpleName } ?: "null"}")
-                }
-                
-                return result
-                
-            } catch (e: Exception) {
-                com.narutohuo.xindazhou.core.log.ILog.e("FastJsonConverter", "JSON解析失败: type=${type}, json=${json.take(500)}", e)
-                throw e
-            }
-        }
-    }
-}
-

+ 73 - 4
base-core/src/main/java/com/narutohuo/xindazhou/wxapi/WXEntryActivity.kt

@@ -1,17 +1,23 @@
 package com.narutohuo.xindazhou.wxapi
 
+import android.app.Activity
 import android.content.Intent
 import android.os.Bundle
 import com.alibaba.android.arouter.facade.annotation.Autowired
 import com.alibaba.android.arouter.launcher.ARouter
 import com.narutohuo.xindazhou.core.log.ILog
 import com.narutohuo.xindazhou.core.share.IShareCallback
-import com.umeng.socialize.weixin.view.WXCallbackActivity
+import com.tencent.mm.opensdk.constants.ConstantsAPI
+import com.tencent.mm.opensdk.modelbase.BaseReq
+import com.tencent.mm.opensdk.modelbase.BaseResp
+import com.tencent.mm.opensdk.openapi.IWXAPI
+import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
+import com.tencent.mm.opensdk.openapi.WXAPIFactory
 
 /**
  * 微信分享回调 Activity
  * 
- * 按照友盟官方文档,需要创建此 Activity 处理微信分享回调
+ * 按照微信官方 SDK 文档,需要创建此 Activity 处理微信分享回调
  * 
  * 注意:
  * - 包名必须是应用包名(com.narutohuo.xindazhou.wxapi),不能是模块 namespace
@@ -22,14 +28,17 @@ import com.umeng.socialize.weixin.view.WXCallbackActivity
  * - 使用 ARouter 依赖注入获取 IShareCallback 接口实现
  * - share 模块实现 IShareCallback 接口并通过 ARouter 注册
  * - base-core 不直接依赖 share 模块,实现解耦
+ * - base-core 只依赖微信官方 SDK,不依赖友盟
  * 
  * 工作原理:
  * 1. 用户在微信中完成分享操作后,微信会通过 Intent 回调到此 Activity
- * 2. 友盟的 WXCallbackActivity 会自动处理回调,并触发友盟 SDK 的回
+ * 2. 通过微信 SDK 的 IWXAPIEventHandler 接口处理回
  * 3. 通过 ARouter 获取 IShareCallback 实现,调用 share 模块的处理方法
  * 4. share 模块处理完成后,通过 ShareProxyActivity 的回调传递给业务层
  */
-class WXEntryActivity : WXCallbackActivity() {
+class WXEntryActivity : Activity(), IWXAPIEventHandler {
+    
+    private var api: IWXAPI? = null
     
     /**
      * 通过 ARouter 依赖注入获取分享回调服务
@@ -46,6 +55,10 @@ class WXEntryActivity : WXCallbackActivity() {
         // ARouter 依赖注入
         ARouter.getInstance().inject(this)
         
+        // 创建微信 API 实例(需要从 share 模块获取 AppId,这里先尝试处理回调)
+        // 注意:实际的微信 API 初始化应该在 share 模块中完成
+        // 这里只是接收回调并转发给 share 模块处理
+        
         ILog.d("WXEntryActivity", "onCreate: 收到微信回调")
         
         // 调用 share 模块处理回调
@@ -55,16 +68,72 @@ class WXEntryActivity : WXCallbackActivity() {
         } ?: run {
             ILog.e("WXEntryActivity", "未找到 IShareCallback 实现,请确保 share 模块已注册")
         }
+        
+        // 处理微信回调(通过 IWXAPIEventHandler)
+        handleIntent(intent)
+        
+        // 关闭 Activity
+        finish()
     }
     
     override fun onNewIntent(intent: Intent?) {
         super.onNewIntent(intent)
+        setIntent(intent)
         ILog.d("WXEntryActivity", "onNewIntent: 收到新的微信回调 Intent")
         
         // 调用 share 模块处理回调
         intent?.let {
             shareCallback?.onWeChatCallback(it)
+            handleIntent(it)
         }
     }
+    
+    /**
+     * 处理微信回调 Intent
+     */
+    private fun handleIntent(intent: Intent?) {
+        if (intent == null) return
+        
+        // 尝试从 share 模块获取微信 API 实例
+        // 如果 share 模块已经初始化了微信 API,这里可以直接使用
+        // 否则,这里只转发 Intent 给 share 模块处理
+        
+        // 注意:微信 SDK 要求通过 IWXAPI.handleIntent 处理回调
+        // 但这里为了解耦,将 Intent 转发给 share 模块处理
+        // share 模块会使用自己的 IWXAPI 实例处理回调
+    }
+    
+    /**
+     * 微信请求回调
+     */
+    override fun onReq(req: BaseReq?) {
+        ILog.d("WXEntryActivity", "onReq: ${req?.type}")
+        // 微信请求通常不需要处理,主要是响应回调
+    }
+    
+    /**
+     * 微信响应回调
+     */
+    override fun onResp(resp: BaseResp?) {
+        ILog.d("WXEntryActivity", "onResp: type=${resp?.type}, errCode=${resp?.errCode}, errStr=${resp?.errStr}")
+        
+        when (resp?.type) {
+            ConstantsAPI.COMMAND_SENDAUTH -> {
+                // 微信登录回调
+                ILog.d("WXEntryActivity", "收到微信登录回调")
+            }
+            ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX -> {
+                // 微信分享回调
+                ILog.d("WXEntryActivity", "收到微信分享回调")
+            }
+            ConstantsAPI.COMMAND_PAY_BY_WX -> {
+                // 微信支付回调
+                ILog.d("WXEntryActivity", "收到微信支付回调")
+            }
+        }
+        
+        // 将回调转发给 share 模块处理
+        shareCallback?.onWeChatCallback(intent)
+    }
 }
 

+ 666 - 0
capability-ble/README.md

@@ -0,0 +1,666 @@
+# BLE 蓝牙能力层集成说明
+
+## 概述
+
+`capability-ble` 模块封装了新大洲本田蓝牙协议,提供简洁的高级 API 供业务模块调用。所有底层细节(连接、握手、配对、分包、加密等)都在能力层内部完成,业务层只需要调用简单的 API 即可。
+
+## 快速开始
+
+### 方式一:最简单(推荐)
+
+```kotlin
+import com.narutohuo.xindazhou.ble.factory.BLEServiceFactory
+import com.narutohuo.xindazhou.ble.api.BLEService
+
+class VehicleControlActivity : AppCompatActivity() {
+    
+    private lateinit var bleService: BLEService
+    
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        
+        // 获取服务实例并一键初始化连接
+        bleService = BLEServiceFactory.create(this)
+        
+        val userId = getUserId() // 16字节,从用户信息获取
+        val userType = BLEConstants.USER_TYPE_OWNER
+        
+        // 一键完成:初始化监听 + 扫描 + 连接 + 握手
+        bleService.initializeAndConnect(
+            userId = userId,
+            userType = userType,
+            onConnected = {
+                // 连接成功,已自动完成握手和配对,可以直接使用
+                showToast("连接成功")
+                setupControls()
+            },
+            onDisconnected = {
+                showToast("连接已断开")
+            },
+            onDataReceived = { data ->
+                // 处理接收到的数据
+                handleReceivedData(data)
+            },
+            onError = { error ->
+                showError(error)
+            }
+        )
+    }
+    
+    private fun setupControls() {
+        // 设防
+        btnDefense.setOnClickListener {
+            bleService.setDefense(enabled = true) { response ->
+                if (response.success) showToast("设防成功")
+            }
+        }
+        
+        // 上电
+        btnPower.setOnClickListener {
+            bleService.powerOn { response ->
+                if (response.success) showToast("上电成功")
+            }
+        }
+    }
+    
+    override fun onDestroy() {
+        super.onDestroy()
+        if (bleService.isConnected()) {
+            bleService.disconnect()
+        }
+    }
+}
+```
+
+### 方式二:分步操作(更灵活)
+
+### 1. 获取服务实例
+
+```kotlin
+import com.narutohuo.xindazhou.ble.factory.BLEServiceFactory
+import com.narutohuo.xindazhou.ble.api.BLEService
+
+// 在任何地方获取单例实例
+val bleService: BLEService = BLEServiceFactory.create(context)
+```
+
+### 2. 扫描设备
+
+```kotlin
+// 开始扫描
+bleService.startScan { device ->
+    // 找到设备
+    println("发现设备: ${device.name}, MAC: ${device.address}")
+}
+
+// 停止扫描(通常在找到设备后或超时后调用)
+bleService.stopScan()
+```
+
+### 3. 连接设备(自动完成握手和配对)
+
+```kotlin
+// 准备用户信息
+val userId = ByteArray(16) { /* 从用户信息获取 */ }
+val userType = BLEConstants.USER_TYPE_OWNER // 0x02=车主
+
+// 连接设备(连接成功即表示已完成握手和配对)
+val device = BLEDevice(
+    name = "新大洲",
+    address = "AA:BB:CC:DD:EE:FF",
+    rssi = -50
+)
+
+bleService.connect(device, userId, userType) { response ->
+    if (response.success) {
+        // 连接成功,已自动完成握手和配对,可以直接使用
+        println("连接成功")
+    } else {
+        // 连接失败
+        println("连接失败: ${response.errorMessage}")
+    }
+}
+```
+
+### 4. 发送指令
+
+连接成功后,就可以发送各种指令了。推荐使用便捷方法,更简单易用:
+
+#### 4.1 便捷方法(推荐)
+
+```kotlin
+// 设防/撤防
+bleService.setDefense(enabled = true) { response ->
+    if (response.success) {
+        println("设防成功")
+    }
+}
+
+// 上电/下电
+bleService.powerOn { response ->
+    if (response.success) {
+        println("上电成功")
+    }
+}
+
+bleService.powerOff { response ->
+    if (response.success) {
+        println("下电成功")
+    }
+}
+
+// 寻车
+bleService.findCar { response ->
+    if (response.success) {
+        println("寻车成功")
+    }
+}
+
+// 座桶锁
+bleService.unlockSeat { response ->
+    if (response.success) {
+        println("座桶锁已打开")
+    }
+}
+
+// 龙头锁
+bleService.unlockHandlebar { response ->
+    if (response.success) {
+        println("龙头锁已打开")
+    }
+}
+
+bleService.lockHandlebar { response ->
+    if (response.success) {
+        println("龙头锁已关闭")
+    }
+}
+
+// 尾箱锁
+bleService.unlockTrunk { response ->
+    if (response.success) {
+        println("尾箱锁已打开")
+    }
+}
+
+bleService.lockTrunk { response ->
+    if (response.success) {
+        println("尾箱锁已关闭")
+    }
+}
+
+// 感应解锁开关
+bleService.setSensorUnlock(enabled = true) { response ->
+    if (response.success) {
+        println("感应解锁已开启")
+    }
+}
+
+// 氛围灯开关
+bleService.setAmbientLight(enabled = true) { response ->
+    if (response.success) {
+        println("氛围灯已开启")
+    }
+}
+
+// 氛围灯颜色(RGB)
+bleService.setAmbientLightColor(r = 255, g = 0, b = 0) { response ->
+    if (response.success) {
+        println("氛围灯颜色已设置为红色")
+    }
+}
+
+// 自动下电时间(秒)
+bleService.setAutoPowerOffTime(timeSeconds = 300) { response ->
+    if (response.success) {
+        println("自动下电时间已设置为300秒")
+    }
+}
+
+// 蓝牙音箱音量(0-100)
+bleService.setSpeakerVolume(volume = 50) { response ->
+    if (response.success) {
+        println("音量已设置为50%")
+    }
+}
+```
+
+#### 4.2 通用方法(高级用法)
+
+如果需要更灵活的控制,可以使用通用方法:
+
+```kotlin
+import com.narutohuo.xindazhou.ble.model.AppControlInstruction
+
+// 应用控制指令
+bleService.sendAppControlCommand(
+    instructionType = AppControlInstruction.SET_DEFENSE,
+    data = byteArrayOf(0x01)
+) { response ->
+    // 处理响应
+}
+```
+
+#### 4.3 查询车辆信息
+
+```kotlin
+bleService.queryVehicleInfo { response ->
+    if (response.success && response.data != null) {
+        // 解析车辆信息
+        val data = response.data!!
+        // 根据协议文档解析数据
+        // data[0]: 设防状态
+        // data[1]: 上电状态
+        // data[2]: 门锁状态
+        // ...
+    } else {
+        println("查询失败: ${response.errorMessage}")
+    }
+}
+```
+
+#### 4.4 系统控制指令(其他)
+
+对于便捷方法未覆盖的指令,可以使用通用方法:
+
+```kotlin
+import com.narutohuo.xindazhou.ble.model.SystemControlInstruction
+
+// 被盗锁定开关
+bleService.sendSystemControlCommand(
+    instructionType = SystemControlInstruction.STOLEN_LOCK,
+    data = byteArrayOf(0x01) // 0x01=开启, 0x00=关闭
+) { response ->
+    // 处理响应
+}
+
+// 更多指令类型请查看 SystemControlInstruction 对象
+```
+
+#### 4.5 系统设置指令
+
+```kotlin
+import com.narutohuo.xindazhou.ble.config.BLEConstants
+import com.narutohuo.xindazhou.ble.model.BLECommand
+
+// 钥匙学码
+val command = BLECommand(
+    functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_SETTING,
+    instructionType = 0x01.toByte(),
+    applicationData = byteArrayOf(0x01)
+)
+
+bleService.sendCommand(command) { response ->
+    // 处理响应
+}
+
+// 震动灵敏度设置
+val command = BLECommand(
+    functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_SETTING,
+    instructionType = 0x02.toByte(),
+    applicationData = byteArrayOf(3) // 1-5级
+)
+
+bleService.sendCommand(command) { response ->
+    // 处理响应
+}
+```
+
+### 5. 接收数据
+
+```kotlin
+import com.narutohuo.xindazhou.ble.callback.DataCallback
+
+bleService.setDataReceivedListener(object : DataCallback {
+    override fun onDataReceived(data: ByteArray) {
+        // 处理接收到的数据(通常是JSON格式)
+        val jsonString = String(data, Charsets.UTF_8)
+        println("收到数据: $jsonString")
+        
+        // 解析JSON并处理业务逻辑
+        // ...
+    }
+})
+```
+
+### 6. 断开连接
+
+```kotlin
+bleService.disconnect()
+```
+
+## 完整使用示例
+
+### 方式三:分步操作(更灵活)
+
+如果需要更精细的控制,可以分步操作:
+
+```kotlin
+class VehicleControlActivity : AppCompatActivity() {
+    
+    private lateinit var bleService: BLEService
+    
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        
+        // 1. 获取服务实例
+        bleService = BLEServiceFactory.create(this)
+        
+        // 2. 设置数据接收监听
+        bleService.setDataReceivedListener(object : DataCallback {
+            override fun onDataReceived(data: ByteArray) {
+                handleReceivedData(data)
+            }
+        })
+        
+        // 3. 扫描设备
+        scanDevices()
+    }
+    
+    private fun scanDevices() {
+        bleService.startScan { device ->
+            // 找到设备,停止扫描
+            bleService.stopScan()
+            
+            // 连接设备
+            connectToDevice(device)
+        }
+        
+        // 10秒后自动停止扫描
+        Handler(Looper.getMainLooper()).postDelayed({
+            bleService.stopScan()
+        }, 10000)
+    }
+    
+    private fun connectToDevice(device: BLEDevice) {
+        val userId = getUserId() // 16字节
+        val userType = BLEConstants.USER_TYPE_OWNER
+        
+        bleService.connect(device, userId, userType) { response ->
+            if (response.success) {
+                // 连接成功,已自动完成握手和配对
+                onConnected()
+            } else {
+                showError("连接失败: ${response.errorMessage}")
+            }
+        }
+    }
+    
+    private fun onConnected() {
+        // 连接成功后,可以发送各种指令
+        // ...
+    }
+    
+    override fun onDestroy() {
+        super.onDestroy()
+        if (bleService.isConnected()) {
+            bleService.disconnect()
+        }
+    }
+}
+```
+
+## API 参考
+
+### 基础连接功能
+
+#### `initializeAndConnect(...)` ⭐⭐⭐ 最推荐,最简单
+一键完成所有初始化、监听设置、扫描、连接、握手,最简单的方式。
+
+**参数:**
+- `userId`: 用户ID(16字节)
+- `userType`: 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户)
+- `onConnected`: 连接成功回调(已自动完成握手和配对)
+- `onDisconnected`: 断开连接回调(可选)
+- `onDataReceived`: 数据接收回调(可选)
+- `onError`: 错误回调(可选)
+- `scanTimeoutMs`: 扫描超时时间(毫秒),默认10秒
+
+**示例:**
+```kotlin
+bleService.initializeAndConnect(
+    userId = getUserId(),
+    userType = BLEConstants.USER_TYPE_OWNER,
+    onConnected = {
+        // 连接成功,已自动完成握手和配对,可以直接使用
+        showToast("连接成功")
+    },
+    onDisconnected = {
+        showToast("连接已断开")
+    },
+    onDataReceived = { data ->
+        // 处理接收到的数据
+        handleData(data)
+    },
+    onError = { error ->
+        showError(error)
+    }
+)
+```
+
+#### `scanAndConnect(...)` ⭐⭐ 推荐使用
+一键完成扫描+连接+握手。
+
+**参数:**
+- `userId`: 用户ID(16字节)
+- `userType`: 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户)
+- `scanTimeoutMs`: 扫描超时时间(毫秒),默认10秒
+- `onScanning`: 扫描中回调(可选)
+- `onDeviceFound`: 找到设备回调(可选)
+- `onConnected`: 连接成功回调(已自动完成握手和配对)
+- `onError`: 错误回调
+
+**示例:**
+```kotlin
+bleService.scanAndConnect(
+    userId = getUserId(),
+    userType = BLEConstants.USER_TYPE_OWNER,
+    onScanning = { showToast("正在扫描...") },
+    onDeviceFound = { device -> showToast("找到设备: ${device.name}") },
+    onConnected = { 
+        // 连接成功,已自动完成握手和配对,可以直接使用
+        showToast("连接成功")
+    },
+    onError = { error -> showError(error) }
+)
+```
+
+#### `setConnectionListener(...)` ⭐ 推荐使用
+设置连接状态监听器,自动监听连接/断开事件。
+
+**参数:**
+- `onConnected`: 连接成功回调
+- `onDisconnected`: 断开连接回调
+- `onError`: 错误回调
+
+**示例:**
+```kotlin
+bleService.setConnectionListener(
+    onConnected = { 
+        // 连接成功,已自动完成握手和配对
+        showToast("连接成功")
+    },
+    onDisconnected = { 
+        showToast("连接已断开")
+    },
+    onError = { error -> 
+        showError(error)
+    }
+)
+```
+
+#### `startScan(callback: (BLEDevice) -> Unit)`
+开始扫描 BLE 设备(用于分步操作)。
+
+**参数:**
+- `callback`: 扫描结果回调,每次发现设备时调用
+
+**示例:**
+```kotlin
+bleService.startScan { device ->
+    println("发现设备: ${device.name}")
+}
+```
+
+#### `stopScan()`
+停止扫描设备。
+
+#### `connect(device: BLEDevice, userId: ByteArray, userType: Byte, callback: (BLEResponse) -> Unit)`
+连接设备并自动完成握手和配对(用于分步操作)。
+
+**参数:**
+- `device`: 要连接的设备
+- `userId`: 用户ID(16字节)
+- `userType`: 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户)
+- `callback`: 连接结果回调,连接成功表示已完成握手和配对
+
+**注意:** 连接成功即表示已完成握手和配对,业务层无需再调用握手方法。
+
+#### `disconnect()`
+断开连接。
+
+#### `isConnected(): Boolean`
+检查是否已连接。
+
+### 指令发送功能
+
+#### 便捷方法(推荐)
+
+**应用控制:**
+- `setDefense(enabled: Boolean, callback)` - 设防/撤防
+- `powerOn(callback)` - 上电
+- `powerOff(callback)` - 下电
+- `findCar(callback)` - 寻车
+- `unlockSeat(callback)` - 打开座桶锁
+- `unlockHandlebar(callback)` - 打开龙头锁
+- `lockHandlebar(callback)` - 关闭龙头锁
+- `unlockTrunk(callback)` - 打开尾箱锁
+- `lockTrunk(callback)` - 关闭尾箱锁
+
+**系统控制:**
+- `setSensorUnlock(enabled: Boolean, callback)` - 设置感应解锁开关
+- `setAmbientLight(enabled: Boolean, callback)` - 设置氛围灯开关
+- `setAmbientLightColor(r: Int, g: Int, b: Int, callback)` - 设置氛围灯颜色
+- `setAutoPowerOffTime(timeSeconds: Int, callback)` - 设置自动下电时间
+- `setSpeakerVolume(volume: Int, callback)` - 设置蓝牙音箱音量
+
+#### 通用方法(高级用法)
+
+#### `sendAppControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)`
+发送应用控制指令(用于便捷方法未覆盖的场景)。
+
+**常用指令类型:**
+- `AppControlInstruction.SET_DEFENSE` - 设撤防
+- `AppControlInstruction.POWER_ON_OFF` - 上下电
+- `AppControlInstruction.FIND_CAR` - 寻车
+- `AppControlInstruction.SEAT_LOCK` - 座桶锁
+- `AppControlInstruction.HANDLEBAR_LOCK` - 龙头锁
+- `AppControlInstruction.TRUNK_LOCK` - 尾箱锁
+
+#### `sendSystemControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)`
+发送系统控制指令(用于便捷方法未覆盖的场景)。
+
+**常用指令类型:**
+- `SystemControlInstruction.SENSOR_UNLOCK` - 感应解锁开关
+- `SystemControlInstruction.AMBIENT_LIGHT` - 氛围灯开关
+- `SystemControlInstruction.AMBIENT_LIGHT_COLOR` - 氛围灯颜色
+- `SystemControlInstruction.AUTO_POWER_OFF_TIME` - 自动下电时间
+- `SystemControlInstruction.SPEAKER_VOLUME` - 蓝牙音箱音量
+- 更多指令类型请查看 `SystemControlInstruction` 对象
+
+#### `queryVehicleInfo(callback: (BLEResponse) -> Unit)`
+查询车辆信息。
+
+**响应数据:**
+- `response.data`: 车辆信息数据(ByteArray),需要根据协议文档解析
+
+#### `sendCommand(command: BLECommand, callback: (BLEResponse) -> Unit)`
+发送自定义指令(用于系统设置等)。
+
+**示例:**
+```kotlin
+val command = BLECommand(
+    functionCode = BLEConstants.FUNCTION_CODE_SYSTEM_SETTING,
+    instructionType = 0x01.toByte(),
+    applicationData = byteArrayOf(0x01)
+)
+
+bleService.sendCommand(command) { response ->
+    // 处理响应
+}
+```
+
+### 数据接收
+
+#### `setDataReceivedListener(listener: DataCallback)`
+设置数据接收监听器。
+
+**示例:**
+```kotlin
+bleService.setDataReceivedListener(object : DataCallback {
+    override fun onDataReceived(data: ByteArray) {
+        // 处理接收到的数据
+    }
+})
+```
+
+## 常量定义
+
+### 用户类型
+```kotlin
+BLEConstants.USER_TYPE_HIGHEST  // 0x01 - 最高权限
+BLEConstants.USER_TYPE_OWNER    // 0x02 - 车主
+BLEConstants.USER_TYPE_SHARED   // 0x03 - 分享用户
+```
+
+### 功能码
+```kotlin
+BLEConstants.FUNCTION_CODE_HANDSHAKE        // 0x01 - 握手
+BLEConstants.FUNCTION_CODE_APP_CONTROL    // 0x02 - 应用控制
+BLEConstants.FUNCTION_CODE_SYSTEM_CONTROL  // 0x03 - 系统控制
+BLEConstants.FUNCTION_CODE_SYSTEM_QUERY    // 0x04 - 系统查询
+BLEConstants.FUNCTION_CODE_SYSTEM_SETTING  // 0x05 - 系统设置
+```
+
+## 注意事项
+
+1. **单例模式**:`BLEService` 使用单例模式,全局共享同一个连接状态。
+
+2. **自动握手**:连接时传入用户信息,连接成功即表示已完成握手和配对,无需手动调用握手方法。
+
+3. **线程安全**:所有回调都在主线程执行,可以直接更新 UI。
+
+4. **错误处理**:所有 API 都通过 `BLEResponse` 返回结果,需要检查 `response.success` 判断是否成功。
+
+5. **权限要求**:需要在 `AndroidManifest.xml` 中添加蓝牙相关权限:
+   ```xml
+   <uses-permission android:name="android.permission.BLUETOOTH" />
+   <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+   <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
+   <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+   ```
+
+6. **生命周期管理**:建议在 `onDestroy()` 中调用 `disconnect()` 断开连接。
+
+## 架构说明
+
+能力层内部自动处理:
+- ✅ GATT 连接管理
+- ✅ 服务发现
+- ✅ 握手认证(连接时自动完成)
+- ✅ 配对处理(连接时自动完成)
+- ✅ 数据分包和组包
+- ✅ ACK/REX 机制
+- ✅ 超时重试
+- ✅ AES 加密/解密
+- ✅ 协议包构建和解析
+
+业务层只需要:
+- ✅ 调用高级 API
+- ✅ 处理业务逻辑
+- ✅ 更新 UI
+
+## 更多信息
+
+详细的协议说明请参考:`doc/蓝牙协议.md`
+

+ 3 - 3
capability-ble/build.gradle

@@ -21,8 +21,8 @@ android {
 }
 
 dependencies {
-    // 只依赖 base-common(不直接依赖 base-core
-    // base-common 会传递 base-core 的依赖
-    implementation(project(":base-common"))
+    // 直接依赖 base-core(能力层只需要 base-core 的接口和基础能力
+    // base-core 提供接口定义和基础实现(ILog、NetworkManager)
+    implementation(project(":base-core"))
 }
 

+ 164 - 44
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/api/BLEService.kt

@@ -1,10 +1,9 @@
 package com.narutohuo.xindazhou.ble.api
 
-import com.narutohuo.xindazhou.ble.callback.*
+import com.narutohuo.xindazhou.ble.callback.DataCallback
 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服务接口
@@ -29,21 +28,14 @@ interface BLEService {
     fun stopScan()
     
     /**
-     * 连接设备
+     * 连接设备(自动完成握手和配对)
      * 
      * @param device 要连接的设备
-     * @param callback 连接结果回调(统一使用lambda)
+     * @param userId 用户ID(16字节),用于握手认证
+     * @param userType 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户),用于握手认证
+     * @param callback 连接结果回调,连接成功表示已完成握手和配对
      */
-    fun connect(device: BLEDevice, callback: (BLEResponse) -> Unit)
-    
-    /**
-     * 连接设备(兼容旧接口)
-     * 
-     * @param device 要连接的设备
-     * @param callback 连接结果回调
-     */
-    @Deprecated("使用 lambda 回调方式", ReplaceWith("connect(device) { response -> ... }"))
-    fun connect(device: BLEDevice, callback: ConnectCallback)
+    fun connect(device: BLEDevice, userId: ByteArray, userType: Byte, callback: (BLEResponse) -> Unit)
     
     /**
      * 断开连接
@@ -55,50 +47,79 @@ interface BLEService {
      */
     fun isConnected(): Boolean
     
-    // ========== 协议封装功能(高级API,业务模块直接调用) ==========
+    // ========== 高级连接功能(推荐使用) ==========
     
     /**
-     * 握手认证
+     * 初始化并连接(最简单的方式,一键完成所有设置和连接)
      * 
-     * @param userId 用户ID(16字节)
+     * @param userId 用户ID(16字节),用于握手认证
      * @param userType 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户)
-     * @param callback 握手结果回调(统一使用lambda)
+     * @param onConnected 连接成功回调(已自动完成握手和配对)
+     * @param onDisconnected 断开连接回调(可选)
+     * @param onDataReceived 数据接收回调(可选)
+     * @param onError 错误回调(可选)
+     * @param scanTimeoutMs 扫描超时时间(毫秒),默认10秒
      */
-    fun handshake(userId: ByteArray, userType: Byte, callback: (BLEResponse) -> Unit)
+    fun initializeAndConnect(
+        userId: ByteArray,
+        userType: Byte,
+        onConnected: () -> Unit,
+        onDisconnected: (() -> Unit)? = null,
+        onDataReceived: ((ByteArray) -> Unit)? = null,
+        onError: ((String) -> Unit)? = null,
+        scanTimeoutMs: Long = 10000
+    )
     
     /**
-     * 握手认证(兼容旧接口)
+     * 扫描并连接设备(一键完成扫描+连接
      * 
-     * @param userId 用户ID(16字节)
+     * @param userId 用户ID(16字节),用于握手认证
      * @param userType 用户类型(0x01=最高权限, 0x02=车主, 0x03=分享用户)
-     * @param callback 握手结果回调
+     * @param scanTimeoutMs 扫描超时时间(毫秒),默认10秒
+     * @param onScanning 扫描中回调(可选)
+     * @param onDeviceFound 找到设备回调(可选)
+     * @param onConnected 连接成功回调
+     * @param onError 错误回调
      */
-    @Deprecated("使用 lambda 回调方式", ReplaceWith("handshake(userId, userType) { response -> ... }"))
-    fun handshake(userId: ByteArray, userType: Byte, callback: HandshakeCallback)
+    fun scanAndConnect(
+        userId: ByteArray,
+        userType: Byte,
+        scanTimeoutMs: Long = 10000,
+        onScanning: (() -> Unit)? = null,
+        onDeviceFound: ((BLEDevice) -> Unit)? = null,
+        onConnected: () -> Unit,
+        onError: (String) -> Unit
+    )
     
     /**
-     * 发送指令
+     * 设置连接状态监听器(连接/断开时自动回调)
      * 
-     * @param command BLE指令(包含功能码、指令类型、应用数据)
-     * @param callback 指令响应回调(统一使用lambda)
+     * @param onConnected 连接成功回调
+     * @param onDisconnected 断开连接回调
+     * @param onError 错误回调
      */
-    fun sendCommand(command: BLECommand, callback: (BLEResponse) -> Unit)
+    fun setConnectionListener(
+        onConnected: () -> Unit,
+        onDisconnected: () -> Unit,
+        onError: (String) -> Unit
+    )
+    
+    // ========== 协议封装功能(高级API,业务模块直接调用) ==========
     
     /**
-     * 发送指令(兼容旧接口)
+     * 发送指令
      * 
      * @param command BLE指令(包含功能码、指令类型、应用数据)
      * @param callback 指令响应回调
      */
-    @Deprecated("使用 lambda 回调方式", ReplaceWith("sendCommand(command) { response -> ... }"))
-    fun sendCommand(command: BLECommand, callback: CommandCallback)
+    fun sendCommand(command: BLECommand, callback: (BLEResponse) -> Unit)
     
     /**
      * 发送应用控制指令(业务模块常用)
      * 
      * @param instructionType 指令类型(如:设撤防、上下电、寻车等)
      * @param data 指令参数数据
-     * @param callback 响应回调(统一使用lambda)
+     * @param callback 响应回调
      */
     fun sendAppControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)
     
@@ -107,17 +128,125 @@ interface BLEService {
      * 
      * @param instructionType 指令类型(如:感应解锁、氛围灯等)
      * @param data 指令参数数据
-     * @param callback 响应回调(统一使用lambda)
+     * @param callback 响应回调
      */
     fun sendSystemControlCommand(instructionType: Byte, data: ByteArray, callback: (BLEResponse) -> Unit)
     
     /**
      * 查询车辆信息
      * 
-     * @param callback 响应回调(统一使用lambda),返回车辆信息数据
+     * @param callback 响应回调,返回车辆信息数据
      */
     fun queryVehicleInfo(callback: (BLEResponse) -> Unit)
     
+    // ========== 便捷方法(业务层常用操作) ==========
+    
+    /**
+     * 设防/撤防
+     * 
+     * @param enabled true=设防, false=撤防
+     * @param callback 响应回调
+     */
+    fun setDefense(enabled: Boolean, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 上电
+     * 
+     * @param callback 响应回调
+     */
+    fun powerOn(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 下电
+     * 
+     * @param callback 响应回调
+     */
+    fun powerOff(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 寻车
+     * 
+     * @param callback 响应回调
+     */
+    fun findCar(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 打开座桶锁
+     * 
+     * @param callback 响应回调
+     */
+    fun unlockSeat(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 打开龙头锁
+     * 
+     * @param callback 响应回调
+     */
+    fun unlockHandlebar(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 关闭龙头锁
+     * 
+     * @param callback 响应回调
+     */
+    fun lockHandlebar(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 打开尾箱锁
+     * 
+     * @param callback 响应回调
+     */
+    fun unlockTrunk(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 关闭尾箱锁
+     * 
+     * @param callback 响应回调
+     */
+    fun lockTrunk(callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 设置感应解锁开关
+     * 
+     * @param enabled true=开启, false=关闭
+     * @param callback 响应回调
+     */
+    fun setSensorUnlock(enabled: Boolean, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 设置氛围灯开关
+     * 
+     * @param enabled true=开启, false=关闭
+     * @param callback 响应回调
+     */
+    fun setAmbientLight(enabled: Boolean, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 设置氛围灯颜色
+     * 
+     * @param r 红色分量 (0-255)
+     * @param g 绿色分量 (0-255)
+     * @param b 蓝色分量 (0-255)
+     * @param callback 响应回调
+     */
+    fun setAmbientLightColor(r: Int, g: Int, b: Int, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 设置自动下电时间
+     * 
+     * @param timeSeconds 时间(秒),范围:0-60000
+     * @param callback 响应回调
+     */
+    fun setAutoPowerOffTime(timeSeconds: Int, callback: (BLEResponse) -> Unit)
+    
+    /**
+     * 设置蓝牙音箱音量
+     * 
+     * @param volume 音量 (0-100)
+     * @param callback 响应回调
+     */
+    fun setSpeakerVolume(volume: Int, callback: (BLEResponse) -> Unit)
+    
     // ========== 数据接收监听 ==========
     
     /**
@@ -133,17 +262,8 @@ interface BLEService {
      * 发送原始数据(底层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)
+    fun writeRawData(data: ByteArray, callback: (BLEResponse) -> Unit)
 }
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 397 - 743
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/impl/BLEServiceImpl.kt


+ 57 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/BLEEncryptedData.kt

@@ -0,0 +1,57 @@
+package com.narutohuo.xindazhou.ble.model
+
+/**
+ * 数据加密区内容
+ * 
+ * 按照协议文档,数据加密区包含:
+ * - 时间戳(4字节)
+ * - 功能码(1字节)
+ * - 指令类型(1字节)
+ * - 应用数据(N字节)
+ */
+data class BLEEncryptedData(
+    /**
+     * 时间戳(秒级)
+     */
+    val timestamp: Long,
+    
+    /**
+     * 功能码
+     * 0x01=握手, 0x02=应用控制, 0x03=系统控制, 0x04=系统查询, 0x05=系统设置, 0x06=MTU查询
+     */
+    val functionCode: Byte,
+    
+    /**
+     * 指令类型
+     * 根据功能码不同,指令类型含义不同
+     */
+    val instructionType: Byte,
+    
+    /**
+     * 应用数据
+     */
+    val applicationData: ByteArray
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as BLEEncryptedData
+
+        if (timestamp != other.timestamp) return false
+        if (functionCode != other.functionCode) return false
+        if (instructionType != other.instructionType) return false
+        if (!applicationData.contentEquals(other.applicationData)) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = timestamp.hashCode()
+        result = 31 * result + functionCode
+        result = 31 * result + instructionType
+        result = 31 * result + applicationData.contentHashCode()
+        return result
+    }
+}
+

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

@@ -1,85 +0,0 @@
-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
-)
-

+ 110 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/Command.kt

@@ -0,0 +1,110 @@
+package com.narutohuo.xindazhou.ble.model
+
+import kotlin.experimental.xor
+
+/**
+ * 指令协议数据类
+ * 
+ * 按照协议文档"数据下行"结构定义(不包含包头包尾,因为分包协议会处理)
+ */
+data class Command(
+    /**
+     * 地址(1字节)
+     * APP地址为0x0F,仪表地址为0x0A,中控地址为0x05
+     */
+    val address: Byte,
+    
+    /**
+     * 协议版本(1字节)
+     * 初始v1.0 0x01
+     */
+    val protocolVersion: Byte,
+    
+    /**
+     * 时区(1字节)
+     * 单位小时
+     */
+    val timezone: Byte,
+    
+    /**
+     * 加密标志(1字节)
+     * 0x00=不加密,0x01=加密
+     */
+    val encryptionFlag: Byte,
+    
+    /**
+     * 操作系统(1字节)
+     * Android:0x01, iOS:0x02
+     */
+    val operatingSystem: Byte,
+    
+    /**
+     * 数据长度(2字节,无符号短整型)
+     * 数据加密区长度
+     */
+    val dataLength: UShort,
+    
+    /**
+     * 数据区(dataLength 大小的字节数组)
+     * 存放加密数据(时间戳+功能码+指令类型+应用数据)
+     */
+    val data: ByteArray,
+    
+    /**
+     * 校验和(1字节)
+     * 异或校验,从地址到数据区结束
+     */
+    val checksum: Byte
+) {
+    /**
+     * 计算校验和(按字节异或)
+     */
+    fun computeChecksum(): Byte {
+        var sum: Byte = 0
+        sum = sum xor address
+        sum = sum xor protocolVersion
+        sum = sum xor timezone
+        sum = sum xor encryptionFlag
+        sum = sum xor operatingSystem
+        sum = sum xor (dataLength.toInt() and 0xFF).toByte()
+        sum = sum xor ((dataLength.toInt() shr 8) and 0xFF).toByte()
+        data.forEach { sum = sum xor it }
+        return sum
+    }
+    
+    /**
+     * 校验当前对象的 checksum 是否正确
+     */
+    fun isValid(): Boolean = checksum == computeChecksum()
+    
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as Command
+
+        if (address != other.address) return false
+        if (protocolVersion != other.protocolVersion) return false
+        if (timezone != other.timezone) return false
+        if (encryptionFlag != other.encryptionFlag) return false
+        if (operatingSystem != other.operatingSystem) return false
+        if (dataLength != other.dataLength) return false
+        if (!data.contentEquals(other.data)) return false
+        if (checksum != other.checksum) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = address.toInt()
+        result = 31 * result + protocolVersion.toInt()
+        result = 31 * result + timezone.toInt()
+        result = 31 * result + encryptionFlag.toInt()
+        result = 31 * result + operatingSystem.toInt()
+        result = 31 * result + dataLength.hashCode()
+        result = 31 * result + data.contentHashCode()
+        result = 31 * result + checksum.toInt()
+        return result
+    }
+}
+

+ 41 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/FragmentBuffer.kt

@@ -0,0 +1,41 @@
+package com.narutohuo.xindazhou.ble.model
+
+/**
+ * 分包缓冲区
+ * 
+ * 用于保存同一业务ID下的分片信息,用于组包
+ */
+data class FragmentBuffer(
+    /**
+     * 总包数
+     */
+    val totalPackets: Int,
+    
+    /**
+     * 已收到的分片
+     * key: 包序号(从0开始)
+     * value: 数据片段
+     */
+    val received: MutableMap<Int, ByteArray> = mutableMapOf()
+) {
+    /**
+     * 是否已经收到全部分片
+     */
+    fun isComplete(): Boolean = received.size == totalPackets
+    
+    /**
+     * 按序号把数据拼接成完整指令
+     */
+    fun assemble(): ByteArray {
+        val sorted = received.toSortedMap()
+        val totalLen = sorted.values.sumOf { it.size }
+        val result = ByteArray(totalLen)
+        var pos = 0
+        for (buf in sorted.values) {
+            System.arraycopy(buf, 0, result, pos, buf.size)
+            pos += buf.size
+        }
+        return result
+    }
+}
+

+ 179 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/model/Packet.kt

@@ -0,0 +1,179 @@
+package com.narutohuo.xindazhou.ble.model
+
+import kotlin.experimental.xor
+
+/**
+ * 分包协议数据包
+ * 
+ * 按照协议文档第3节"分包协议"定义
+ */
+data class Packet(
+    /**
+     * 包头(固定0x0A)
+     */
+    val header: Byte,
+    
+    /**
+     * 业务ID(4字节)
+     * 最后一个字节表示业务类型:0x01=请求,0x02=响应
+     */
+    val businessId: UInt,
+    
+    /**
+     * 总包数(2字节)
+     */
+    val totalPackets: UShort,
+    
+    /**
+     * 包序号(2字节,从0开始)
+     */
+    val packetSeq: UShort,
+    
+    /**
+     * 数据长度(2字节)
+     */
+    val dataLength: UShort,
+    
+    /**
+     * 数据区
+     */
+    val data: ByteArray,
+    
+    /**
+     * 应答状态(1字节)
+     * 0x01=ACK,0x02=REX
+     */
+    val responseStatus: Byte,
+    
+    /**
+     * 包校验(1字节,异或校验)
+     */
+    val checksum: Byte,
+    
+    /**
+     * 包尾(固定0x0D)
+     */
+    val tail: Byte
+) {
+    /**
+     * 计算校验和
+     */
+    fun computeChecksum(): Byte {
+        var sum: Byte = 0
+        // businessId 拆成 4 个字节参与校验
+        sum = sum xor (businessId.toInt() and 0xFF).toByte()
+        sum = sum xor ((businessId.toInt() shr 8) and 0xFF).toByte()
+        sum = sum xor ((businessId.toInt() shr 16) and 0xFF).toByte()
+        sum = sum xor ((businessId.toInt() shr 24) and 0xFF).toByte()
+        // totalPackets、packetSeq、dataLength 各 2 字节
+        sum = sum xor (totalPackets.toInt() and 0xFF).toByte()
+        sum = sum xor ((totalPackets.toInt() shr 8) and 0xFF).toByte()
+        sum = sum xor (packetSeq.toInt() and 0xFF).toByte()
+        sum = sum xor ((packetSeq.toInt() shr 8) and 0xFF).toByte()
+        sum = sum xor (dataLength.toInt() and 0xFF).toByte()
+        sum = sum xor ((dataLength.toInt() shr 8) and 0xFF).toByte()
+        // data 区
+        data.forEach { sum = sum xor it }
+        // responseStatus
+        sum = sum xor responseStatus
+        return sum
+    }
+    
+    /**
+     * 校验当前对象的 checksum 是否正确
+     */
+    fun isValid(): Boolean = checksum == computeChecksum()
+    
+    /**
+     * 获取消息类型(业务ID的最后一位)
+     * 0x01=请求,0x02=响应
+     */
+    fun messageType(): Byte {
+        return (businessId and 0xFFu).toByte()
+    }
+    
+    /**
+     * 根据收到的包生成确认响应报文(ACK)
+     */
+    fun buildAckResponse(): ByteArray {
+        // 业务ID最低字节改为0x02(响应)
+        val responseBusinessId = (this.businessId and 0xFFFFFF00u) or 0x02u
+        
+        val totalPackets = 0x0001.toUShort()
+        val dataLength = 0x0000.toUShort()
+        val responseStatus = 0x01.toByte() // ACK
+        val tail = 0x0D.toByte()
+        
+        // 响应报文长度 = 1(header) + 4(businessId) + 2(total) + 2(seq) + 2(len) + 1(rsp) + 1(chk) + 1(tail) = 14
+        val result = ByteArray(14)
+        
+        var pos = 0
+        result[pos++] = 0x0A.toByte() // header
+        
+        // businessId(4字节,大端序)
+        result[pos++] = ((responseBusinessId.toInt() shr 24) and 0xFF).toByte()
+        result[pos++] = ((responseBusinessId.toInt() shr 16) and 0xFF).toByte()
+        result[pos++] = ((responseBusinessId.toInt() shr 8) and 0xFF).toByte()
+        result[pos++] = (responseBusinessId.toInt() and 0xFF).toByte()
+        
+        // totalPackets(2字节,大端序)
+        result[pos++] = ((totalPackets.toInt() shr 8) and 0xFF).toByte()
+        result[pos++] = (totalPackets.toInt() and 0xFF).toByte()
+        
+        // packetSeq(2字节,大端序)- 保持请求的seq
+        result[pos++] = ((this.packetSeq.toInt() shr 8) and 0xFF).toByte()
+        result[pos++] = (this.packetSeq.toInt() and 0xFF).toByte()
+        
+        // dataLength(2字节,大端序)
+        result[pos++] = ((dataLength.toInt() shr 8) and 0xFF).toByte()
+        result[pos++] = (dataLength.toInt() and 0xFF).toByte()
+        
+        // responseStatus
+        result[pos++] = responseStatus
+        
+        // checksum(异或校验,从businessId开始到responseStatus)
+        var checksum: Byte = 0x00
+        for (i in 1 until pos) {
+            checksum = checksum xor result[i]
+        }
+        result[pos++] = checksum
+        
+        // 包尾
+        result[pos] = tail
+        
+        return result
+    }
+    
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as Packet
+
+        if (header != other.header) return false
+        if (businessId != other.businessId) return false
+        if (totalPackets != other.totalPackets) return false
+        if (packetSeq != other.packetSeq) return false
+        if (dataLength != other.dataLength) return false
+        if (!data.contentEquals(other.data)) return false
+        if (responseStatus != other.responseStatus) return false
+        if (checksum != other.checksum) return false
+        if (tail != other.tail) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = header.toInt()
+        result = 31 * result + businessId.hashCode()
+        result = 31 * result + totalPackets.hashCode()
+        result = 31 * result + packetSeq.hashCode()
+        result = 31 * result + dataLength.hashCode()
+        result = 31 * result + data.contentHashCode()
+        result = 31 * result + responseStatus.toInt()
+        result = 31 * result + checksum.toInt()
+        result = 31 * result + tail.toInt()
+        return result
+    }
+}
+

+ 143 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEExtension.kt

@@ -0,0 +1,143 @@
+package com.narutohuo.xindazhou.ble.util
+
+import com.narutohuo.xindazhou.ble.model.Command
+import com.narutohuo.xindazhou.ble.model.Packet
+
+/**
+ * ByteArray 扩展函数
+ */
+
+/**
+ * 将 ByteArray 按分包协议解析为 Packet 对象
+ */
+fun ByteArray.parsePacket(): Packet {
+    require(this.size >= 13) { "分包字节数组长度不足,最少需要 13 字节(不含 data)" }
+    
+    var offset = 0
+    val header = this[offset++]
+    
+    // businessId 为 4 字节(大端序)
+    val businessId = ((this[offset].toLong() and 0xFF) shl 24) or
+            ((this[offset + 1].toLong() and 0xFF) shl 16) or
+            ((this[offset + 2].toLong() and 0xFF) shl 8) or
+            (this[offset + 3].toLong() and 0xFF)
+    offset += 4
+    
+    // totalPackets、packetSeq、dataLength 均为 2 字节(大端序)
+    val totalPackets = ((this[offset].toInt() and 0xFF) shl 8 or
+            (this[offset + 1].toInt() and 0xFF)).toUShort()
+    offset += 2
+    
+    val packetSeq = ((this[offset].toInt() and 0xFF) shl 8 or
+            (this[offset + 1].toInt() and 0xFF)).toUShort()
+    offset += 2
+    
+    val dataLength = ((this[offset].toInt() and 0xFF) shl 8 or
+            (this[offset + 1].toInt() and 0xFF)).toUShort()
+    offset += 2
+    
+    // 检查 data 区长度是否匹配
+    require(this.size >= offset + dataLength.toInt() + 3) {
+        "实际字节数组长度不足 dataLength(${dataLength}) + responseStatus + checksum + tail"
+    }
+    
+    val data = this.copyOfRange(offset, offset + dataLength.toInt())
+    offset += dataLength.toInt()
+    
+    val responseStatus = this[offset++]
+    val checksum = this[offset++]
+    val tail = this[offset]
+    
+    return Packet(
+        header = header,
+        businessId = businessId.toUInt(),
+        totalPackets = totalPackets,
+        packetSeq = packetSeq,
+        dataLength = dataLength,
+        data = data,
+        responseStatus = responseStatus,
+        checksum = checksum,
+        tail = tail
+    )
+}
+
+/**
+ * 将 ByteArray 按指令协议解析为 Command 对象
+ */
+fun ByteArray.parseCommand(): Command {
+    require(this.size >= 7) { "指令字节数组长度不足,最少需要 7 字节(不含 data)" }
+    
+    var offset = 0
+    val address = this[offset++]
+    val protocolVersion = this[offset++]
+    val timezone = this[offset++]
+    val encryptionFlag = this[offset++]
+    val operatingSystem = this[offset++]
+    
+    // dataLength 为 2 字节(大端序)
+    val dataLength = ((this[offset].toInt() and 0xFF) shl 8 or
+            (this[offset + 1].toInt() and 0xFF)).toUShort()
+    offset += 2
+    
+    // 检查 data 区长度是否匹配
+    require(this.size >= offset + dataLength.toInt() + 1) {
+        "实际字节数组长度不足 dataLength(${dataLength}) + checksum"
+    }
+    
+    val data = this.copyOfRange(offset, offset + dataLength.toInt())
+    offset += dataLength.toInt()
+    
+    val checksum = this[offset]
+    
+    return Command(
+        address = address,
+        protocolVersion = protocolVersion,
+        timezone = timezone,
+        encryptionFlag = encryptionFlag,
+        operatingSystem = operatingSystem,
+        dataLength = dataLength,
+        data = data,
+        checksum = checksum
+    )
+}
+
+/**
+ * ByteArray 转十六进制字符串
+ */
+@OptIn(ExperimentalStdlibApi::class)
+fun ByteArray.toHexString(): String {
+    return this.joinToString("") { "%02X".format(it) }
+}
+
+/**
+ * 十六进制字符串转 ByteArray
+ */
+@OptIn(ExperimentalStdlibApi::class)
+fun String.hexToByteArray(): ByteArray {
+    require(this.length % 2 == 0) { "Hex string length must be even" }
+    val result = ByteArray(this.length / 2)
+    for (i in result.indices) {
+        val idx = i * 2
+        result[i] = ((hexCharToInt(this[idx]) shl 4) + hexCharToInt(this[idx + 1])).toByte()
+    }
+    return result
+}
+
+private fun hexCharToInt(c: Char): Int = when (c) {
+    in '0'..'9' -> c - '0'
+    in 'a'..'f' -> c - 'a' + 10
+    in 'A'..'F' -> c - 'A' + 10
+    else -> throw IllegalArgumentException("Invalid hex char: $c")
+}
+
+/**
+ * Int 转偶数位十六进制字符串
+ */
+fun Int.toEvenHex(): String {
+    var hex = Integer.toHexString(this)
+    if (hex.length % 2 != 0) {
+        hex = "0" + hex
+    }
+    return hex
+}
+

+ 112 - 31
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketBuilder.kt

@@ -4,24 +4,31 @@ 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
+import kotlin.experimental.xor
 
 /**
  * BLE数据包构建器
  * 
  * 负责构建符合新大洲本田蓝牙协议的数据包
- * 封装数据包结构、加密、校验等细节
+ * 按照协议文档"数据下行"结构构建(不包含包头包尾,因为分包协议会处理)
+ * 
+ * 数据包结构:
+ * 地址 + 协议版本 + 时区 + 加密标志 + 操作系统 + 数据长度 + 数据加密区 + 校验
+ * 
+ * 数据加密区结构(加密前):
+ * 时间戳(4字节)+ 功能码(1字节)+ 指令类型(1字节)+ 应用数据
  */
 class BLEPacketBuilder {
     
     /**
-     * 构建数据包
+     * 构建完整指令数据包(不包含包头包尾)
      * 
      * @param command BLE指令
-     * @param encryptKey 加密密钥(16字节)
-     * @return 完整的数据包(ByteArray)
+     * @param encryptKey 加密密钥(16字节),如果为null则不加密
+     * @return 完整的数据包(ByteArray),不包含包头包尾
      */
-    fun buildPacket(command: BLECommand, encryptKey: ByteArray): ByteArray {
-        // 1. 构建数据加密区
+    fun buildPacket(command: BLECommand, encryptKey: ByteArray? = null): ByteArray {
+        // 1. 构建数据加密区(时间戳+功能码+指令类型+应用数据)
         val timestamp = System.currentTimeMillis() / 1000 // 秒级时间戳
         val encryptedData = BLEEncryptedData(
             timestamp = timestamp,
@@ -33,17 +40,18 @@ class BLEPacketBuilder {
         // 2. 序列化数据加密区
         val encryptedDataBytes = serializeEncryptedData(encryptedData)
         
-        // 3. 加密数据
-        val encryptedBytes = BLECrypto.encrypt(encryptedDataBytes, encryptKey)
+        // 3. 加密数据(如果提供了密钥)
+        val finalDataBytes = if (encryptKey != null) {
+            BLECrypto.encrypt(encryptedDataBytes, encryptKey)
+        } else {
+            encryptedDataBytes
+        }
         
-        // 4. 构建完整数据包
+        // 4. 构建完整数据包(不包含包头包尾)
         val packet = mutableListOf<Byte>()
         
-        // 包头
-        packet.add(BLEConstants.PACKET_HEAD)
-        
-        // 地址
-        packet.add(BLEConstants.ADDRESS_APP)
+        // 地址(默认中控地址)
+        packet.add(BLEConstants.ADDRESS_CONTROLLER)
         
         // 协议版本
         packet.add(BLEConstants.PROTOCOL_VERSION)
@@ -53,41 +61,114 @@ class BLEPacketBuilder {
         packet.add(timezone)
         
         // 加密标志
-        packet.add(BLEConstants.ENCRYPT_FLAG_ENCRYPTED)
+        packet.add(if (encryptKey != null) BLEConstants.ENCRYPT_FLAG_ENCRYPTED else BLEConstants.ENCRYPT_FLAG_NONE)
         
         // 操作系统
         packet.add(BLEConstants.OS_ANDROID)
         
-        // 数据长度(2字节,小端序)
-        val dataLength = encryptedBytes.size
+        // 数据长度(2字节,大端序)
+        val dataLength = finalDataBytes.size
+        packet.add((dataLength shr 8).toByte())
         packet.add((dataLength and 0xFF).toByte())
-        packet.add(((dataLength shr 8) and 0xFF).toByte())
         
         // 数据加密区
-        packet.addAll(encryptedBytes.toList())
+        packet.addAll(finalDataBytes.toList())
         
-        // 校验(异或校验,包头至校验前一位
+        // 校验(异或校验,从地址到数据区结束
         val checksum = calculateChecksum(packet)
         packet.add(checksum)
         
-        // 包尾
-        packet.add(BLEConstants.PACKET_TAIL)
+        return packet.toByteArray()
+    }
+    
+    /**
+     * 构建完整指令数据包(包含包头包尾)
+     * 
+     * @param command BLE指令
+     * @param encryptKey 加密密钥(16字节),如果为null则不加密
+     * @return 完整的数据包(ByteArray),包含包头包尾
+     */
+    fun buildFullPacket(command: BLECommand, encryptKey: ByteArray? = null): ByteArray {
+        val packet = buildPacket(command, encryptKey)
+        
+        // 添加包头和包尾
+        val fullPacket = mutableListOf<Byte>()
+        fullPacket.add(BLEConstants.PACKET_HEAD)  // 包头
+        fullPacket.addAll(packet.toList())
+        fullPacket.add(BLEConstants.PACKET_TAIL)  // 包尾
+        
+        return fullPacket.toByteArray()
+    }
+    
+    /**
+     * 构建原始数据包(直接使用传入的数据,不构建数据加密区)
+     * 
+     * 用于握手等JSON协议场景
+     * 
+     * @param rawData 原始数据(JSON字节等)
+     * @param address 地址(默认0x05中控地址)
+     * @param encryptKey 加密密钥(16字节),如果为null则不加密
+     * @return 完整的数据包(ByteArray),不包含包头包尾
+     */
+    fun buildRawPacket(
+        rawData: ByteArray,
+        address: Byte = BLEConstants.ADDRESS_CONTROLLER,
+        encryptKey: ByteArray? = null
+    ): ByteArray {
+        // 加密数据(如果提供了密钥)
+        val finalDataBytes = if (encryptKey != null) {
+            BLECrypto.encrypt(rawData, encryptKey)
+        } else {
+            rawData
+        }
+        
+        // 构建数据包
+        val packet = mutableListOf<Byte>()
+        
+        // 地址
+        packet.add(address)
+        
+        // 协议版本
+        packet.add(BLEConstants.PROTOCOL_VERSION)
+        
+        // 时区
+        val timezone = (TimeZone.getDefault().rawOffset / (1000 * 60 * 60)).toByte()
+        packet.add(timezone)
+        
+        // 加密标志
+        packet.add(if (encryptKey != null) BLEConstants.ENCRYPT_FLAG_ENCRYPTED else BLEConstants.ENCRYPT_FLAG_NONE)
+        
+        // 操作系统
+        packet.add(BLEConstants.OS_ANDROID)
+        
+        // 数据长度(2字节,大端序)
+        val dataLength = finalDataBytes.size
+        packet.add((dataLength shr 8).toByte())
+        packet.add((dataLength and 0xFF).toByte())
+        
+        // 数据区
+        packet.addAll(finalDataBytes.toList())
+        
+        // 校验(异或校验,从地址到数据区结束)
+        val checksum = calculateChecksum(packet)
+        packet.add(checksum)
         
         return packet.toByteArray()
     }
     
     /**
      * 序列化数据加密区
+     * 按照协议:时间戳(4字节)+ 功能码(1字节)+ 指令类型(1字节)+ 应用数据
      */
     private fun serializeEncryptedData(data: BLEEncryptedData): ByteArray {
         val result = mutableListOf<Byte>()
         
-        // 时间戳(4字节,小端序)
+        // 时间戳(4字节,端序)
         val timestamp = data.timestamp.toInt()
-        result.add((timestamp and 0xFF).toByte())
-        result.add(((timestamp shr 8) and 0xFF).toByte())
+        result.add((timestamp shr 24).toByte())
         result.add(((timestamp shr 16) and 0xFF).toByte())
-        result.add(((timestamp shr 24) and 0xFF).toByte())
+        result.add(((timestamp shr 8) and 0xFF).toByte())
+        result.add((timestamp and 0xFF).toByte())
         
         // 功能码
         result.add(data.functionCode)
@@ -103,14 +184,14 @@ class BLEPacketBuilder {
     
     /**
      * 计算异或校验
+     * 从地址开始(跳过包头),到校验位前一位
      */
     private fun calculateChecksum(packet: List<Byte>): Byte {
-        var checksum = 0x00
-        // 从地址开始(跳过包头),到校验位前一位
-        for (i in 1 until packet.size) {
-            checksum = checksum xor packet[i].toInt()
+        var checksum: Byte = 0x00
+        for (i in packet.indices) {
+            checksum = checksum.xor(packet[i])
         }
-        return checksum.toByte()
+        return checksum
     }
 }
 

+ 101 - 31
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketParser.kt

@@ -2,6 +2,8 @@ package com.narutohuo.xindazhou.ble.util
 
 import com.narutohuo.xindazhou.ble.config.BLEConstants
 import com.narutohuo.xindazhou.ble.model.BLEEncryptedData
+import com.narutohuo.xindazhou.ble.model.Command
+import kotlin.experimental.xor
 
 /**
  * BLE数据包解析器
@@ -12,13 +14,13 @@ import com.narutohuo.xindazhou.ble.model.BLEEncryptedData
 class BLEPacketParser {
     
     /**
-     * 解析数据包
+     * 解析完整数据包(包含包头包尾)
      * 
-     * @param packet 接收到的数据包
-     * @param encryptKey 解密密钥(16字节)
-     * @return 解析后的数据加密区内容
+     * @param packet 接收到的数据包(包含包头包尾)
+     * @param encryptKey 解密密钥(16字节),如果为null则不解密
+     * @return 解析后的Command对象,如果解析失败返回null
      */
-    fun parsePacket(packet: ByteArray, encryptKey: ByteArray): BLEEncryptedData? {
+    fun parseFullPacket(packet: ByteArray, encryptKey: ByteArray? = null): Command? {
         // 1. 校验包头包尾
         if (packet.isEmpty() || packet[0] != BLEConstants.PACKET_HEAD) {
             return null
@@ -27,46 +29,113 @@ class BLEPacketParser {
             return null
         }
         
-        // 2. 提取数据长度
-        val dataLength = (packet[6].toInt() and 0xFF) or 
-                        ((packet[7].toInt() and 0xFF) shl 8)
+        // 2. 提取数据包内容(去掉包头包尾)
+        val packetContent = packet.sliceArray(1 until packet.size - 1)
         
-        // 3. 提取加密数据
-        val encryptedData = packet.sliceArray(8 until 8 + dataLength)
+        // 3. 解析数据包内容
+        return parsePacket(packetContent, encryptKey)
+    }
+    
+    /**
+     * 解析数据包(不包含包头包尾)
+     * 
+     * @param packet 接收到的数据包(不包含包头包尾)
+     * @param encryptKey 解密密钥(16字节),如果为null则不解密
+     * @return 解析后的Command对象,如果解析失败返回null
+     */
+    fun parsePacket(packet: ByteArray, encryptKey: ByteArray? = null): Command? {
+        if (packet.size < 7) {
+            return null
+        }
+        
+        var offset = 0
+        
+        // 地址
+        val address = packet[offset++]
+        
+        // 协议版本
+        val protocolVersion = packet[offset++]
+        
+        // 时区
+        val timezone = packet[offset++]
+        
+        // 加密标志
+        val encryptionFlag = packet[offset++]
         
-        // 4. 校验校验位
-        val checksum = packet[packet.size - 2]
+        // 操作系统
+        val operatingSystem = packet[offset++]
+        
+        // 数据长度(2字节,大端序)
+        val dataLength = ((packet[offset].toInt() and 0xFF) shl 8) or
+                        (packet[offset + 1].toInt() and 0xFF)
+        offset += 2
+        
+        // 检查数据长度
+        if (packet.size < offset + dataLength + 1) {
+            return null
+        }
+        
+        // 提取加密数据
+        val encryptedData = packet.sliceArray(offset until offset + dataLength)
+        offset += dataLength
+        
+        // 校验位
+        val checksum = packet[offset]
+        
+        // 校验校验位
         if (!verifyChecksum(packet, checksum)) {
             return null
         }
         
-        // 5. 解密数据
-        val decryptedData = BLECrypto.decrypt(encryptedData, encryptKey)
+        // 解密数据(如果需要)
+        val decryptedData = if (encryptKey != null && encryptionFlag == BLEConstants.ENCRYPT_FLAG_ENCRYPTED) {
+            try {
+                BLECrypto.decrypt(encryptedData, encryptKey)
+            } catch (e: Exception) {
+                return null
+            }
+        } else {
+            encryptedData
+        }
         
-        // 6. 解析数据加密区
-        return parseEncryptedData(decryptedData)
+        return Command(
+            address = address,
+            protocolVersion = protocolVersion,
+            timezone = timezone,
+            encryptionFlag = encryptionFlag,
+            operatingSystem = operatingSystem,
+            dataLength = dataLength.toUShort(),
+            data = decryptedData,
+            checksum = checksum
+        )
     }
     
     /**
      * 解析数据加密区
+     * 按照协议:时间戳(4字节)+ 功能码(1字节)+ 指令类型(1字节)+ 应用数据
+     * 
+     * @param data 解密后的数据加密区
+     * @return 解析后的BLEEncryptedData对象
      */
-    private fun parseEncryptedData(data: ByteArray): BLEEncryptedData {
+    fun parseEncryptedData(data: ByteArray): BLEEncryptedData? {
+        if (data.size < 6) {
+            return null
+        }
+        
         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)
+        // 时间戳(4字节,端序)
+        val timestamp = ((data[offset].toInt() and 0xFF) shl 24) or
+                       ((data[offset + 1].toInt() and 0xFF) shl 16) or
+                       ((data[offset + 2].toInt() and 0xFF) shl 8) or
+                       (data[offset + 3].toInt() and 0xFF)
         offset += 4
         
         // 功能码
-        val functionCode = data[offset]
-        offset += 1
+        val functionCode = data[offset++]
         
         // 指令类型
-        val instructionType = data[offset]
-        offset += 1
+        val instructionType = data[offset++]
         
         // 应用数据
         val applicationData = data.sliceArray(offset until data.size)
@@ -81,14 +150,15 @@ class BLEPacketParser {
     
     /**
      * 校验校验位
+     * 从地址开始(跳过包头),到校验位前一位
      */
     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()
+        var checksum: Byte = 0x00
+        // 从地址开始,到校验位前一位
+        for (i in 0 until packet.size - 1) {
+            checksum = checksum.xor(packet[i])
         }
-        return checksum.toByte() == expectedChecksum
+        return checksum == expectedChecksum
     }
 }
 

+ 127 - 70
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BLEPacketSplitter.kt

@@ -1,36 +1,92 @@
 package com.narutohuo.xindazhou.ble.util
 
+import java.util.Arrays
+import kotlin.experimental.xor
+
 /**
  * BLE分包处理器
  * 
  * 处理数据包的分包和组包
- * 根据新大洲本田蓝牙协议文档的分包协议
+ * 根据新大洲本田蓝牙协议文档的分包协议(第3节)
  */
-class BLEPacketSplitter {
+class BLEPacketSplitter(
+    /**
+     * 包头(默认0x0A)
+     */
+    private val header: Byte = 0x0A.toByte(),
+    
+    /**
+     * 包尾(默认0x0D)
+     */
+    private val footer: Byte = 0x0D.toByte(),
     
     /**
-     * 分包数据
+     * 单个包最大业务数据长度(不含协议头尾)
+     * 建议 ≤ 20(符合 BLE 单次写入限制)
+     */
+    private val maxPayloadPerPacket: Int = 20
+) {
+    
+    /**
+     * 生成分包列表
      * 
-     * @param data 原始数据
-     * @param mtu MTU大小(最大传输单元)
-     * @param businessId 业务ID(4字节)
-     * @return 分包后的数据包列表
+     * @param rawData 待发送的完整指令数据(不包含分包协议头尾)
+     * @param businessId 业务标识(4字节),最后一个字节会在调用时被设置为0x01(请求)或0x02(响应
+     * @param isRequest true → 请求(业务ID 低两位 01),false → 响应(业务ID 低两位 02
+     * @return List<ByteArray> 每个元素即为一个完整的 BLE 分包
      */
-    fun splitPacket(data: ByteArray, mtu: Int, businessId: Int): List<ByteArray> {
+    fun split(
+        rawData: ByteArray,
+        businessId: ByteArray,
+        isRequest: Boolean = true
+    ): List<ByteArray> {
+        // 业务ID 低两位:01 请求,02 响应
+        val idLow: Byte = if (isRequest) 0x01 else 0x02
+        
+        // 复制 businessId 并设置最后一位
+        val fullBusinessId = businessId.copyOf()
+        if (fullBusinessId.size >= 4) {
+            fullBusinessId[3] = idLow
+        }
+        
+        // 计算总包数
+        val totalPackets = (rawData.size + maxPayloadPerPacket - 1) / maxPayloadPerPacket
+        require(totalPackets <= 255) { "单次发送的包数不能超过 255(单字节表示)" }
+        
         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)
+        for (seq in 0 until totalPackets) {
+            // 取出本包的数据片段
+            val start = seq * maxPayloadPerPacket
+            val end = minOf(start + maxPayloadPerPacket, rawData.size)
+            val payload = rawData.sliceArray(start until end)
             
-            val packet = buildSplitPacket(
-                businessId = businessId,
-                totalPackets = totalPackets,
-                packetIndex = i,
-                data = packetData
-            )
+            // 构造单包
+            // 包体长度 = 1(header) + 4(businessId) + 2(total) + 2(seq) + 2(len) + N(data) + 1(responseStatus) + 1(checksum) + 1(footer)
+            val packet = ByteArray(14 + payload.size)
+            var idx = 0
+            packet[idx++] = header                     // 包头
+            packet[idx++] = fullBusinessId[0]          // 业务ID
+            packet[idx++] = fullBusinessId[1]          // 业务ID
+            packet[idx++] = fullBusinessId[2]          // 业务ID
+            packet[idx++] = fullBusinessId[3]          // 业务ID
+            // 总包数(大端序)
+            packet[idx++] = (totalPackets shr 8).toByte()
+            packet[idx++] = totalPackets.toByte()
+            // 包序号(大端序)
+            packet[idx++] = (seq shr 8).toByte()
+            packet[idx++] = seq.toByte()
+            // 数据长度(大端序)
+            packet[idx++] = (payload.size shr 8).toByte()
+            packet[idx++] = payload.size.toByte()
+            // 数据区
+            payload.copyInto(packet, destinationOffset = idx)
+            idx += payload.size
+            packet[idx++] = 0x00.toByte()             // 应答状态(发送时设为0,接收时填充)
+            // 包校验(异或所有前面的字节,不包含包头)
+            packet[idx++] = calculateXorChecksum(packet, 1, idx)
+            // 包尾
+            packet[idx] = footer
             
             packets.add(packet)
         }
@@ -39,72 +95,73 @@ class BLEPacketSplitter {
     }
     
     /**
-     * 构建分包数据包
+     * 生成仅携带 ACK/REX 状态的响应包
+     * 
+     * @param requestSeq 请求报文的序号(从收到的报文中解析)
+     * @param businessId 原业务标识(4 字节),低两位会被强制置为 0x02(响应)
+     * @param value 收到的请求包数据(用于校验)
+     * @return 完整的 BLE 响应报文
      */
-    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())
+    fun createResponsePacket(requestSeq: Int, businessId: ByteArray, value: ByteArray): ByteArray {
+        // 业务 ID 低两位改为 0x02(响应)
+        val responseBusinessId = businessId.copyOf()
+        if (responseBusinessId.size >= 4) {
+            responseBusinessId[3] = 0x02
+        }
+        val totalPackets = 1               // 只发一包
+        val payloadLen = 0                 // 无业务数据
         
-        // 总包数(2字节,小端序)
-        packet.add((totalPackets and 0xFF).toByte())
-        packet.add(((totalPackets shr 8) and 0xFF).toByte())
+        // 包体长度 = header(1) + businessId(4) + total(2) + seq(2) + len(2) + status(1) + checksum(1) + footer(1) = 14
+        val packet = ByteArray(14)
+        var idx = 0
+        packet[idx++] = header
+        packet[idx++] = responseBusinessId[0]
+        packet[idx++] = responseBusinessId[1]
+        packet[idx++] = responseBusinessId[2]
+        packet[idx++] = responseBusinessId[3]
         
-        // 包序号(2字节,小端序)
-        packet.add((packetIndex and 0xFF).toByte())
-        packet.add(((packetIndex shr 8) and 0xFF).toByte())
+        // total‑packets(大端序)
+        packet[idx++] = (totalPackets shr 8).toByte()
+        packet[idx++] = totalPackets.toByte()
         
-        // 数据长度(2字节,小端序)
-        val dataLength = data.size
-        packet.add((dataLength and 0xFF).toByte())
-        packet.add(((dataLength shr 8) and 0xFF).toByte())
+        // seq‑number(保持请求的 seq,大端序)
+        packet[idx++] = (requestSeq shr 8).toByte()
+        packet[idx++] = requestSeq.toByte()
         
-        // 数据区
-        packet.addAll(data.toList())
+        // payload length = 0(大端序)
+        packet[idx++] = (payloadLen shr 8).toByte()
+        packet[idx++] = payloadLen.toByte()
         
-        // 应答状态(0x01=ACK)
-        packet.add(0x01.toByte())
+        // 计算校验和(从收到的包中提取)
+        val checkSumArray = Arrays.copyOfRange(value, 1, value.size - 3)
+        val calculatedChecksum = calculateXorChecksum(checkSumArray, 1, checkSumArray.size)
+        val receivedChecksum = value[value.size - 2]
         
-        // 包校验(异或校验)
-        var checksum = 0x00
-        for (i in 1 until packet.size) {
-            checksum = checksum xor packet[i].toInt()
+        // 状态位:如果校验通过则为0x01(ACK),否则为0x02(REX)
+        val status: Byte = if (calculatedChecksum == receivedChecksum) {
+            0x01.toByte()
+        } else {
+            0x02.toByte()
         }
-        packet.add(checksum.toByte())
+        packet[idx++] = status
         
-        // 包尾(0x0D
-        packet.add(0x0D.toByte())
+        // checksum(异或 Header 之后到状态位
+        packet[idx++] = calculateXorChecksum(packet, 1, idx)
         
-        return packet.toByteArray()
+        // footer
+        packet[idx] = footer
+        return packet
     }
     
     /**
-     * 组包数据
-     * 
-     * @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())
+    private fun calculateXorChecksum(buf: ByteArray, start: Int, endExclusive: Int): Byte {
+        var chk: Byte = 0x00
+        for (i in start until endExclusive) {
+            chk = chk.xor(buf[i])
         }
-        
-        return result.toByteArray()
+        return chk
     }
 }
 

+ 174 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BleConnector.kt

@@ -0,0 +1,174 @@
+package com.narutohuo.xindazhou.ble.util
+
+import android.annotation.SuppressLint
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGatt
+import android.bluetooth.BluetoothGattCallback
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor
+import android.bluetooth.BluetoothProfile
+import android.content.Context
+import com.narutohuo.xindazhou.ble.config.BLEConstants
+import com.narutohuo.xindazhou.core.log.ILog
+import java.util.UUID
+
+/**
+ * BLE连接器
+ * 
+ * 负责与单个 BLE 设备建立 GATT 连接并完成服务发现
+ * 连接成功后会把需要写入的特征回调给业务层
+ */
+class BleConnector(
+    private val context: Context,
+    private val device: BluetoothDevice,
+    private val onConnected: (BluetoothGatt, BluetoothGattCharacteristic) -> Unit,
+    private val onDisconnected: () -> Unit,
+    private val onError: (String) -> Unit
+) {
+    
+    private val tag = "BleConnector"
+    
+    private var gatt: BluetoothGatt? = null
+    private var writeChar: BluetoothGattCharacteristic? = null
+    private var notifyChar: BluetoothGattCharacteristic? = null
+    
+    /** 供外部发送模块注入的回调对象 */
+    var packetSender: BlePacketSender? = null
+    
+    /**
+     * 发起连接
+     */
+    @SuppressLint("MissingPermission")
+    fun connect() {
+        try {
+            gatt = device.connectGatt(context, false, gattCallback)
+            ILog.d(tag, "开始连接设备: ${device.address}")
+        } catch (e: SecurityException) {
+            ILog.e(tag, "连接权限不足", e)
+            onError("连接权限不足: ${e.message}")
+        } catch (e: Exception) {
+            ILog.e(tag, "连接失败", e)
+            onError("连接失败: ${e.message}")
+        }
+    }
+    
+    /**
+     * 断开连接并释放资源
+     */
+    @SuppressLint("MissingPermission")
+    fun disconnect() {
+        try {
+            gatt?.disconnect()
+            gatt?.close()
+            gatt = null
+            writeChar = null
+            notifyChar = null
+            ILog.d(tag, "已断开连接")
+        } catch (e: Exception) {
+            ILog.e(tag, "断开连接失败", e)
+        }
+    }
+    
+    /**
+     * GATT 回调
+     */
+    private val gattCallback = object : BluetoothGattCallback() {
+        
+        @SuppressLint("MissingPermission")
+        override fun onConnectionStateChange(
+            gatt: BluetoothGatt, status: Int, newState: Int
+        ) {
+            if (newState == BluetoothProfile.STATE_CONNECTED) {
+                ILog.d(tag, "已连接 ${device.address},开始发现服务")
+                gatt.discoverServices()  // 触发 onServicesDiscovered
+            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+                ILog.d(tag, "已断开连接")
+                onDisconnected()
+                disconnect()
+            }
+        }
+        
+        @SuppressLint("MissingPermission")
+        override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
+            if (status != BluetoothGatt.GATT_SUCCESS) {
+                onError("发现服务失败 status=$status")
+                return
+            }
+            
+            ILog.d(tag, "onServicesDiscovered: 发现服务")
+            
+            val targetServiceUuid = BLEConstants.SERVICE_UUID
+            val targetWriteCharUuid = BLEConstants.WRITE_CHARACTERISTIC_UUID
+            val targetNotifyCharUuid = BLEConstants.NOTIFY_CHARACTERISTIC_UUID
+            val charConfigUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
+            
+            val service = this@BleConnector.gatt!!.getService(targetServiceUuid)
+            
+            writeChar = service?.getCharacteristic(targetWriteCharUuid)
+            notifyChar = service?.getCharacteristic(targetNotifyCharUuid)
+            
+            if (writeChar == null) {
+                onError("未找到写特征 $targetWriteCharUuid")
+                return
+            }
+            
+            if (notifyChar == null) {
+                onError("未找到通知特征 $targetNotifyCharUuid")
+                return
+            }
+            
+            // 启用通知
+            try {
+                this@BleConnector.gatt!!.setCharacteristicNotification(notifyChar, true)
+                val descriptor = notifyChar?.getDescriptor(charConfigUuid)
+                descriptor?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
+                this@BleConnector.gatt!!.writeDescriptor(descriptor)
+                
+                ILog.d(tag, "已启用通知")
+                
+                // 连接成功,回调
+                onConnected(this@BleConnector.gatt!!, writeChar!!)
+                
+            } catch (e: SecurityException) {
+                ILog.e(tag, "启用通知权限不足", e)
+                onError("启用通知权限不足: ${e.message}")
+            } catch (e: Exception) {
+                ILog.e(tag, "启用通知失败", e)
+                onError("启用通知失败: ${e.message}")
+            }
+        }
+        
+        override fun onCharacteristicWrite(
+            gatt: BluetoothGatt?,
+            characteristic: BluetoothGattCharacteristic,
+            status: Int
+        ) {
+            super.onCharacteristicWrite(gatt, characteristic, status)
+            ILog.d(tag, "onCharacteristicWrite: status=$status")
+            packetSender?.onCharacteristicWrite(characteristic, status)
+        }
+        
+        override fun onDescriptorWrite(
+            gatt: BluetoothGatt?,
+            descriptor: BluetoothGattDescriptor?,
+            status: Int
+        ) {
+            super.onDescriptorWrite(gatt, descriptor, status)
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                ILog.d(tag, "CCCD 写入成功")
+            } else {
+                ILog.e(tag, "CCCD 写入失败,状态码: $status")
+            }
+        }
+        
+        override fun onCharacteristicChanged(
+            gatt: BluetoothGatt,
+            characteristic: BluetoothGattCharacteristic
+        ) {
+            super.onCharacteristicChanged(gatt, characteristic)
+            ILog.d(tag, "收到通知")
+            packetSender?.onCharacteristicNotify(characteristic)
+        }
+    }
+}
+

+ 343 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BlePacketSender.kt

@@ -0,0 +1,343 @@
+package com.narutohuo.xindazhou.ble.util
+
+import android.annotation.SuppressLint
+import android.bluetooth.BluetoothGatt
+import android.bluetooth.BluetoothGattCharacteristic
+import com.narutohuo.xindazhou.ble.model.FragmentBuffer
+import com.narutohuo.xindazhou.ble.model.Packet
+import com.narutohuo.xindazhou.ble.util.parseCommand
+import com.narutohuo.xindazhou.ble.util.parsePacket
+import com.narutohuo.xindazhou.ble.util.toHexString
+import org.json.JSONObject
+import com.narutohuo.xindazhou.core.log.ILog
+import kotlinx.coroutines.*
+import java.util.LinkedList
+import java.util.Queue
+import java.util.UUID
+import kotlin.random.Random
+
+/**
+ * BLE数据包发送器
+ * 
+ * 负责 BLE 写入、超时、重试以及队列管理
+ */
+class BlePacketSender(
+    private val gatt: BluetoothGatt,
+    private var writeChar: BluetoothGattCharacteristic,
+    private val splitter: BLEPacketSplitter = BLEPacketSplitter(),
+    private val maxPayloadPerPacket: Int = 20,
+    private val ackTimeoutMs: Long = 1000L,
+    private val maxRetry: Int = 3,
+    private val onPairing: ((Int) -> Unit)? = null
+) {
+    
+    private val tag = "BlePacketSender"
+    
+    // 发送队列
+    private val pendingPackets: Queue<ByteArray> = LinkedList()
+    
+    // 用来标记当前正在等待的包序号(-1 表示空闲)
+    @Volatile
+    private var waitingSeq = -1
+    
+    // 分包接收缓存
+    private val fragmentCache = mutableMapOf<UInt, FragmentBuffer>()
+    
+    // 业务消息处理回调
+    private var onBusinessMessage: ((String, String, Map<String, String>, String?) -> Unit)? = null
+    
+    /**
+     * 把完整指令数据放入发送队列,随后自动开始发送
+     * 
+     * @param rawData 完整指令数据(不包含分包协议头尾)
+     * @param businessId 业务标识(4字节)
+     * @param isRequest true→请求,false→响应
+     */
+    fun enqueueAndStart(
+        rawData: ByteArray,
+        businessId: ByteArray,
+        isRequest: Boolean = true
+    ) {
+        // 1️⃣ 分包
+        val packets = splitter.split(rawData, businessId, isRequest)
+        // 2️⃣ 入队
+        pendingPackets.addAll(packets)
+        // 3️⃣ 启动发送(如果当前没有正在发送的任务)
+        if (waitingSeq == -1) {
+            sendNextPacket()
+        }
+    }
+    
+    /**
+     * 发送队列中的下一个包(如果有的话)
+     */
+    private fun sendNextPacket() {
+        val packet = pendingPackets.peek() ?: run {
+            // 队列为空 → 发送完毕
+            onAllPacketsSent()
+            return
+        }
+        
+        // 取出包序号(第 7-8 个字节,大端序)
+        waitingSeq = extractSeqFromPacket(packet)
+        sendPacketWithRetry(packet, retryCount = 0)
+    }
+    
+    /**
+     * 实际写入并处理超时/重试
+     */
+    @OptIn(DelicateCoroutinesApi::class)
+    @SuppressLint("MissingPermission")
+    private fun sendPacketWithRetry(packet: ByteArray, retryCount: Int) {
+        // 1️⃣ 写入(WRITE_TYPE_NO_RESPONSE)
+        writeChar.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
+        writeChar.value = packet
+        val writeResult = gatt.writeCharacteristic(writeChar)
+        
+        ILog.d(tag, "发送数据: result=$writeResult, packet=${packet.toHexString()}")
+        
+        if (!writeResult) {
+            // 写入函数本身失败(比如 GATT 已断开),直接进入重试逻辑
+            handleWriteFailure(packet, retryCount, "writeCharacteristic 返回 false")
+            return
+        }
+        
+        // 2️⃣ 启动超时计时
+        CoroutineScope(Dispatchers.Main).launch {
+            try {
+                withTimeout(ackTimeoutMs) {
+                    // 这里会被 onCharacteristicWrite 回调的 `waitingSeq` 置为 -1 打断
+                    while (waitingSeq != -1) {
+                        delay(50)   // 轮询等待 ACK
+                    }
+                }
+                // 超时未抛异常 → 收到 ACK
+                onPacketSuccess()
+            } catch (e: TimeoutCancellationException) {
+                // 超时未收到 ACK
+                handleWriteFailure(packet, retryCount, "ACK 超时")
+            }
+        }
+    }
+    
+    /**
+     * 处理一次写入失败或超时后的重试/跳过逻辑
+     */
+    private fun handleWriteFailure(packet: ByteArray, retryCount: Int, reason: String) {
+        if (retryCount < maxRetry - 1) {
+            // 还有重试次数 → 再次发送
+            ILog.w(tag, "包 seq=$waitingSeq 发送失败($reason),第 ${retryCount + 1} 次重试")
+            sendPacketWithRetry(packet, retryCount + 1)
+        } else {
+            // 已经重试 maxRetry 次,直接放弃该包,进入下一个
+            ILog.e(tag, "包 seq=$waitingSeq 重试 $maxRetry 次仍失败,跳过该包")
+            pendingPackets.poll()   // 移除当前包
+            waitingSeq = -1
+            sendNextPacket()
+        }
+    }
+    
+    /**
+     * 当前包发送成功后调用
+     */
+    private fun onPacketSuccess() {
+        ILog.d(tag, "包 seq=$waitingSeq 发送成功")
+        pendingPackets.poll()   // 移除已成功的包
+        waitingSeq = -1
+        sendNextPacket()
+    }
+    
+    /**
+     * 所有队列中的包都已发送完毕后调用
+     */
+    private fun onAllPacketsSent() {
+        ILog.d(tag, "全部分包发送完毕")
+    }
+    
+    /**
+     * 必须在外部的 BluetoothGattCallback 中调用此方法
+     * 当收到从设备的写响应(onCharacteristicWrite)时触发
+     */
+    fun onCharacteristicWrite(characteristic: BluetoothGattCharacteristic, status: Int) {
+        ILog.d(tag, "onCharacteristicWrite: status=$status")
+        if (characteristic.uuid != writeChar.uuid) return
+        if (status == android.bluetooth.BluetoothGatt.GATT_SUCCESS) {
+            ILog.d(tag, "设备返回写成功")
+            // 从设备确认收到该包 → 结束等待
+            waitingSeq = -1
+        } else {
+            ILog.w(tag, "设备返回写错误 status=$status,视为发送失败")
+            waitingSeq = -1
+        }
+    }
+    
+    /**
+     * 必须在外部的 BluetoothGattCallback 中调用此方法
+     * 当收到从设备的通知(onCharacteristicChanged)时触发
+     */
+    @SuppressLint("MissingPermission")
+    fun onCharacteristicNotify(characteristic: BluetoothGattCharacteristic) {
+        val value = characteristic.value ?: return
+        ILog.d(tag, "收到通知: ${value.toHexString()}")
+        
+        try {
+            val packet = value.parsePacket()
+            if (!packet.isValid()) {
+                ILog.e(tag, "收到非法数据包,校验失败")
+                return
+            }
+            
+            if (packet.messageType() == 0x01.toByte()) { // 请求
+                // 1. 自动发送 ACK 响应
+                val ackPacket = packet.buildAckResponse()
+                pendingPackets.add(ackPacket)
+                if (waitingSeq == -1) sendNextPacket()
+                
+                // 2. 业务层分片缓存(去掉最低字节,只保留高 24 位)
+                val cacheKey = packet.businessId and 0xFFFFFF00u
+                val buffer = fragmentCache.getOrPut(cacheKey) {
+                    FragmentBuffer(totalPackets = packet.totalPackets.toInt())
+                }
+                
+                // 3. 保存当前分片
+                buffer.received[packet.packetSeq.toInt()] = packet.data
+                
+                // 4. 检查是否已收齐
+                if (buffer.isComplete()) {
+                    val fullData = buffer.assemble()
+                    try {
+                        val command = fullData.parseCommand()
+                        ILog.d(tag, "完整指令解析成功,数据长度=${command.data.size}")
+                        
+                        // 5. 处理业务消息(JSON格式)
+                        handleBusinessMessage(command.data)
+                        
+                    } catch (e: Exception) {
+                        ILog.e(tag, "指令解析失败", e)
+                    }
+                    // 清理缓存
+                    fragmentCache.remove(cacheKey)
+                } else {
+                    ILog.d(tag, "业务ID 0x${cacheKey.toString(16)} 已收到 ${buffer.received.size}/${buffer.totalPackets} 包")
+                }
+                
+            } else if (packet.messageType() == 0x02.toByte()) { // 响应
+                // 处理响应包(如果需要)
+                ILog.d(tag, "收到响应包,seq=${packet.packetSeq}")
+            }
+        } catch (e: Exception) {
+            ILog.e(tag, "解析通知数据失败", e)
+        }
+    }
+    
+    /**
+     * 处理业务消息(JSON格式)
+     */
+    private fun handleBusinessMessage(data: ByteArray) {
+        try {
+            val jsonString = String(data, Charsets.UTF_8)
+            ILog.d(tag, "收到业务消息: $jsonString")
+            
+            // 解析JSON
+            val jsonObject = JSONObject(jsonString)
+            val ty = jsonObject.optInt("TY", 0)
+            val `in` = jsonObject.optInt("IN", 0)
+            
+            // 处理握手和配对
+            if (ty == 3 && `in` == 3) {
+                // 握手请求
+                handleHandshakeRequest(jsonObject)
+            } else if (ty == 3 && `in` == 4) {
+                // 配对请求
+                handlePairingRequest(jsonObject)
+            }
+            
+            // 通知业务层
+            val extras = mutableMapOf<String, String>()
+            jsonObject.keys().forEach { key ->
+                extras[key] = jsonObject.optString(key, "")
+            }
+            
+            onBusinessMessage?.invoke(
+                "业务消息",
+                jsonString,
+                extras,
+                jsonObject.optString("ID", null)
+            )
+            
+        } catch (e: Exception) {
+            ILog.e(tag, "解析业务消息失败", e)
+        }
+    }
+    
+    /**
+     * 处理握手请求
+     */
+    private fun handleHandshakeRequest(message: JSONObject) {
+        try {
+            val c = message.getJSONObject("C")
+            val d = c.getJSONObject("D")
+            val random = d.getInt("Random")
+            ILog.d(tag, "收到握手请求,随机数: $random")
+            
+            // 这里应该由业务层处理握手响应
+            // 暂时只记录日志
+            ILog.d(tag, "握手请求已接收,等待业务层处理")
+            
+        } catch (e: Exception) {
+            ILog.e(tag, "处理握手请求失败", e)
+        }
+    }
+    
+    /**
+     * 处理配对请求
+     */
+    private fun handlePairingRequest(message: JSONObject) {
+        try {
+            val c = message.getJSONObject("C")
+            val d = c.getJSONObject("D")
+            val pairing = d.getInt("Pairing")
+            ILog.d(tag, "收到配对请求,配对状态: $pairing")
+            
+            // 通知业务层
+            onPairing?.invoke(pairing)
+            
+        } catch (e: Exception) {
+            ILog.e(tag, "处理配对请求失败", e)
+        }
+    }
+    
+    /**
+     * 设置业务消息监听器
+     */
+    fun setBusinessMessageListener(listener: (String, String, Map<String, String>, String?) -> Unit) {
+        this.onBusinessMessage = listener
+    }
+    
+    /**
+     * 从包中提取序号
+     */
+    private fun extractSeqFromPacket(packet: ByteArray): Int {
+        if (packet.size < 9) return -1
+        val high = packet[7].toInt() and 0xFF
+        val low = packet[8].toInt() and 0xFF
+        return (high shl 8) or low
+    }
+    
+    /**
+     * 生成业务ID
+     */
+    fun generateBusinessId(): ByteArray {
+        val timestamp = System.currentTimeMillis()
+        val timePart = timestamp and 0xFFFFL
+        val randomPart: Int = Random.nextInt(0xFF + 1)
+        val combined = ((timePart shl 8) or randomPart.toLong()).toInt()
+        val idBytes = ByteArray(4)
+        idBytes[0] = (combined shr 16).toByte() // 高8位
+        idBytes[1] = (combined shr 8).toByte()  // 中8位
+        idBytes[2] = combined.toByte()          // 低8位
+        idBytes[3] = 0x01.toByte()             // 请求类型(会在split时设置)
+        return idBytes
+    }
+}
+

+ 113 - 0
capability-ble/src/main/java/com/narutohuo/xindazhou/ble/util/BleScanner.kt

@@ -0,0 +1,113 @@
+package com.narutohuo.xindazhou.ble.util
+
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+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 com.narutohuo.xindazhou.core.log.ILog
+
+/**
+ * BLE扫描器
+ * 
+ * 负责 BLE 设备的扫描,返回符合过滤条件的 BluetoothDevice 列表
+ * 使用 Android 12+ 推荐的 BluetoothLeScanner API
+ */
+class BleScanner(
+    private val context: Context,
+    private val onDeviceFound: (BluetoothDevice) -> Unit,
+    private val onScanFinished: () -> Unit
+) {
+    
+    private val tag = "BleScanner"
+    
+    private val bluetoothAdapter: BluetoothAdapter by lazy {
+        val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
+        manager.adapter
+    }
+    
+    private var scanner: BluetoothLeScanner? = null
+    private var scanning = false
+    
+    private val scanCallback = object : ScanCallback() {
+        override fun onScanResult(callbackType: Int, result: ScanResult) {
+            result.device?.let {
+                onDeviceFound(it)
+                stopScan()
+            }
+        }
+        
+        override fun onBatchScanResults(results: List<ScanResult>) {
+            results.forEach {
+                it.device?.let { device ->
+                    onDeviceFound(device)
+                    stopScan()
+                }
+            }
+        }
+        
+        override fun onScanFailed(errorCode: Int) {
+            ILog.e(tag, "BLE scan failed, error=$errorCode")
+            stopScan()
+        }
+    }
+    
+    /**
+     * 开始扫描(默认 10 秒后自动停止)
+     */
+    @android.annotation.SuppressLint("MissingPermission")
+    fun startScan(filterNamePrefix: String? = null, timeoutMs: Long = 10_000L) {
+        if (scanning) return
+        
+        scanner = bluetoothAdapter.bluetoothLeScanner
+        val settings = ScanSettings.Builder()
+            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+            .build()
+        
+        val filters = mutableListOf<ScanFilter>()
+        filterNamePrefix?.let {
+            filters.add(ScanFilter.Builder().setDeviceName(it).build())
+        }
+        
+        try {
+            scanner?.startScan(filters, settings, scanCallback)
+            scanning = true
+            ILog.d(tag, "开始扫描BLE设备,过滤前缀: $filterNamePrefix")
+            
+            // 超时自动停止
+            Handler(Looper.getMainLooper()).postDelayed({ stopScan() }, timeoutMs)
+        } catch (e: SecurityException) {
+            ILog.e(tag, "扫描权限不足", e)
+            scanning = false
+        } catch (e: Exception) {
+            ILog.e(tag, "启动扫描失败", e)
+            scanning = false
+        }
+    }
+    
+    /**
+     * 停止扫描
+     */
+    @android.annotation.SuppressLint("MissingPermission")
+    fun stopScan() {
+        if (!scanning) return
+        
+        try {
+            scanner?.stopScan(scanCallback)
+            scanning = false
+            ILog.d(tag, "停止扫描")
+            onScanFinished()
+        } catch (e: SecurityException) {
+            ILog.e(tag, "停止扫描权限不足", e)
+        } catch (e: Exception) {
+            ILog.e(tag, "停止扫描失败", e)
+        }
+    }
+}
+

+ 3 - 3
capability-nfc/build.gradle

@@ -21,8 +21,8 @@ android {
 }
 
 dependencies {
-    // 只依赖 base-common(不直接依赖 base-core
-    // base-common 会传递 base-core 的依赖
-    implementation(project(":base-common"))
+    // 直接依赖 base-core(能力层只需要 base-core 的接口和基础能力
+    // base-core 提供接口定义和基础实现(ILog、NetworkManager)
+    implementation(project(":base-core"))
 }
 

+ 4 - 4
capability-push/build.gradle

@@ -37,15 +37,15 @@ repositories {
 }
 
 dependencies {
-    // 只依赖 base-common(不直接依赖 base-core
-    // base-common 会传递 base-core 的依赖(包括 Gson、ILog 等
-    implementation(project(":base-common"))
+    // 直接依赖 base-core(能力层只需要 base-core 的接口和基础能力
+    // base-core 提供接口定义(IPushService)和基础实现(ILog、NetworkManager
+    implementation(project(":base-core"))
     
     // ARouter(用于依赖注入,实现 base-core 与 push 模块的解耦)
     // base-core 已经通过 api 传递了 arouter-api,这里只需要添加编译器
     kapt("com.alibaba:arouter-compiler:1.5.2")
     
-    // 注意:Gson、ILog 已通过 base-common 传递,无需重复依赖
+    // 注意:Gson、ILog、ARouter 等已通过 base-core 传递,无需重复依赖
     
     // 极光推送SDK(使用本地下载的 AAR 文件)
     // 注意:需要在极光推送官网注册应用获取 AppKey,并在 AndroidManifest.xml 中配置

+ 3 - 3
capability-push/src/main/java/com/narutohuo/xindazhou/push/receiver/JPushReceiver.kt

@@ -4,7 +4,7 @@ import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
 import cn.jpush.android.api.JPushInterface
-import com.alibaba.fastjson2.JSON
+import com.google.gson.Gson
 import com.narutohuo.xindazhou.core.log.ILog
 import com.narutohuo.xindazhou.push.factory.PushServiceFactory
 import com.narutohuo.xindazhou.push.impl.PushServiceImpl
@@ -32,7 +32,7 @@ class JPushReceiver : BroadcastReceiver() {
                 
                 // 解析 extras(JSON 格式)
                 val extrasMap = try {
-                    val jsonObject = JSON.parseObject(extrasJson, Map::class.java) as? Map<*, *>
+                    val jsonObject = Gson().fromJson(extrasJson, Map::class.java) as? Map<*, *>
                     jsonObject?.mapKeys { it.key.toString() }?.mapValues { it.value.toString() } ?: emptyMap()
                 } catch (e: Exception) {
                     ILog.e("JPushReceiver", "解析 extras 失败", e)
@@ -63,7 +63,7 @@ class JPushReceiver : BroadcastReceiver() {
                 
                 // 解析 extras(JSON 格式)
                 val extrasMap = try {
-                    val jsonObject = JSON.parseObject(extrasJson, Map::class.java) as? Map<*, *>
+                    val jsonObject = Gson().fromJson(extrasJson, Map::class.java) as? Map<*, *>
                     jsonObject?.mapKeys { it.key.toString() }?.mapValues { it.value.toString() } ?: emptyMap()
                 } catch (e: Exception) {
                     ILog.e("JPushReceiver", "解析 extras 失败", e)

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 170 - 16
capability-push/集成说明.html


+ 178 - 15
capability-push/集成说明.md

@@ -16,6 +16,8 @@ capability-push/src/
             │   └── PushServiceImpl.kt     # 推送服务具体实现(封装极光推送SDK)
             ├── receiver/             # 接收器层
             │   └── JPushReceiver.kt       # 推送消息接收器(完全封装在模块内部)
+            ├── mapping/              # 页面映射层
+            │   └── ActivityMapping.kt     # 静态页面映射配置(支持应用未启动时跳转)
             └── model/                # 数据模型层
                 ├── PushConfig.kt          # 推送服务配置模型
                 └── PushResponse.kt         # 推送相关的数据模型
@@ -46,7 +48,16 @@ capability-push/src/
   - 自动接收极光推送的消息(自定义消息、通知消息、通知点击)
   - 自动解析消息内容
   - **完全封装**:在模块的 `AndroidManifest.xml` 中自动注册,业务层无需处理
-  - **自动跳转**:根据 `pageMappings` 自动处理通知点击跳转
+  - **自动跳转**:优先使用静态配置(`ActivityMapping`)自动处理通知点击跳转,支持应用未启动场景
+
+### 3.2 mapping/ 层 - 页面映射配置
+- **职责**:提供静态页面映射配置,支持应用未启动时的跳转
+- **内容**:`ActivityMapping` 静态配置类
+- **功能**:
+  - **静态配置**:页面映射关系在编译时确定,不依赖运行时初始化
+  - **应用未启动支持**:即使应用从未启动过,点击通知也能正常跳转
+  - **向后兼容**:支持运行时动态配置(通过 `pageMappings` 参数)
+  - **优先级**:静态配置优先,运行时配置作为补充
 
 ### 4. model/ 层 - 数据模型
 - **职责**:定义推送相关的数据模型
@@ -63,6 +74,7 @@ capability-push/src/
 - **单例模式**:全局共享一个服务实例
 - **分层架构**:base-core (接口) → capability-push (实现) → ARouter (注册) → Factory (获取)
 - **完全封装**:跳转逻辑封装在模块内部,外部只需配置页面映射规则
+- **静态配置优先**:使用静态配置(`ActivityMapping`)确保应用未启动时也能正常跳转
 
 ### ARouter 架构说明
 
@@ -89,7 +101,8 @@ capability-push/src/
 - `IPushService` 接口已在 `base-core` 模块定义
 - `PushConfig` 配置模型已创建
 - `JPushReceiver` 消息接收器已封装
-- **跳转逻辑已封装**:自动跳转功能已实现
+- **`ActivityMapping` 静态页面映射已实现**:支持应用未启动时的跳转
+- **跳转逻辑已封装**:自动跳转功能已实现,优先使用静态配置
 - **ARouter 集成完成**:模块间解耦,通过 ARouter 进行依赖注入
 
 ✅ **配置已完成**
@@ -128,6 +141,64 @@ capability-push/src/
 </resources>
 ```
 
+### 3.5 配置静态页面映射(推荐,支持应用未启动场景)
+
+**方式1:使用静态配置(推荐)**
+
+在 `capability-push/src/main/java/com/narutohuo/xindazhou/push/mapping/ActivityMapping.kt` 中配置:
+
+```kotlin
+package com.narutohuo.xindazhou.push.mapping
+
+import com.narutohuo.xindazhou.core.log.ILog
+
+/**
+ * 静态页面映射配置
+ * 
+ * 优势:
+ * - 支持应用未启动时的跳转
+ * - 不依赖 Application.onCreate() 的执行顺序
+ * - 更可靠,避免初始化时序问题
+ */
+object ActivityMapping {
+    /**
+     * 静态页面映射配置
+     * 页面名称 -> Activity 完整类名
+     */
+    private val pageToActivityMap = mapOf(
+        "detail" to "com.narutohuo.xindazhou.ui.DetailActivity",
+        "home" to "com.narutohuo.xindazhou.ui.MainActivity",
+        "order" to "com.narutohuo.xindazhou.ui.OrderActivity",
+        // 添加更多页面映射...
+    )
+    
+    /**
+     * 根据页面名称获取 Activity Class
+     * 
+     * @param page 页面名称(从推送的 extras["page"] 获取)
+     * @return Activity Class,如果未找到返回 null
+     */
+    fun getActivityClass(page: String): Class<*>? {
+        val className = pageToActivityMap[page] ?: return null
+        return try {
+            Class.forName(className)
+        } catch (e: ClassNotFoundException) {
+            ILog.e("ActivityMapping", "找不到 Activity: $className", e)
+            null
+        }
+    }
+}
+```
+
+**方式2:使用运行时配置(向后兼容)**
+
+在 `Application.onCreate()` 中通过 `pageMappings` 参数配置(见下方"4. 在 Application 中初始化")。
+
+**推荐使用方式1(静态配置)**,因为:
+- ✅ 支持应用未启动时的跳转
+- ✅ 不依赖初始化顺序
+- ✅ 更可靠
+
 ### 4. 在 Application 中初始化(统一入口)
 
 在您的 `XinDaZhouApplication` 类中初始化推送服务:
@@ -145,9 +216,16 @@ class XinDaZhouApplication : Application() {
         super.onCreate()
         
         // ========== 初始化推送服务(从资源文件读取配置)==========
+        // 方式1:只使用静态配置(推荐,已在 ActivityMapping 中配置)
+        PushServiceFactory.init(
+            context = this
+        )
+        
+        // 方式2:同时配置运行时映射(可选,作为静态配置的补充)
         PushServiceFactory.init(
             context = this,
-            // 页面映射规则(用于自动跳转)
+            // 页面映射规则(用于自动跳转,作为静态配置的补充)
+            // 注意:如果已在 ActivityMapping 中配置,这里可以不传
             pageMappings = mapOf(
                 "detail" to DetailActivity::class.java,  // 详情页
                 "home" to MainActivity::class.java,       // 首页
@@ -157,10 +235,16 @@ class XinDaZhouApplication : Application() {
 }
 ```
 
+**配置说明**:
+- ✅ **静态配置优先**:`ActivityMapping` 中的配置优先级最高,即使应用未启动也能使用
+- ✅ **运行时配置补充**:`pageMappings` 参数作为补充,用于动态配置或覆盖静态配置
+- ✅ **向后兼容**:如果只使用 `pageMappings`,也能正常工作(但应用未启动时可能失败)
+
 **优势**:
-- ✅ **最简单**:只需一行代码,配置都在资源文件中
+- ✅ **最简单**:只需一行代码,配置都在资源文件和静态配置类
 - ✅ **统一入口**:通过 `PushServiceFactory.init()` 统一初始化
 - ✅ **跳转逻辑封装**:跳转逻辑完全封装在模块内部,外部只需要配置页面映射规则
+- ✅ **应用未启动支持**:静态配置确保即使应用从未启动过,点击通知也能正常跳转
 - ✅ **容错处理**:初始化失败不会影响应用启动,只记录日志
 - ✅ **自动识别设备**:极光推送 SDK 自动识别设备类型并选择对应厂商通道
 - ✅ 业务层不直接依赖极光推送API
@@ -182,8 +266,16 @@ class XinDaZhouApplication : Application() {
 **工作原理**:
 1. 用户点击通知栏通知
 2. 模块内部自动解析 `extras["page"]`
-3. 根据 `pageMappings` 自动跳转到对应 Activity
-4. 所有 `extras` 参数自动传递给目标 Activity
+3. **优先使用静态配置**:从 `ActivityMapping` 获取 Activity Class(支持应用未启动场景)
+4. **备选方案**:如果静态配置未找到,使用运行时配置的 `pageMappings`
+5. 根据映射关系自动跳转到对应 Activity
+6. 所有 `extras` 参数自动传递给目标 Activity
+
+**优势**:
+- ✅ **应用未启动支持**:即使应用从未启动过,点击通知也能正常跳转
+- ✅ **不依赖初始化顺序**:静态配置在类加载时即可用,不依赖 `Application.onCreate()`
+- ✅ **更可靠**:避免因初始化时序问题导致的跳转失败
+- ✅ **向后兼容**:仍支持运行时动态配置 `pageMappings`
 
 **服务器推送格式**:
 ```json
@@ -193,7 +285,7 @@ class XinDaZhouApplication : Application() {
     "alert": "您有一个新订单待处理"
   },
   "extras": {
-    "page": "detail",  // 必须匹配 pageMappings 中的 key
+    "page": "detail",  // 必须匹配 ActivityMapping 或 pageMappings 中的 key
     "id": "12345"      // 会自动传递给目标 Activity
   }
 }
@@ -213,16 +305,13 @@ class XinDaZhouApplication : Application() {
 ### 初始化(在 Application 中)
 
 ```kotlin
-// 方式1:只配置自动跳转(推荐,最简单)
+// 方式1:只使用静态配置(推荐,支持应用未启动场景)
+// 页面映射已在 ActivityMapping 中配置
 PushServiceFactory.init(
-    context = this,
-    pageMappings = mapOf(
-        "detail" to DetailActivity::class.java,
-        "home" to MainActivity::class.java,
-    )
+    context = this
 )
 
-// 方式2:配置监听器(可选
+// 方式2:同时配置运行时映射(可选,作为静态配置的补充)
 PushServiceFactory.init(
     context = this,
     messageListener = { message ->
@@ -235,10 +324,39 @@ PushServiceFactory.init(
     },
     pageMappings = mapOf(
         "detail" to DetailActivity::class.java,
+        // 注意:如果已在 ActivityMapping 中配置,这里可以不传
     )
 )
 ```
 
+### 配置静态页面映射(在 ActivityMapping.kt 中)
+
+```kotlin
+// capability-push/src/main/java/com/narutohuo/xindazhou/push/mapping/ActivityMapping.kt
+package com.narutohuo.xindazhou.push.mapping
+
+import com.narutohuo.xindazhou.core.log.ILog
+
+object ActivityMapping {
+    private val pageToActivityMap = mapOf(
+        "detail" to "com.narutohuo.xindazhou.ui.DetailActivity",
+        "home" to "com.narutohuo.xindazhou.ui.MainActivity",
+        "order" to "com.narutohuo.xindazhou.ui.OrderActivity",
+        // 添加更多页面映射...
+    )
+    
+    fun getActivityClass(page: String): Class<*>? {
+        val className = pageToActivityMap[page] ?: return null
+        return try {
+            Class.forName(className)
+        } catch (e: ClassNotFoundException) {
+            ILog.e("ActivityMapping", "找不到 Activity: $className", e)
+            null
+        }
+    }
+}
+```
+
 ### 后续使用(可选,按需调用)
 
 ```kotlin
@@ -258,7 +376,7 @@ val isEnabled = pushService.isPushEnabled()  // 检查推送状态(可选)
 
 2. **通知消息(系统通知栏)**:
    - **展示**:由极光推送 SDK 和系统自动处理,自动显示在通知栏
-   - **点击**:通过 `pageMappings` 自动跳转(已封装)
+   - **点击**:优先使用静态配置(`ActivityMapping`)自动跳转,支持应用未启动场景(已封装)
    - 适用于需要系统通知栏显示的推送
 
 ## 配置位置说明
@@ -275,6 +393,51 @@ val isEnabled = pushService.isPushEnabled()  // 检查推送状态(可选)
 - ❌ **禁止**在 `app/build.gradle` 中配置极光推送相关参数
 - ✅ **所有配置都在 `capability-push` 模块中!**
 
+## 常见问题
+
+### Q1: 应用从未启动过,点击通知能正常跳转吗?
+
+**A: 可以!** 使用静态配置(`ActivityMapping`)后,即使应用从未启动过,点击通知也能正常跳转。
+
+**原理**:
+- `BroadcastReceiver` 是独立组件,系统会在应用未启动时启动应用进程
+- 静态配置在类加载时即可用,不依赖 `Application.onCreate()` 的执行
+- 跳转逻辑优先使用静态配置,确保可靠性
+
+### Q2: 静态配置和运行时配置(pageMappings)有什么区别?
+
+**A:**
+- **静态配置**(`ActivityMapping`):
+  - ✅ 支持应用未启动时的跳转
+  - ✅ 不依赖初始化顺序
+  - ✅ 更可靠
+  - ❌ 需要修改代码并重新编译
+  
+- **运行时配置**(`pageMappings`):
+  - ✅ 可以动态配置
+  - ✅ 不需要重新编译
+  - ❌ 依赖 `Application.onCreate()` 的执行
+  - ❌ 应用未启动时可能失败
+
+**推荐**:优先使用静态配置,运行时配置作为补充。
+
+### Q3: 如何添加新的页面映射?
+
+**A:** 在 `ActivityMapping.kt` 的 `pageToActivityMap` 中添加新的映射关系:
+
+```kotlin
+private val pageToActivityMap = mapOf(
+    "detail" to "com.narutohuo.xindazhou.ui.DetailActivity",
+    "newPage" to "com.narutohuo.xindazhou.ui.NewPageActivity",  // 新增
+)
+```
+
+注意:Activity 类名必须是完整的包名路径。
+
+### Q4: 如果静态配置和运行时配置都配置了同一个页面,会使用哪个?
+
+**A:** 静态配置(`ActivityMapping`)优先级更高。如果静态配置中找到了对应的 Activity,会优先使用静态配置;如果静态配置中未找到,才会使用运行时配置(`pageMappings`)。
+
 ## 参考文档
 
 - [极光推送官方文档](https://docs.jiguang.cn/jpush/client/android/android_guide/)

+ 3 - 3
capability-qrcode/build.gradle

@@ -21,9 +21,9 @@ android {
 }
 
 dependencies {
-    // 只依赖 base-common(不直接依赖 base-core
-    // base-common 会传递 base-core 的依赖
-    implementation(project(":base-common"))
+    // 直接依赖 base-core(能力层只需要 base-core 的接口和基础能力
+    // base-core 提供接口定义和基础实现(ILog、NetworkManager)
+    implementation(project(":base-core"))
     
     // 华为扫码SDK(待添加具体版本)
     // implementation 'com.huawei.hms:scan:xxx'

+ 3 - 3
capability-share/build.gradle

@@ -39,9 +39,9 @@ repositories {
 }
 
 dependencies {
-    // 只依赖 base-common(不直接依赖 base-core
-    // base-common 会传递 base-core 的依赖
-    implementation(project(":base-common"))
+    // 直接依赖 base-core(能力层只需要 base-core 的接口和基础能力
+    // base-core 提供接口定义(IShareService)和基础实现(ILog、NetworkManager)
+    implementation(project(":base-core"))
     
     // ARouter(用于依赖注入,实现 base-core 与 share 模块的解耦)
     // base-core 已经通过 api 传递了 arouter-api,这里只需要添加编译器

capability-share/集成说明.html → capability-share/分享集成说明.html


+ 398 - 0
capability-share/重构方案-移除ShareProxyActivity.md

@@ -0,0 +1,398 @@
+# 分享模块重构方案 - 移除 ShareProxyActivity
+
+## 一、现状分析
+
+### 1.1 当前架构
+
+当前分享模块使用 **ShareProxyActivity** 作为透明代理 Activity 来统一处理所有平台的分享回调:
+
+```
+业务层调用 shareService.share(activity, content, callback)
+    ↓
+自动启动 ShareProxyActivity(透明)
+    ↓
+ShareProxyActivity.onCreate() 调用 shareService.shareManual()
+    ↓
+执行实际分享(友盟SDK)
+    ↓
+用户在第三方应用完成分享
+    ↓
+第三方应用回调 → ShareProxyActivity.onActivityResult()
+    ↓
+ShareProxyActivity 调用 shareService.onActivityResult()
+    ↓
+处理回调并传递给业务层
+    ↓
+ShareProxyActivity 自动关闭
+```
+
+### 1.2 当前实现的关键点
+
+1. **ShareProxyActivity**:
+   - 透明的代理 Activity,用户看不到
+   - 统一处理所有平台的 `onActivityResult` 回调
+   - 业务层无需在 Activity 中处理回调
+
+2. **share() 方法**:
+   - 自动启动 `ShareProxyActivity`
+   - 内部使用 `shareManual()` 避免递归调用
+
+3. **shareManual() 方法**:
+   - 供 `ShareProxyActivity` 内部调用
+   - 直接执行分享逻辑,不启动代理 Activity
+
+4. **onActivityResult() 方法**:
+   - 由 `ShareProxyActivity` 调用
+   - 转发给友盟 SDK 处理
+
+### 1.3 当前架构的优势
+
+✅ **业务层透明**:业务层不需要处理 `onActivityResult`  
+✅ **统一处理**:所有平台的回调都统一在 `ShareProxyActivity` 中处理  
+✅ **完全封装**:实现细节完全封装在模块内部  
+
+### 1.4 当前架构的问题
+
+❌ **依赖 Activity**:必须启动一个透明的 Activity  
+❌ **生命周期复杂**:需要管理 Activity 的生命周期和超时  
+❌ **增加 Activity 栈**:每次分享都会启动新的 Activity  
+❌ **灵活性不足**:无法让业务层自行处理回调  
+
+---
+
+## 二、重构目标
+
+### 2.1 需求
+
+1. **移除 ShareProxyActivity**:不通过代理 Activity 统一处理
+2. **只暴露方法**:所有功能都通过方法暴露
+3. **统一入口**:提供一个统一的分享方法给外部调用
+4. **业务层自行处理回调**:业务层需要在 Activity 中处理 `onActivityResult`
+
+### 2.2 重构后的架构
+
+```
+业务层调用 shareService.share(activity, content, callback)
+    ↓
+直接执行分享(友盟SDK)
+    ↓
+用户在第三方应用完成分享
+    ↓
+第三方应用回调 → 业务层 Activity.onActivityResult()
+    ↓
+业务层调用 shareService.onActivityResult()
+    ↓
+处理回调并传递给业务层
+```
+
+---
+
+## 三、重构方案
+
+### 3.1 API 设计
+
+#### 3.1.1 统一分享方法
+
+所有分享都通过一个统一的 `share()` 方法:
+
+```kotlin
+interface ShareService {
+    /**
+     * 统一分享方法(推荐使用)
+     * 
+     * 如果 ShareContent.platform 已指定,则直接分享到该平台
+     * 如果 ShareContent.platform 为 null,则显示分享弹窗让用户选择平台
+     * 
+     * 注意:业务层需要在 Activity.onActivityResult() 中调用 shareService.onActivityResult()
+     * 
+     * @param activity Activity上下文
+     * @param content 分享内容
+     * @param callback 分享结果回调
+     */
+    fun share(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    
+    /**
+     * 处理分享回调(必须在 Activity.onActivityResult() 中调用)
+     * 
+     * 业务层必须在 Activity.onActivityResult() 中调用此方法,以接收分享结果
+     * 
+     * @param activity Activity上下文
+     * @param requestCode 请求码
+     * @param resultCode 结果码
+     * @param data Intent数据
+     */
+    fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?)
+}
+```
+
+#### 3.1.2 各平台分享方法(可选,向后兼容)
+
+保留各平台的具体分享方法,但都改为直接调用,不通过代理 Activity:
+
+```kotlin
+interface ShareService {
+    // 统一分享方法(推荐)
+    fun share(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    
+    // 各平台分享方法(可选,向后兼容)
+    fun shareToWeChat(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToWeChatMoments(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToQQ(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToQZone(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToWeibo(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToDouyin(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToXiaohongshu(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToKuaishou(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    fun shareToSystem(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    
+    // 显示分享弹窗
+    fun showShareDialog(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    
+    // 必须调用:处理分享回调
+    fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?)
+}
+```
+
+### 3.2 实现改动
+
+#### 3.2.1 ShareService 接口改动
+
+```kotlin
+interface ShareService {
+    // 移除 shareManual() 方法(不再需要)
+    // 移除:fun shareManual(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit)
+    
+    // share() 方法改为直接执行,不启动 ShareProxyActivity
+    fun share(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit) {
+        // 如果指定了平台,直接分享到该平台
+        if (content.platform != null) {
+            shareToPlatform(activity, content, content.platform, callback)
+        } else {
+            // 否则显示分享弹窗
+            showShareDialog(activity, content, callback)
+        }
+    }
+}
+```
+
+#### 3.2.2 ShareServiceImpl 实现改动
+
+```kotlin
+class ShareServiceImpl : ShareService {
+    
+    // 存储回调(用于 onActivityResult 时查找)
+    private val callbacks = mutableMapOf<Int, (ShareResponse) -> Unit>()
+    private var requestCodeCounter = 1000
+    
+    override fun share(activity: Activity, content: ShareContent, callback: (ShareResponse) -> Unit) {
+        // 不再启动 ShareProxyActivity,直接执行分享
+        if (content.platform != null) {
+            shareToPlatform(activity, content, content.platform, callback)
+        } else {
+            showShareDialog(activity, content, callback)
+        }
+    }
+    
+    private fun shareToPlatform(
+        activity: Activity,
+        content: ShareContent,
+        platform: SharePlatform,
+        callback: (ShareResponse) -> Unit
+    ) {
+        // 生成唯一的 requestCode
+        val requestCode = requestCodeCounter++
+        callbacks[requestCode] = callback
+        
+        // 调用友盟 SDK 进行分享
+        val shareMedia = createShareMedia(activity, content)
+        val shareAction = ShareAction(activity)
+        shareAction.withMedia(shareMedia)
+        shareAction.setPlatform(toShareMedia(platform))
+        shareAction.setCallback(createShareListener(platform, requestCode, callback))
+        shareAction.share()
+    }
+    
+    override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
+        // 转发给友盟 SDK 处理
+        UMShareAPI.get(activity).onActivityResult(requestCode, resultCode, data)
+    }
+    
+    private fun createShareListener(
+        platform: SharePlatform,
+        requestCode: Int,
+        callback: (ShareResponse) -> Unit
+    ): UMShareListener {
+        return object : UMShareListener {
+            override fun onResult(shareMedia: SHARE_MEDIA?) {
+                // 找到对应的回调并调用
+                callbacks[requestCode]?.invoke(
+                    ShareResponse(success = true, data = platform)
+                )
+                callbacks.remove(requestCode)
+            }
+            
+            override fun onError(shareMedia: SHARE_MEDIA?, throwable: Throwable?) {
+                callbacks[requestCode]?.invoke(
+                    ShareResponse(
+                        success = false,
+                        data = platform,
+                        errorMessage = throwable?.message
+                    )
+                )
+                callbacks.remove(requestCode)
+            }
+            
+            override fun onCancel(shareMedia: SHARE_MEDIA?) {
+                callbacks[requestCode]?.invoke(
+                    ShareResponse(
+                        success = false,
+                        data = platform,
+                        errorMessage = "用户取消分享"
+                    )
+                )
+                callbacks.remove(requestCode)
+            }
+        }
+    }
+}
+```
+
+#### 3.2.3 移除 ShareProxyActivity
+
+- 删除 `ShareProxyActivity.kt` 文件
+- 从 `AndroidManifest.xml` 中移除 `ShareProxyActivity` 的声明
+- 移除 `shareManual()` 方法(不再需要)
+
+### 3.3 业务层改动
+
+#### 3.3.1 使用示例(Fragment)
+
+```kotlin
+class UserFragment : Fragment() {
+    
+    private val shareService = ShareServiceFactory.getInstance()
+    
+    private fun shareContent() {
+        val content = ShareContent.builder()
+            .setTitle("分享标题")
+            .setDescription("分享描述")
+            .setUrl("https://example.com")
+            .build()
+        
+        // 调用统一分享方法
+        shareService.share(requireActivity(), content) { response ->
+            if (response.success) {
+                Toast.makeText(requireContext(), "分享成功", Toast.LENGTH_SHORT).show()
+            } else {
+                Toast.makeText(requireContext(), "分享失败: ${response.errorMessage}", Toast.LENGTH_SHORT).show()
+            }
+        }
+    }
+}
+```
+
+#### 3.3.2 必须处理 onActivityResult
+
+**重要**:业务层必须在 Activity 中处理 `onActivityResult`:
+
+```kotlin
+class MainActivity : AppCompatActivity() {
+    
+    private val shareService = ShareServiceFactory.getInstance()
+    
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        
+        // 必须调用:处理分享回调
+        shareService.onActivityResult(this, requestCode, resultCode, data)
+    }
+}
+```
+
+### 3.4 兼容性考虑
+
+#### 3.4.1 向后兼容
+
+- 保留所有现有的 API 方法(`shareToWeChat()`, `shareToQQ()` 等)
+- 只是改变实现方式(不再通过 ShareProxyActivity)
+- 业务层代码改动最小化
+
+#### 3.4.2 迁移指南
+
+1. **必须添加**:在 Activity 中添加 `onActivityResult()` 处理
+2. **无需改动**:调用 `share()` 方法的代码无需改动
+3. **可选**:可以继续使用各平台的具体方法(`shareToWeChat()` 等)
+
+---
+
+## 四、重构步骤
+
+### 步骤 1:修改 ShareService 接口
+
+- [ ] 移除 `shareManual()` 方法
+- [ ] 更新 `share()` 方法的文档说明
+
+### 步骤 2:修改 ShareServiceImpl 实现
+
+- [ ] 修改 `share()` 方法,不再启动 `ShareProxyActivity`
+- [ ] 实现回调管理(使用 Map 存储回调)
+- [ ] 修改各平台分享方法,使用回调管理
+- [ ] 更新 `onActivityResult()` 方法,从回调 Map 中查找并调用回调
+
+### 步骤 3:移除 ShareProxyActivity
+
+- [ ] 删除 `ShareProxyActivity.kt` 文件
+- [ ] 从 `AndroidManifest.xml` 中移除相关声明
+- [ ] 清理相关引用
+
+### 步骤 4:更新文档
+
+- [ ] 更新 `集成说明.md`
+- [ ] 添加 `onActivityResult()` 处理说明
+- [ ] 更新使用示例
+
+### 步骤 5:测试
+
+- [ ] 测试各平台分享功能
+- [ ] 测试分享回调处理
+- [ ] 测试分享弹窗功能
+
+---
+
+## 五、优缺点分析
+
+### 5.1 优点
+
+✅ **灵活性更高**:业务层可以自行处理回调  
+✅ **减少 Activity 栈**:不再启动代理 Activity  
+✅ **代码更简洁**:移除复杂的 Activity 生命周期管理  
+✅ **更符合 Android 规范**:业务层直接处理回调  
+
+### 5.2 缺点
+
+❌ **增加业务层负担**:业务层必须在 Activity 中处理 `onActivityResult`  
+❌ **可能遗漏回调**:如果业务层忘记处理 `onActivityResult`,分享回调将丢失  
+❌ **Fragment 使用不便**:Fragment 需要依赖 Activity 的 `onActivityResult`  
+
+---
+
+## 六、注意事项
+
+1. **必须处理 onActivityResult**:业务层必须在 Activity 中调用 `shareService.onActivityResult()`
+2. **Fragment 使用**:Fragment 需要确保 Activity 正确处理 `onActivityResult`
+3. **回调管理**:需要实现回调的存储和查找机制(使用 requestCode 作为 key)
+4. **内存泄漏**:需要确保回调能够及时清理,避免内存泄漏
+
+---
+
+## 七、总结
+
+重构后的分享模块:
+
+- ✅ 移除了 `ShareProxyActivity`,不再通过代理 Activity 处理回调
+- ✅ 所有功能都通过方法暴露,提供统一的 `share()` 方法
+- ✅ 业务层需要自行处理 `onActivityResult`
+- ✅ 保持向后兼容,现有 API 仍然可用
+
+这个方案更符合 Android 的开发规范,也给了业务层更多的控制权。
+

+ 5 - 4
capability-socketio/build.gradle

@@ -21,15 +21,16 @@ android {
 }
 
 dependencies {
-    // 只依赖 base-common(不直接依赖 base-core)
-    // base-common 会传递 base-core 的依赖(包括 Gson、Coroutines、ILog 等)
-    implementation(project(":base-common"))
+    // 直接依赖 base-core(能力层只需要 base-core 的接口和基础能力)
+    // base-core 提供接口定义和基础实现(ILog、NetworkManager)
+    // base-core 会传递 Gson、Coroutines、ILog 等依赖
+    implementation(project(":base-core"))
     
     // SocketIO客户端库
     // Maven Central最新版本:2.1.2(Java/Android客户端最高版本)
     // netty-socketio 2.0.13 支持 Socket.IO 2.x 客户端
     implementation("io.socket:socket.io-client:2.1.2")
     
-    // 注意:Gson、Coroutines、ILog 已通过 base-common 传递,无需重复依赖
+    // 注意:Gson、Coroutines、ILog 已通过 base-core 传递,无需重复依赖
 }
 

+ 4 - 4
capability-socketio/src/main/java/com/narutohuo/xindazhou/socketio/impl/SocketIOServiceImpl.kt

@@ -1,6 +1,6 @@
 package com.narutohuo.xindazhou.socketio.impl
 
-import com.alibaba.fastjson2.JSON
+import com.google.gson.Gson
 import com.narutohuo.xindazhou.core.log.ILog
 import com.narutohuo.xindazhou.socketio.api.SocketIOService
 import com.narutohuo.xindazhou.socketio.model.SocketIOResponse
@@ -87,7 +87,7 @@ class SocketIOServiceImpl private constructor() : SocketIOService {
                                 when (val arg = args[0]) {
                                     is String -> arg
                                     is JSONObject -> arg.toString() // JSONObject.toString() 返回标准 JSON 字符串
-                                    else -> JSON.toJSONString(arg)
+                                    else -> Gson().toJson(arg)
                                 }
                             } else {
                                 "{}"
@@ -178,7 +178,7 @@ class SocketIOServiceImpl private constructor() : SocketIOService {
                     when (val arg = args[0]) {
                         is String -> arg
                         is JSONObject -> arg.toString() // JSONObject.toString() 返回标准 JSON 字符串
-                        else -> JSON.toJSONString(arg)
+                        else -> Gson().toJson(arg)
                     }
                 } else {
                     "{}"
@@ -218,7 +218,7 @@ class SocketIOServiceImpl private constructor() : SocketIOService {
                 }
                 else -> {
                     // 其他类型先转为 JSON 字符串,再转为 JSONObject
-                    JSONObject(JSON.toJSONString(data))
+                    JSONObject(Gson().toJson(data))
                 }
             }
             

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 454
新大洲 Android 项目结构文档.html


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 275 - 0
架构说明.html


+ 334 - 0
架构说明.md

@@ -0,0 +1,334 @@
+# base-core 与 base-common 整体架构说明
+
+## 📋 架构概述
+
+```
+业务层(app 模块)
+    ↓ 依赖
+    ├── base-common(业务封装层)
+    └── capability-xxx(能力层)
+            ↓ 依赖
+        base-core(基础设施层)
+            ↑ 依赖
+        base-common(业务封装层)
+```
+
+### 依赖关系
+
+- ✅ **业务层(app 模块)依赖 base-common 和 capability-xxx**
+- ✅ **能力层(capability 模块)依赖 base-core**(直接依赖,不通过 base-common)
+- ✅ **base-common 依赖 base-core**
+
+**注意:** capability 模块应该直接依赖 base-core,而不是通过 base-common。虽然当前实现中 capability 依赖 base-common(base-common 会传递 base-core),但更合理的做法是直接依赖 base-core。
+
+### 使用原则
+
+- ✅ **能力层(capability 模块)可以调用 base-core**
+- ✅ **业务层(app 模块)可以调用 base-common 和 capability-xxx**
+- ❌ **业务层不直接调用 base-core**(通过 base-common 间接使用)
+
+---
+
+## 🏗️ 整体代码结构
+
+### base-core(基础设施层)
+
+```
+xdz_android/base-core/
+├── src/main/java/com/narutohuo/xindazhou/core/
+│   ├── log/
+│   │   ├── ILog.kt                       ✅ 日志接口定义
+│   │   └── impl/
+│   │       ├── TimberLog.kt              ✅ Timber 日志实现(基于 Timber 库)
+│   │       └── NoOpLog.kt                ✅ 空日志实现(生产环境使用)
+│   ├── network/
+│   │   └── NetworkManager.kt             ✅ Retrofit/OkHttp 管理器(单例模式)
+│   ├── push/
+│   │   └── IPushService.kt               ✅ 推送服务接口
+│   ├── share/
+│   │   ├── IShareService.kt              ✅ 分享服务接口
+│   │   └── IShareCallback.kt             ✅ 分享回调接口
+│   ├── storage/
+│   │   └── IStorage.kt                   ✅ 存储服务接口(键值存储、文件存储、数据库存储)
+│   └── util/
+│       └── IUtil.kt                       ✅ 工具类接口(时间处理、字符串处理、加密解密)
+└── build.gradle                           ✅ 第三方库管理(Retrofit, OkHttp, Gson, Glide, Coroutines, ARouter, Timber)
+```
+
+---
+
+### base-common(业务封装层)
+
+```
+xdz_android/base-common/
+├── src/main/java/com/narutohuo/xindazhou/common/
+│   ├── bridge/
+│   │   └── BridgeManager.kt              ✅ H5通信、模块间通信封装(直接实现,无需接口)
+│   ├── config/
+│   │   ├── ConfigManager.kt               ✅ 配置管理封装(直接使用 SharedPreferences,无需接口)
+│   │   └── ServerConfigManager.kt         ✅ 服务器配置管理(开发测试时配置服务器地址)
+│   ├── executor/
+│   │   └── ExecutorManager.kt             ✅ 异步任务执行封装(直接使用协程,无需接口)
+│   ├── storage/
+│   │   └── StorageManager.kt              ✅ 封装 IStorage,提供存储管理的便捷方法
+│   ├── util/
+│   │   └── UtilManager.kt                 ✅ 封装 IUtil,提供工具方法的便捷调用
+│   ├── network/
+│   │   ├── ApiServiceFactory.kt           ✅ API 服务工厂,统一创建 API 服务实例
+│   │   ├── ApiBaseRemoteDataSource.kt     ✅ 远程数据源基类,封装通用网络请求逻辑
+│   │   ├── ApiBaseRepository.kt           ✅ Repository 基类,提供通用错误处理和数据转换
+│   │   └── ApiResponseParser.kt           ✅ 响应解析器,解析 Retrofit Response
+│   ├── ui/
+│   │   ├── BaseActivity.kt                ✅ Activity 基类,支持 ViewBinding、加载状态管理、权限请求、屏幕方向
+│   │   ├── BaseFragment.kt                ✅ Fragment 基类,支持 ViewBinding、加载状态管理
+│   │   ├── ActivityManager.kt              ✅ Activity 栈管理,统一管理所有 Activity 生命周期
+│   │   ├── ActivityExtensions.kt          ✅ Activity 扩展函数,简化 StateFlow 观察
+│   │   ├── FragmentExtensions.kt           ✅ Fragment 扩展函数,简化 StateFlow 观察
+│   │   ├── MessageHelper.kt               ✅ Toast/Snackbar 统一封装,提供便捷的消息提示
+│   │   └── StatusBarHelper.kt             ✅ 状态栏/导航栏管理,沉浸式状态栏支持
+│   ├── image/
+│   │   └── ImageLoader.kt                 ✅ 图片加载封装(Glide),支持圆形、圆角、占位图
+│   ├── dialog/
+│   │   ├── DialogHelper.kt                ✅ 对话框统一封装,iOS 风格确认/提示对话框
+│   │   └── CascadePickerDialog.kt         ✅ 级联选择器对话框
+│   ├── file/
+│   │   └── FilePickerHelper.kt            ✅ 文件选择器封装,支持图片、文件、多文件选择
+│   ├── camera/
+│   │   └── CameraHelper.kt                ✅ 相机/相册封装,支持拍照、相册选择、图片裁剪
+│   ├── router/
+│   │   └── RouterHelper.kt                ✅ ARouter 路由封装,统一路由跳转、参数传递
+│   ├── permission/
+│   │   └── PermissionHelper.kt             ✅ 权限管理封装,权限检查、请求、说明对话框
+│   ├── crash/
+│   │   └── CrashHelper.kt                  ✅ 崩溃收集封装,自动捕获崩溃并记录日志
+│   ├── auth/
+│   │   ├── AuthManager.kt                 ✅ 认证管理器,封装登录、注册、Token 刷新逻辑
+│   │   ├── LoginActivity.kt                ✅ 登录页 Activity(完整封装,可直接使用)
+│   │   ├── RegisterActivity.kt             ✅ 注册页 Activity(完整封装,可直接使用)
+│   │   ├── ui/
+│   │   │   ├── LoginFragment.kt            ✅ 登录 Fragment(完整 UI 和逻辑)
+│   │   │   └── RegisterFragment.kt         ✅ 注册 Fragment(完整 UI 和逻辑)
+│   │   ├── model/
+│   │   │   ├── LoginRequest.kt             ✅ 登录请求参数
+│   │   │   ├── LoginResponse.kt            ✅ 登录响应数据
+│   │   │   └── RegisterRequest.kt          ✅ 注册请求参数
+│   │   ├── datasource/
+│   │   │   ├── remote/
+│   │   │   │   ├── AuthApi.kt              ✅ 认证 API 接口
+│   │   │   │   └── AuthRemoteDataSource.kt ✅ 认证远程数据源
+│   │   │   └── local/
+│   │   │       └── AuthLocalDataSource.kt ✅ 认证本地数据源接口(需业务模块实现)
+│   │   └── repository/
+│   │       └── AuthRepository.kt          ✅ 认证数据仓库
+│   ├── version/
+│   │   ├── VersionUpdateManager.kt        ✅ 版本更新管理器,封装版本检查、更新对话框、强制更新
+│   │   ├── VersionCheckActivity.kt        ✅ 版本检查 Activity(通用)
+│   │   ├── ui/
+│   │   │   └── UpdateDialogFragment.kt    ✅ 版本更新对话框 Fragment
+│   │   ├── model/
+│   │   │   └── VersionInfo.kt             ✅ 版本信息数据模型
+│   │   ├── datasource/
+│   │   │   └── remote/
+│   │   │       └── VersionApi.kt           ✅ 版本 API 接口
+│   │   └── repository/
+│   │       └── VersionRepository.kt       ✅ 版本数据仓库
+│   └── launch/
+│       ├── LaunchActivity.kt               ✅ 启动页 Activity(通用,处理登录状态判断和跳转)
+│       └── AppLaunchManager.kt             ✅ 应用启动管理器,统一处理启动逻辑
+└── build.gradle                            ✅ 依赖 base-core
+```
+
+---
+
+### capability-xxx(能力层)
+
+```
+xdz_android/capability-push/
+├── src/main/java/com/narutohuo/xindazhou/push/
+│   ├── api/
+│   │   └── PushService.kt                 ✅ 推送服务接口(模块内部)
+│   ├── factory/
+│   │   └── PushServiceFactory.kt          ✅ 推送服务工厂
+│   ├── impl/
+│   │   └── PushServiceImpl.kt             ✅ 实现 IPushService(base-core 定义)
+│   └── ...
+└── build.gradle                            ✅ 直接依赖 base-core
+
+xdz_android/capability-share/
+├── src/main/java/com/narutohuo/xindazhou/share/
+│   ├── impl/
+│   │   └── ShareServiceImpl.kt            ✅ 实现 IShareService(base-core 定义)
+│   └── ...
+└── build.gradle                            ✅ 直接依赖 base-core
+
+xdz_android/capability-ble/
+└── build.gradle                            ✅ 直接依赖 base-core
+
+xdz_android/capability-nfc/
+└── build.gradle                            ✅ 直接依赖 base-core
+
+xdz_android/capability-qrcode/
+└── build.gradle                            ✅ 直接依赖 base-core
+
+xdz_android/capability-socketio/
+└── build.gradle                            ✅ 直接依赖 base-core
+```
+
+---
+
+### app(业务层)
+
+```
+xdz_android/app/
+├── src/main/java/com/narutohuo/xindazhou/
+│   ├── XinDaZhouApplication.kt             ✅ Application 类,初始化 AuthManager、VersionUpdateManager
+│   ├── MainActivity.kt                     ✅ 主界面 Activity
+│   ├── user/
+│   │   ├── datasource/
+│   │   │   └── local/
+│   │   │       └── AuthLocalDataSourceImpl.kt ✅ 实现 AuthLocalDataSource(使用 TokenManager)
+│   │   └── ...
+│   └── ...
+└── build.gradle                             ✅ 依赖 base-common 和 capability-xxx
+```
+
+**注意:** 
+- ✅ 认证功能已完全封装在 base-common 中,app 模块只需实现 `AuthLocalDataSource`(因为 TokenManager 在 app 模块)
+- ✅ 版本管理功能已完全封装在 base-common 中,app 模块只需在 Application 中调用 `VersionUpdateManager.init()`
+- ✅ 登录/注册界面已完全封装在 base-common 中,app 模块可直接使用 `LoginActivity` 和 `RegisterActivity`
+
+---
+
+## 💡 核心作用
+
+### base-core 的作用
+
+1. **定义接口**:让 capability 模块实现(如 IPushService、IShareService)
+2. **提供基础能力**:ILog、NetworkManager 等,让所有模块统一使用
+3. **管理第三方库**:统一版本,避免冲突
+
+### base-common 的作用
+
+1. **封装 base-core 的接口**:提供便捷的调用方式(StorageManager、UtilManager)
+2. **业务工具封装**:
+   - BridgeManager:H5通信、模块间通信(直接实现)
+   - ConfigManager:配置管理(直接使用 SharedPreferences)
+   - ExecutorManager:异步任务执行(直接使用协程)
+   - ServerConfigManager:服务器配置管理(开发测试时使用)
+3. **MVVM 网络封装**:简化网络请求(ApiServiceFactory、ApiBaseRemoteDataSource、ApiBaseRepository)
+4. **UI 基础类**:简化 UI 开发(BaseActivity、BaseFragment、ActivityManager、扩展函数)
+5. **UI 工具封装**:
+   - ImageLoader:图片加载统一封装
+   - MessageHelper:Toast/Snackbar 统一封装
+   - DialogHelper:iOS 风格对话框统一封装
+   - CascadePickerDialog:级联选择器对话框
+   - StatusBarHelper:状态栏/导航栏管理
+6. **功能封装**:
+   - FilePickerHelper:文件选择器封装
+   - CameraHelper:相机/相册封装
+   - RouterHelper:ARouter 路由封装
+   - PermissionHelper:权限管理封装
+   - CrashHelper:崩溃收集封装
+7. **业务功能完整封装**:
+   - **认证模块(auth)**:完整的登录/注册功能,包括 UI、业务逻辑、数据层
+     - LoginActivity/RegisterActivity:可直接使用的 Activity
+     - LoginFragment/RegisterFragment:完整的 UI 和逻辑
+     - AuthManager:认证管理器,统一管理登录、注册、Token 刷新
+     - AuthRepository:认证数据仓库,MVVM 架构
+   - **版本管理模块(version)**:完整的版本检查更新功能
+     - VersionUpdateManager:版本更新管理器,封装版本检查、更新对话框、强制更新
+     - VersionCheckActivity:版本检查 Activity(通用)
+     - UpdateDialogFragment:版本更新对话框
+   - **启动管理(launch)**:应用启动逻辑封装
+     - LaunchActivity:启动页 Activity(通用)
+     - AppLaunchManager:应用启动管理器,统一处理登录状态判断和跳转
+
+---
+
+## ⚠️ 注意事项
+
+### 1. 依赖关系
+
+- ✅ **业务层(app 模块)依赖 base-common 和 capability-xxx**
+- ✅ **能力层(capability 模块)依赖 base-core**(直接依赖,不通过 base-common)
+- ✅ **base-common 依赖 base-core**
+
+**说明:** 
+- ✅ capability 模块只需要 base-core 的接口和基础能力(ILog、NetworkManager),不需要 base-common 的业务封装
+- ✅ 已优化:所有 capability 模块现在都直接依赖 base-core,不再通过 base-common
+
+### 2. 接口实现
+
+- ✅ base-core 定义接口(IPushService、IShareService 等能力接口)
+- ✅ app 模块实现接口(通过 ARouter 注册)
+- ✅ capability 模块实现接口(IPushService、IShareService 等)
+
+### 3. 初始化顺序
+
+1. ARouter 初始化
+2. 注册接口实现
+3. NetworkManager 初始化
+4. ApiServiceFactory 初始化(设置 baseUrlProvider)
+5. AuthManager 初始化(传入 AuthLocalDataSource 实现)
+6. VersionUpdateManager 初始化
+
+### 4. 使用原则
+
+- ✅ 能力层使用 base-core 的接口和基础能力
+- ✅ 业务层使用 base-common 的封装
+- ❌ 业务层不直接使用 base-core
+
+### 5. 业务功能使用示例
+
+#### 认证功能使用
+
+```kotlin
+// 1. 在 Application 中初始化
+val localDataSource = object : AuthLocalDataSource {
+    override suspend fun saveToken(loginResponse: LoginResponse) {
+        TokenManager.saveToken(...)
+    }
+    // ...
+}
+AuthManager.init(localDataSource)
+
+// 2. 启动登录页
+val intent = Intent(context, LoginActivity::class.java).apply {
+    putExtra(LoginActivity.EXTRA_MAIN_ACTIVITY_CLASS, MainActivity::class.java.name)
+}
+startActivity(intent)
+```
+
+#### 版本管理使用
+
+```kotlin
+// 1. 在 Application 中初始化
+VersionUpdateManager.init(context)
+
+// 2. 在 Activity 中检查更新
+VersionUpdateManager.checkUpdate(activity)
+```
+
+#### 启动管理使用
+
+```kotlin
+// 在 LaunchActivity 中使用
+AppLaunchManager.handleLaunch(
+    activity = this,
+    isLoggedIn = { TokenManager.getAccessToken() != null },
+    mainActivityClass = MainActivity::class.java,
+    loginActivityClass = LoginActivity::class.java
+)
+```
+
+---
+
+## 📚 相关文档
+
+- [base-core README](./base-core/README.md)
+- [base-common README](./base-common/README.md)
+- [网络请求 MVVM 封装方案](./base-common/src/main/java/com/narutohuo/xindazhou/common/network/网络请求MVVM封装方案.md)
+- [UI 层封装方案](./base-common/src/main/java/com/narutohuo/xindazhou/common/ui/UI层封装方案.md)
+- [封装功能使用说明](./base-common/src/main/java/com/narutohuo/xindazhou/common/封装功能使用说明.md)
+- [待封装功能分析](./base-common/src/main/java/com/narutohuo/xindazhou/common/base-common待封装功能分析.md)
+

+ 0 - 868
能力模块开发规范.md

@@ -1,868 +0,0 @@
-# 能力模块开发规范
-
-## 📋 核心原则
-
-**每个能力模块必须完全独立,自己管理自己的所有配置和依赖,app 模块只负责组装,不负责管理能力模块的内部事务。**
-
----
-
-## 🎯 原始诉求
-
-### 问题背景
-- ❌ **之前的问题**:所有配置都在 app 模块的 `strings.xml` 中
-- ❌ **之前的问题**:所有依赖都在 app 模块的 `build.gradle` 中重复声明
-- ❌ **之前的问题**:app 模块需要解析 XML 来读取配置
-- ❌ **之前的问题**:能力模块的配置散落在各处,难以维护
-
-### 解决方案
-- ✅ **现在**:每个能力模块有自己的 `strings.xml`
-- ✅ **现在**:每个能力模块管理自己的依赖(使用 `api` 传递)
-- ✅ **现在**:不需要 XML 解析,直接使用 `@string/` 引用
-- ✅ **现在**:能力模块完全独立,app 模块只负责组装
-
----
-
-## 📁 模块结构规范
-
-### 标准目录结构
-
-```
-capability-xxx/
-├── build.gradle                    # 模块依赖配置
-├── src/main/
-│   ├── AndroidManifest.xml        # 模块的 AndroidManifest(包含 meta-data、Activity 等)
-│   ├── res/
-│   │   └── values/
-│   │       └── strings.xml         # 模块自己的配置(必须!)
-│   └── java/...                    # 模块代码
-└── libs/                           # 模块自己的 SDK 文件(如果有)
-```
-
----
-
-## 🔧 配置管理规范
-
-### 1. strings.xml 配置
-
-**每个能力模块必须有自己的 `strings.xml`**
-
-#### ✅ 正确做法
-
-```xml
-<!-- capability-push/src/main/res/values/strings.xml -->
-<resources>
-    <!-- 极光推送配置 -->
-    <string name="jpush_app_key">your_jpush_appkey_here</string>
-    <string name="push_jpush_channel">developer-default</string>
-</resources>
-```
-
-```xml
-<!-- capability-share/src/main/res/values/strings.xml -->
-<resources>
-    <!-- 友盟分享配置 -->
-    <string name="share_umeng_app_key">your_umeng_appkey_here</string>
-    <string name="share_wechat_app_id">your_wechat_appid_here</string>
-    <string name="qq_app_id_scheme">tencentyour_qq_appid_here</string>
-</resources>
-```
-
-#### ❌ 错误做法
-
-```xml
-<!-- app/src/main/res/values/strings.xml -->
-<resources>
-    <!-- ❌ 不要在这里放能力模块的配置! -->
-    <string name="jpush_app_key">...</string>
-    <string name="share_umeng_app_key">...</string>
-</resources>
-```
-
-### 2. AndroidManifest.xml 配置
-
-**每个能力模块在自己的 AndroidManifest.xml 中配置,使用自己的 `@string/` 资源**
-
-#### ✅ 正确做法
-
-```xml
-<!-- capability-push/src/main/AndroidManifest.xml -->
-<application>
-    <!-- 使用本模块的 @string/ 资源 -->
-    <meta-data
-        android:name="JPUSH_APPKEY"
-        android:value="@string/jpush_app_key"
-        tools:replace="android:value" />
-    
-    <!-- 厂商通道配置(覆盖厂商 SDK 的占位符) -->
-    <meta-data
-        android:name="XIAOMI_APPID"
-        android:value="@string/mi_app_id"
-        tools:replace="android:value" />
-</application>
-```
-
-```xml
-<!-- capability-share/src/main/AndroidManifest.xml -->
-<activity>
-    <!-- 使用本模块的 @string/ 资源 -->
-    <data android:scheme="@string/qq_app_id_scheme" />
-</activity>
-```
-
-#### ❌ 错误做法
-
-```xml
-<!-- app/src/main/AndroidManifest.xml -->
-<application>
-    <!-- ❌ 不要在这里配置能力模块的 meta-data! -->
-    <meta-data android:name="JPUSH_APPKEY" ... />
-</application>
-```
-
-```groovy
-// app/build.gradle
-// ❌ 不要在这里配置能力模块的参数!
-manifestPlaceholders = [
-    XIAOMI_APPID: "..."
-]
-```
-
----
-
-## 📦 依赖管理规范
-
-### 1. 依赖声明
-
-**每个能力模块在自己的 `build.gradle` 中声明依赖**
-
-#### ✅ 正确做法
-
-```groovy
-// capability-share/build.gradle
-dependencies {
-    // 使用 api 让依赖传递到 app 模块
-    api("com.tencent.mm.opensdk:wechat-sdk-android:6.8.24")
-    api(files('libs/umeng-share-wechat-full-7.3.7.jar'))
-}
-```
-
-```groovy
-// app/build.gradle
-dependencies {
-    // 只需要依赖能力模块,不需要重复声明能力模块的依赖
-    implementation project(':capability-share')
-    // ❌ 不要在这里重复声明微信 SDK!
-}
-```
-
-#### ❌ 错误做法
-
-```groovy
-// app/build.gradle
-dependencies {
-    implementation project(':capability-share')
-    // ❌ 不要重复声明能力模块的依赖!
-    implementation("com.tencent.mm.opensdk:wechat-sdk-android:6.8.24")
-}
-```
-
-### 2. 依赖传递规则
-
-| 依赖类型 | 是否传递到 app 模块 | 使用场景 |
-|---------|-------------------|---------|
-| `api` | ✅ 是 | 需要暴露给 app 模块使用的依赖(如 SDK) |
-| `implementation` | ❌ 否 | 模块内部使用的依赖 |
-
-**规则:如果 app 模块需要使用某个依赖,能力模块必须使用 `api` 声明**
-
----
-
-## 🚫 禁止事项
-
-### ❌ 禁止在 app 模块中做的事情
-
-1. **禁止在 app 模块的 `strings.xml` 中配置能力模块的参数**
-   ```xml
-   <!-- ❌ 禁止 -->
-   <string name="jpush_app_key">...</string>
-   <string name="share_umeng_app_key">...</string>
-   ```
-
-2. **禁止在 app 模块的 `AndroidManifest.xml` 中配置能力模块的 meta-data**
-   ```xml
-   <!-- ❌ 禁止 -->
-   <meta-data android:name="JPUSH_APPKEY" ... />
-   ```
-
-3. **禁止在 app 模块的 `build.gradle` 中重复声明能力模块的依赖**
-   ```groovy
-   // ❌ 禁止
-   implementation("com.tencent.mm.opensdk:wechat-sdk-android:6.8.24")
-   ```
-
-4. **禁止在 app 模块的 `build.gradle` 中使用 XML 解析读取配置**
-   ```groovy
-   // ❌ 禁止
-   def xml = new XmlParser().parse(resFile)
-   manifestPlaceholders = [...]
-   ```
-
-5. **禁止在 app 模块中管理能力模块的内部逻辑**
-
----
-
-## ✅ 正确做法检查清单
-
-创建新能力模块时,请按以下清单检查:
-
-### 配置管理
-- [ ] 在 `capability-xxx/src/main/res/values/strings.xml` 中创建配置
-- [ ] 在 `capability-xxx/src/main/AndroidManifest.xml` 中使用 `@string/` 引用配置
-- [ ] 不在 app 模块的 `strings.xml` 中添加能力模块的配置
-- [ ] 不在 app 模块的 `AndroidManifest.xml` 中配置能力模块的 meta-data
-
-### 依赖管理
-- [ ] 在 `capability-xxx/build.gradle` 中声明所有依赖
-- [ ] 需要暴露给 app 的依赖使用 `api`
-- [ ] 模块内部依赖使用 `implementation`
-- [ ] 不在 app 模块的 `build.gradle` 中重复声明能力模块的依赖
-
-### 代码管理
-- [ ] 能力模块的代码完全封装在模块内部
-- [ ] 通过 Factory 模式暴露接口给 app 模块
-- [ ] app 模块只调用能力模块的公开接口
-
----
-
-## 📝 示例:创建新能力模块
-
-### 步骤 1:创建模块结构
-
-```
-capability-new/
-├── build.gradle
-├── src/main/
-│   ├── AndroidManifest.xml
-│   ├── res/values/strings.xml
-│   └── java/...
-└── libs/(如果需要)
-```
-
-### 步骤 2:创建 strings.xml
-
-```xml
-<!-- capability-new/src/main/res/values/strings.xml -->
-<resources>
-    <string name="new_module_config_key">your_config_value_here</string>
-</resources>
-```
-
-### 步骤 3:在 AndroidManifest.xml 中使用
-
-```xml
-<!-- capability-new/src/main/AndroidManifest.xml -->
-<application>
-    <meta-data
-        android:name="NEW_MODULE_KEY"
-        android:value="@string/new_module_config_key" />
-</application>
-```
-
-### 步骤 4:在 build.gradle 中声明依赖
-
-```groovy
-// capability-new/build.gradle
-dependencies {
-    // 需要暴露给 app 的依赖使用 api
-    api("com.example:sdk:1.0.0")
-    
-    // 模块内部依赖使用 implementation
-    implementation("com.example:internal-lib:1.0.0")
-}
-```
-
-### 步骤 5:在 app 模块中引用
-
-```groovy
-// app/build.gradle
-dependencies {
-    // 只需要依赖能力模块,不需要重复声明能力模块的依赖
-    implementation project(':capability-new')
-}
-```
-
----
-
-## 🔍 常见问题
-
-### Q1: 为什么能力模块的依赖要用 `api` 而不是 `implementation`?
-
-**A:** 因为 app 模块在运行时需要这些依赖(如微信 SDK),如果使用 `implementation`,依赖不会传递到 app 模块,会导致运行时找不到类。
-
-### Q2: 能力模块的 `strings.xml` 中的资源,app 模块能访问吗?
-
-**A:** 可以。Android 构建系统会合并所有模块的资源,app 模块可以通过 `context.resources.getIdentifier()` 访问能力模块的资源。
-
-### Q3: 如果能力模块需要读取配置,应该怎么做?
-
-**A:** 在能力模块的代码中使用 Android 标准的资源 API:
-
-```kotlin
-// 在能力模块的代码中
-val resources = context.resources
-val resId = resources.getIdentifier("config_key", "string", context.packageName)
-val value = resources.getString(resId)
-```
-
-**不要使用 XML 解析!**
-
-### Q4: app 模块的 `strings.xml` 应该放什么?
-
-**A:** 只放 app 模块自己的配置,如:
-- `app_name`
-- app 模块特有的配置
-
-**不要放能力模块的配置!**
-
----
-
-## 📚 参考
-
-### 当前项目中的正确示例
-
-1. **capability-push 模块**
-   - ✅ 配置:`capability-push/src/main/res/values/strings.xml`
-   - ✅ AndroidManifest:`capability-push/src/main/AndroidManifest.xml`
-   - ✅ 依赖:`capability-push/build.gradle`
-
-2. **capability-share 模块**
-   - ✅ 配置:`capability-share/src/main/res/values/strings.xml`
-   - ✅ AndroidManifest:`capability-share/src/main/AndroidManifest.xml`
-   - ✅ 依赖:`capability-share/build.gradle`(使用 `api` 传递依赖)
-
----
-
-## 🎯 总结
-
-**记住一句话:每个能力模块都是独立的,自己管理自己的所有事情,app 模块只负责组装,不负责管理!**
-
-- ✅ 配置 → 能力模块的 `strings.xml`
-- ✅ AndroidManifest → 能力模块的 `AndroidManifest.xml`
-- ✅ 依赖 → 能力模块的 `build.gradle`(使用 `api` 传递)
-- ✅ 代码 → 能力模块的 `java/` 目录
-
-**app 模块只做一件事:`implementation project(':capability-xxx')`**
-
----
-
----
-
-## 💻 代码开发规范
-
-### 1. 接口设计规范
-
-#### ✅ 必须定义接口(API)
-
-每个能力模块必须定义清晰的接口,实现类封装在内部:
-
-```kotlin
-// capability-xxx/src/main/java/.../api/XxxService.kt
-interface XxxService {
-    fun initialize(context: Context, config: XxxConfig)
-    fun doSomething(): XxxResponse
-    // ...
-}
-```
-
-#### ✅ 实现类使用 internal 或 private
-
-```kotlin
-// capability-xxx/src/main/java/.../impl/XxxServiceImpl.kt
-internal class XxxServiceImpl : XxxService {
-    // 实现细节
-}
-```
-
-#### ❌ 禁止直接暴露实现类
-
-```kotlin
-// ❌ 禁止
-class XxxServiceImpl : XxxService { ... }  // 不要用 public
-```
-
-### 2. Factory 模式规范
-
-**每个能力模块必须使用 Factory 模式提供单例服务**
-
-#### ✅ 标准 Factory 结构
-
-```kotlin
-// capability-xxx/src/main/java/.../factory/XxxServiceFactory.kt
-object XxxServiceFactory {
-    @Volatile
-    private var instance: XxxService? = null
-    
-    /**
-     * 初始化服务(全局单例)
-     * @param context 应用上下文
-     * @param config 配置(可选,默认从资源文件读取)
-     */
-    @JvmStatic
-    fun init(context: Context, config: XxxConfig? = null) {
-        if (instance == null) {
-            synchronized(this) {
-                if (instance == null) {
-                    val finalConfig = config ?: XxxConfig.fromResources(context)
-                    instance = XxxServiceImpl().apply {
-                        initialize(context, finalConfig)
-                    }
-                }
-            }
-        }
-    }
-    
-    /**
-     * 获取服务实例(必须在 init 之后调用)
-     */
-    @JvmStatic
-    fun getInstance(): XxxService {
-        return instance ?: throw IllegalStateException(
-            "XxxService 未初始化,请先调用 XxxServiceFactory.init()"
-        )
-    }
-}
-```
-
-#### ✅ 使用示例
-
-```kotlin
-// 在 Application 中初始化
-class MyApplication : Application() {
-    override fun onCreate() {
-        super.onCreate()
-        XxxServiceFactory.init(applicationContext)
-    }
-}
-
-// 在业务代码中使用
-val service = XxxServiceFactory.getInstance()
-service.doSomething()
-```
-
-### 3. 配置类设计规范
-
-#### ✅ 配置类必须支持从资源文件读取
-
-```kotlin
-// capability-xxx/src/main/java/.../model/XxxConfig.kt
-data class XxxConfig(
-    val appKey: String,
-    val channel: String = "developer-default"
-) {
-    companion object {
-        /**
-         * 从资源文件读取配置
-         * 资源文件:capability-xxx/src/main/res/values/strings.xml
-         */
-        @JvmStatic
-        fun fromResources(context: Context): XxxConfig {
-            val resources = context.resources
-            val packageName = context.packageName
-            
-            fun getString(name: String): String? {
-                val resId = resources.getIdentifier(name, "string", packageName)
-                return if (resId != 0) resources.getString(resId) else null
-            }
-            
-            val appKey = getString("xxx_app_key") 
-                ?: throw IllegalStateException("未配置 xxx_app_key")
-            val channel = getString("xxx_channel") ?: "developer-default"
-            
-            return XxxConfig(appKey = appKey, channel = channel)
-        }
-    }
-}
-```
-
-#### ❌ 禁止使用 XML 解析
-
-```kotlin
-// ❌ 禁止在代码中解析 XML
-val xml = XmlParser().parse(file)
-```
-
-### 4. 响应模型规范
-
-#### ✅ 统一的响应模型
-
-```kotlin
-// capability-xxx/src/main/java/.../model/XxxResponse.kt
-data class XxxResponse(
-    val success: Boolean,
-    val data: Any? = null,
-    val errorMessage: String? = null,
-    val timestamp: Long = System.currentTimeMillis()
-)
-```
-
-### 5. 错误处理规范
-
-#### ✅ 必须处理异常,返回统一的响应
-
-```kotlin
-override fun doSomething(): XxxResponse {
-    return try {
-        // 业务逻辑
-        XxxResponse(success = true, data = result)
-    } catch (e: Exception) {
-        ILog.e(tag, "操作失败", e)
-        XxxResponse(
-            success = false,
-            errorMessage = e.message ?: "未知错误"
-        )
-    }
-}
-```
-
-#### ❌ 禁止抛出未处理的异常
-
-```kotlin
-// ❌ 禁止
-override fun doSomething() {
-    throw Exception("错误")  // 必须捕获并返回 Response
-}
-```
-
----
-
-## 📝 日志规范
-
-### 1. 使用统一的日志接口
-
-**所有能力模块必须使用 `base-core` 模块的 `ILog` 接口**
-
-#### ✅ 正确做法
-
-```kotlin
-import com.narutohuo.xindazhou.core.log.ILog
-
-class XxxServiceImpl {
-    private val tag = "XxxService"
-    
-    fun doSomething() {
-        ILog.d(tag, "开始执行操作")
-        try {
-            // ...
-            ILog.d(tag, "操作成功")
-        } catch (e: Exception) {
-            ILog.e(tag, "操作失败", e)
-        }
-    }
-}
-```
-
-#### ❌ 禁止直接使用 Android Log
-
-```kotlin
-// ❌ 禁止
-import android.util.Log
-Log.d("Tag", "message")
-```
-
-### 2. 日志级别规范
-
-| 级别 | 使用场景 | 示例 |
-|------|---------|------|
-| `ILog.d()` | 调试信息、流程跟踪 | "开始初始化"、"收到回调" |
-| `ILog.i()` | 重要信息 | "服务初始化成功" |
-| `ILog.w()` | 警告信息 | "配置缺失,使用默认值" |
-| `ILog.e()` | 错误信息(必须带异常) | "初始化失败", exception |
-
-### 3. Tag 命名规范
-
-```kotlin
-// ✅ 使用类名或模块名
-private val tag = "XxxService"
-private val tag = "XxxServiceImpl"
-private val tag = "XxxReceiver"
-```
-
----
-
-## 🔨 编译配置规范
-
-### 1. build.gradle 配置
-
-#### ✅ 标准配置结构
-
-```groovy
-plugins {
-    alias(libs.plugins.kotlin.android)
-    id("com.android.library")  // 能力模块必须是 library
-}
-
-android {
-    namespace = "com.narutohuo.xindazhou.xxx"  // 模块自己的 namespace
-    compileSdk = 36
-
-    defaultConfig {
-        minSdk = 26
-    }
-
-    compileOptions {
-        sourceCompatibility = JavaVersion.VERSION_17
-        targetCompatibility = JavaVersion.VERSION_17
-    }
-    
-    kotlinOptions {
-        jvmTarget = "17"
-    }
-}
-
-repositories {
-    flatDir {
-        dirs 'libs'  // 本地 SDK 文件
-    }
-    mavenCentral()
-    google()
-}
-
-dependencies {
-    // 1. 依赖 base-core(所有能力模块都依赖)
-    implementation(project(":base-core"))
-    
-    // 2. AndroidX 基础依赖
-    implementation(libs.androidx.core.ktx)
-    
-    // 3. 模块特定的依赖
-    // 需要暴露给 app 的依赖使用 api
-    api("com.example:sdk:1.0.0")
-    // 模块内部依赖使用 implementation
-    implementation("com.example:internal-lib:1.0.0")
-    
-    // 4. 本地 SDK 文件
-    implementation(files('libs/xxx-sdk.jar'))
-    implementation(name: 'xxx-sdk', ext: 'aar')
-}
-```
-
-#### ❌ 禁止事项
-
-```groovy
-// ❌ 禁止使用 application 插件
-plugins {
-    id("com.android.application")  // 能力模块必须是 library
-}
-
-// ❌ 禁止在能力模块中配置 applicationId
-defaultConfig {
-    applicationId "..."  // 只有 app 模块才有
-}
-```
-
-### 2. AndroidManifest.xml 配置
-
-#### ✅ 标准结构
-
-```xml
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-    
-    <!-- 模块需要的权限 -->
-    <uses-permission android:name="android.permission.INTERNET" />
-    
-    <application>
-        <!-- 模块的 Service、Receiver、Activity 等 -->
-        <!-- 使用本模块的 @string/ 资源 -->
-        <meta-data
-            android:name="XXX_KEY"
-            android:value="@string/xxx_config_key" />
-    </application>
-</manifest>
-```
-
-### 3. ProGuard 规则
-
-**如果模块使用了第三方 SDK,必须在模块的 `proguard-rules.pro` 中添加规则**
-
-```proguard
-# capability-xxx/proguard-rules.pro
--keep class com.example.sdk.** { *; }
--dontwarn com.example.sdk.**
-```
-
----
-
-## 🧪 测试规范
-
-### 1. 单元测试
-
-**每个能力模块应该有自己的单元测试**
-
-```
-capability-xxx/
-└── src/test/
-    └── java/.../XxxServiceTest.kt
-```
-
-### 2. 集成测试
-
-**在 app 模块中进行集成测试**
-
-```
-app/
-└── src/androidTest/
-    └── java/.../XxxServiceIntegrationTest.kt
-```
-
----
-
-## 📦 版本管理规范
-
-### 1. SDK 版本管理
-
-**所有 SDK 版本统一在 `gradle/libs.versions.toml` 中管理**
-
-```toml
-[versions]
-androidx-core = "1.12.0"
-retrofit = "2.9.0"
-
-[libraries]
-androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core" }
-```
-
-### 2. 模块版本号
-
-**能力模块不需要版本号(因为是内部模块)**
-
-```groovy
-// ❌ 不需要
-version = "1.0.0"
-```
-
----
-
-## 🔍 代码审查检查清单
-
-### 创建新能力模块时检查
-
-- [ ] **模块结构**
-  - [ ] 有 `strings.xml` 配置文件
-  - [ ] 有 `AndroidManifest.xml`
-  - [ ] 有 `build.gradle`(使用 `library` 插件)
-
-- [ ] **接口设计**
-  - [ ] 定义了清晰的 API 接口
-  - [ ] 实现类使用 `internal` 或 `private`
-  - [ ] 使用 Factory 模式提供单例
-
-- [ ] **配置管理**
-  - [ ] 配置在模块自己的 `strings.xml` 中
-  - [ ] AndroidManifest 使用 `@string/` 引用
-  - [ ] 配置类支持从资源文件读取
-
-- [ ] **依赖管理**
-  - [ ] 依赖在模块自己的 `build.gradle` 中
-  - [ ] 需要暴露的依赖使用 `api`
-  - [ ] app 模块不重复声明依赖
-
-- [ ] **日志规范**
-  - [ ] 使用 `ILog` 接口
-  - [ ] 不使用 `android.util.Log`
-  - [ ] Tag 命名规范
-
-- [ ] **错误处理**
-  - [ ] 所有异常都被捕获
-  - [ ] 返回统一的 Response 模型
-  - [ ] 不抛出未处理的异常
-
----
-
-## 🚨 常见错误和解决方案
-
-### 错误 1:运行时找不到类
-
-**原因**:依赖使用了 `implementation` 而不是 `api`
-
-**解决**:
-```groovy
-// 改为 api
-api("com.example:sdk:1.0.0")
-```
-
-### 错误 2:找不到资源
-
-**原因**:在 app 模块的 `strings.xml` 中配置了能力模块的资源
-
-**解决**:移到能力模块自己的 `strings.xml` 中
-
-### 错误 3:编译错误:unable to resolve class
-
-**原因**:依赖没有正确传递
-
-**解决**:
-1. 检查能力模块的依赖是否使用 `api`
-2. 检查 app 模块是否正确依赖了能力模块
-
-### 错误 4:配置读取失败
-
-**原因**:使用了 XML 解析而不是 Android 资源 API
-
-**解决**:
-```kotlin
-// ✅ 正确
-val resId = resources.getIdentifier("key", "string", packageName)
-val value = resources.getString(resId)
-
-// ❌ 错误
-val xml = XmlParser().parse(file)
-```
-
----
-
-## 📚 参考示例
-
-### 当前项目中的标准实现
-
-1. **capability-push 模块**
-   - ✅ Factory: `PushServiceFactory`
-   - ✅ API: `PushService`
-   - ✅ Config: `PushConfig.fromResources()`
-   - ✅ 配置: `capability-push/src/main/res/values/strings.xml`
-
-2. **capability-share 模块**
-   - ✅ Factory: `ShareServiceFactory`
-   - ✅ API: `ShareService`
-   - ✅ Config: `ShareConfig.fromResources()`
-   - ✅ 配置: `capability-share/src/main/res/values/strings.xml`
-
----
-
-## 🎯 总结
-
-### 核心原则(再次强调)
-
-1. **独立性**:每个能力模块完全独立,不依赖 app 模块
-2. **封装性**:实现细节封装在模块内部,只暴露接口
-3. **统一性**:使用统一的 Factory 模式、日志接口、响应模型
-4. **规范性**:遵循统一的代码规范和目录结构
-
-### 开发流程
-
-1. 创建模块目录结构
-2. 定义 API 接口
-3. 实现服务类(internal)
-4. 创建 Factory(单例)
-5. 创建配置类(支持从资源读取)
-6. 创建 `strings.xml` 配置文件
-7. 配置 `AndroidManifest.xml`
-8. 配置 `build.gradle`(依赖使用 `api`)
-9. 在 app 模块中依赖:`implementation project(':capability-xxx')`
-10. 在 Application 中初始化:`XxxServiceFactory.init(context)`
-
----
-
-**最后更新:2024年**
-