feat(sdk): 同步 iOS — 日志等级 logLevel 配置化(默认 OFF)

BleLog 之前所有调用都无条件 Log.d/i/w/e,集成方没法关。新增
public enum BleLogLevel(OFF/ERROR/WARN/INFO/DEBUG),通过
DuooomiBleConfig.logLevel 传入,DuooomiBleSDK init 块第一行写入
BleLog.level。默认 OFF 保证对外集成默认静默。

frameIntervalMs 越界 warn 从 DuooomiBleConfig.init 挪到
DuooomiBleSDK init 内、level 设置之后,避免在 level 写入前丢日志。

平台差异:Android 没有 iOS 的 #if DEBUG 编译期消除;默认 OFF 已足够
静默,如需硬剥离 android.util.Log 可在宿主 ProGuard/R8 加
-assumenosideeffects(README 已说明)。

对齐 ios:6ed3c55。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
km2023
2026-05-20 16:04:27 +08:00
parent f686fa0b95
commit 6bdfa4d39a
4 changed files with 60 additions and 13 deletions

View File

@@ -100,6 +100,7 @@ val sdk = DuooomiBleSDK(
apiKey = "YOUR_API_KEY",
brand = "YOUR_BRAND", // 设备品牌名,所有 RPC 必带
scanNamePrefix = "Duooomi-" // 扫描时按广播名前缀过滤
// logLevel = BleLogLevel.OFF // 日志等级,默认 OFF完全静默排查时改 DEBUG
)
)
```
@@ -115,6 +116,26 @@ val sdk = DuooomiBleSDK(
| `cdnHost` | | 默认 `https://cdn.bowong.cc/` |
| `aniWidth` / `aniHeight` / `aniFps` | | ANI 转换参数,默认 `360 / 360 / "24"` |
| `frameIntervalMs` | | 协议帧之间发送间隔ms默认 `35`,合法 `[0, 500]`;越界仅 warn使用点 `coerceIn`。调高用于排查接收端丢帧 |
| `logLevel` | | 日志等级(`BleLogLevel.OFF/ERROR/WARN/INFO/DEBUG`),默认 `OFF`。详见下文 |
### 5. 日志BleLogLevel
SDK 内部所有日志统一走 `BleLog``android.util.Log`,分级 `OFF / ERROR / WARN / INFO / DEBUG`。集成方通过 `config.logLevel` 控制输出:
```kotlin
// 对外发布:什么都不传,默认完全静默
DuooomiBleSDK(context, DuooomiBleConfig(apiKey = "...", brand = "...", scanNamePrefix = "..."))
// 本地排查:开 DEBUG 看到所有 BLE 帧、RPC opId、传输进度等
DuooomiBleSDK(context, DuooomiBleConfig(
apiKey = "...", brand = "...", scanNamePrefix = "...",
logLevel = BleLogLevel.DEBUG
))
```
- 等级单调:`WARN` 输出 warn + error`INFO` 输出 info + warn + error以此类推。
- 日志按 category 分桶:`SDK / Scan / Connect / BLE / RPC / Command / Transfer / Firmware / Protocol / Decode / Config`Logcat 按 tag `DuooomiBleSDK` + `[<category>]` 过滤。
- **Release 包剥离 `Log.d/i`**Android 平台没有 iOS `#if DEBUG` 那样的编译期消除,默认 `OFF` 已足够静默;如需彻底剥离 `android.util.Log` 调用,可在宿主 ProGuard/R8 配置中加 `-assumenosideeffects class android.util.Log { public static *** d(...); public static *** i(...); }`
## API 参考

View File

@@ -1,6 +1,6 @@
package com.duooomi.ble
import com.duooomi.ble.utils.BleLog
import com.duooomi.ble.utils.BleLogLevel
/**
* SDK 全局配置,在初始化时一次性传入。
@@ -26,14 +26,12 @@ data class DuooomiBleConfig(
* 协议帧之间的发送间隔(毫秒)。合法区间 `[0, 500]`,越界仅 warn使用点会 clamp。
* 集成方一般无需调整;调高用于排查接收端丢帧/拥塞。默认 35。
*/
val frameIntervalMs: Int = 35
val frameIntervalMs: Int = 35,
/**
* SDK 日志等级。默认 [BleLogLevel.OFF],对外发布完全静默;排查时改 [BleLogLevel.WARN] 或 [BleLogLevel.DEBUG]。
*/
val logLevel: BleLogLevel = BleLogLevel.OFF
) {
init {
if (frameIntervalMs !in 0..500) {
BleLog.w("frameIntervalMs=$frameIntervalMs out of [0,500], will clamp at use site", "Config")
}
}
val normalizedCdnHost: String
get() = if (cdnHost.endsWith("/")) cdnHost else "$cdnHost/"
}

View File

@@ -97,7 +97,11 @@ class DuooomiBleSDK(context: Context, val config: DuooomiBleConfig) {
private var flushJob: Job? = null
init {
BleLog.i("SDK initialized (apiHost=${config.apiHost}, brand=${config.brand})", "SDK")
BleLog.level = config.logLevel
BleLog.i("SDK initialized (apiHost=${config.apiHost}, brand=${config.brand}, logLevel=${config.logLevel})", "SDK")
if (config.frameIntervalMs !in 0..500) {
BleLog.w("frameIntervalMs=${config.frameIntervalMs} out of [0,500], will clamp at use site", "Config")
}
setupDisconnectHandler()
protocolService.rawJsonEmitter = { evt -> _rawJsonEvents.tryEmit(evt) }
// 启动时把持久化记录回放到 StateFlow

View File

@@ -2,22 +2,46 @@ package com.duooomi.ble.utils
import android.util.Log
/**
* SDK 日志等级。集成方通过 [com.duooomi.ble.DuooomiBleConfig.logLevel] 设定。
* 默认 [OFF],对外发布完全静默;排查时改 [WARN] 或 [DEBUG]。
*/
enum class BleLogLevel(internal val priority: Int) {
OFF(0),
ERROR(1),
WARN(2),
INFO(3),
DEBUG(4)
}
internal object BleLog {
private const val TAG = "DuooomiBleSDK"
/** 由 [com.duooomi.ble.DuooomiBleSDK] init 块写入;默认 [BleLogLevel.OFF]。 */
@Volatile
var level: BleLogLevel = BleLogLevel.OFF
fun d(message: String, category: String = "General") {
Log.d(TAG, "[$category] $message")
if (level.priority >= BleLogLevel.DEBUG.priority) {
Log.d(TAG, "[$category] $message")
}
}
fun i(message: String, category: String = "General") {
Log.i(TAG, "[$category] $message")
if (level.priority >= BleLogLevel.INFO.priority) {
Log.i(TAG, "[$category] $message")
}
}
fun w(message: String, category: String = "General") {
Log.w(TAG, "[$category] $message")
if (level.priority >= BleLogLevel.WARN.priority) {
Log.w(TAG, "[$category] $message")
}
}
fun e(message: String, category: String = "General") {
Log.e(TAG, "[$category] $message")
if (level.priority >= BleLogLevel.ERROR.priority) {
Log.e(TAG, "[$category] $message")
}
}
}