Initial commit: 91dj android client dev_1.0.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
import 'dart:developer' as developer;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
/// 日志级别枚举
|
||||
enum LogLevel {
|
||||
debug,
|
||||
info,
|
||||
warn,
|
||||
error,
|
||||
}
|
||||
|
||||
/// 日志工具类:统一管理 SDK 中的所有日志输出
|
||||
class Logger {
|
||||
Logger._();
|
||||
|
||||
/// 是否启用日志(默认:仅在 debug 模式下启用)
|
||||
static bool enabled = false;
|
||||
|
||||
/// 外部日志回调(可选)。
|
||||
/// 注册后,所有 SDK 日志在控制台输出的同时也会转发给此回调。
|
||||
/// 示例:在 example app 中将 SDK 内部日志显示到 UI 面板。
|
||||
static void Function(String message, LogLevel level)? onLog;
|
||||
|
||||
/// 测试专用:替换 dart:developer.log,便于验证长日志走 developer log。
|
||||
@visibleForTesting
|
||||
static void Function(String message, {String name})? developerLogWriterForTest;
|
||||
|
||||
/// 测试专用:替换 debugPrint,便于验证长日志分片输出到控制台/logcat。
|
||||
@visibleForTesting
|
||||
static void Function(String message)? consoleLogWriterForTest;
|
||||
|
||||
/// Android logcat 单行有长度限制,保守按字符分片,避免超长 JSON 被截断。
|
||||
static const int _consoleChunkSize = 800;
|
||||
|
||||
/// 日志标签映射
|
||||
static const Map<String, String> _tags = {
|
||||
'AnalyticsSdk': '[AnalyticsSdk]',
|
||||
'DomainManager': '[DomainManager]',
|
||||
'EventTypeConfigManager': '[EventTypeConfigManager]',
|
||||
'GlobalClick': '[GlobalClick]',
|
||||
'AdImpressionManager': '[AdImpressionManager]',
|
||||
'PageLifecycleObserver': '[PageLifecycleObserver]',
|
||||
'InitConfigResult': '[InitConfigResult]',
|
||||
};
|
||||
|
||||
/// 获取日志标签
|
||||
static String _getTag(String tag) {
|
||||
return _tags[tag] ?? '[$tag]';
|
||||
}
|
||||
|
||||
/// 格式化日志消息
|
||||
static String _formatMessage(String tag, String message) {
|
||||
return '${_getTag(tag)} $message';
|
||||
}
|
||||
|
||||
/// 输出到 Flutter 控制台;Android 上会进入 logcat 的 flutter 日志流。
|
||||
static void _writeConsole(String message) {
|
||||
final writer = consoleLogWriterForTest;
|
||||
if (writer != null) {
|
||||
writer(message);
|
||||
} else {
|
||||
debugPrint(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// 分片输出超长日志,避免 logcat / IDE 控制台按单行截断。
|
||||
static void _writeConsoleMessage(String tag, String message) {
|
||||
if (message.length <= _consoleChunkSize) {
|
||||
_writeConsole(_formatMessage(tag, message));
|
||||
return;
|
||||
}
|
||||
|
||||
final tagPrefix = _getTag(tag);
|
||||
final total = (message.length + _consoleChunkSize - 1) ~/ _consoleChunkSize;
|
||||
for (var index = 0; index < total; index++) {
|
||||
final start = index * _consoleChunkSize;
|
||||
final end = (start + _consoleChunkSize < message.length) ? start + _consoleChunkSize : message.length;
|
||||
_writeConsole(
|
||||
'$tagPrefix part ${index + 1}/$total: ${message.substring(start, end)}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 输出调试日志
|
||||
static void debug(String tag, String message) {
|
||||
if (enabled) {
|
||||
final msg = _formatMessage(tag, message);
|
||||
_writeConsoleMessage(tag, message);
|
||||
try {
|
||||
onLog?.call(msg, LogLevel.debug);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 输出信息日志
|
||||
static void info(String tag, String message) {
|
||||
if (enabled) {
|
||||
final msg = _formatMessage(tag, message);
|
||||
_writeConsoleMessage(tag, message);
|
||||
try {
|
||||
onLog?.call(msg, LogLevel.info);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 输出警告日志
|
||||
static void warn(String tag, String message) {
|
||||
if (enabled) {
|
||||
final formattedMessage = '⚠️ $message';
|
||||
final msg = _formatMessage(tag, formattedMessage);
|
||||
_writeConsoleMessage(tag, formattedMessage);
|
||||
try {
|
||||
onLog?.call(msg, LogLevel.warn);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 输出错误日志
|
||||
static void error(String tag, String message, [Object? error, StackTrace? stackTrace]) {
|
||||
if (enabled) {
|
||||
final errorInfo = error != null ? ', 错误: $error' : '';
|
||||
final stackInfo = stackTrace != null ? '\n堆栈: $stackTrace' : '';
|
||||
final formattedMessage = '❌ $message$errorInfo$stackInfo';
|
||||
final msg = _formatMessage(tag, formattedMessage);
|
||||
_writeConsoleMessage(tag, formattedMessage);
|
||||
try {
|
||||
onLog?.call(msg, LogLevel.error);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 输出日志(自动判断级别)
|
||||
static void log(String tag, String message, {LogLevel level = LogLevel.debug}) {
|
||||
switch (level) {
|
||||
case LogLevel.debug:
|
||||
debug(tag, message);
|
||||
break;
|
||||
case LogLevel.info:
|
||||
info(tag, message);
|
||||
break;
|
||||
case LogLevel.warn:
|
||||
warn(tag, message);
|
||||
break;
|
||||
case LogLevel.error:
|
||||
error(tag, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// 输出 developer log。
|
||||
///
|
||||
/// 长 JSON 等需要完整复制的日志使用此入口。
|
||||
///
|
||||
/// developer.log 保留完整单条内容给 DevTools;控制台/logcat 使用分片,避免单行截断。
|
||||
static void developerLog(
|
||||
String tag,
|
||||
String message, {
|
||||
LogLevel level = LogLevel.debug,
|
||||
}) {
|
||||
if (enabled) {
|
||||
final msg = _formatMessage(tag, message);
|
||||
final writer = developerLogWriterForTest;
|
||||
if (writer != null) {
|
||||
writer(msg, name: tag);
|
||||
} else {
|
||||
developer.log(msg, name: tag);
|
||||
}
|
||||
_writeConsoleMessage(tag, message);
|
||||
try {
|
||||
onLog?.call(msg, level);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 便捷方法:AnalyticsSdk 日志
|
||||
static void analyticsSdk(String message, {LogLevel level = LogLevel.debug}) {
|
||||
log('AnalyticsSdk', message, level: level);
|
||||
}
|
||||
|
||||
/// 便捷方法:AnalyticsSdk developer log
|
||||
static void analyticsSdkDeveloperLog(
|
||||
String message, {
|
||||
LogLevel level = LogLevel.debug,
|
||||
}) {
|
||||
developerLog('AnalyticsSdk', message, level: level);
|
||||
}
|
||||
|
||||
/// 便捷方法:DomainManager 日志
|
||||
static void domainManager(String message, {LogLevel level = LogLevel.debug}) {
|
||||
log('DomainManager', message, level: level);
|
||||
}
|
||||
|
||||
/// 便捷方法:EventTypeConfigManager 日志
|
||||
static void eventTypeConfigManager(String message, {LogLevel level = LogLevel.debug}) {
|
||||
log('EventTypeConfigManager', message, level: level);
|
||||
}
|
||||
|
||||
/// 便捷方法:GlobalClick 日志
|
||||
static void globalClick(String message, {LogLevel level = LogLevel.debug}) {
|
||||
log('GlobalClick', message, level: level);
|
||||
}
|
||||
|
||||
/// 便捷方法:AdImpressionManager 日志
|
||||
static void adImpressionManager(String message, {LogLevel level = LogLevel.debug}) {
|
||||
log('AdImpressionManager', message, level: level);
|
||||
}
|
||||
|
||||
/// 便捷方法:PageLifecycleObserver 日志
|
||||
static void pageLifecycleObserver(String message, {LogLevel level = LogLevel.debug}) {
|
||||
log('PageLifecycleObserver', message, level: level);
|
||||
}
|
||||
|
||||
/// 便捷方法:InitConfigResult 日志
|
||||
static void initConfigResult(String message, {LogLevel level = LogLevel.debug}) {
|
||||
log('InitConfigResult', message, level: level);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user