Initial commit: 91dj android client dev_1.0.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
谢宇宁
2026-10-08 11:37:25 +07:00
co-authored by Claude Opus 5.5
commit 97dd6a739a
1262 changed files with 119813 additions and 0 deletions
@@ -0,0 +1,105 @@
import 'package:analytics_sdk/config/sdk_config.dart';
import 'package:analytics_sdk/utils/logger.dart';
/// 广告展示去重管理器
///
/// 以页面为粒度做去重:同一页面访问内不重复上报同一广告,
/// 页面退出后去重状态随之清除,下次进入同一页面广告可重新上报。
/// 新 session 时调用 [clear] 清除所有页面记录。
class AdImpressionManager {
static final AdImpressionManager instance = AdImpressionManager._internal();
factory AdImpressionManager() => instance;
AdImpressionManager._internal();
/// 页面级广告去重表:pageKey → 已上报 adId 集合
final Map<String, Set<String>> _reportedAdIdsByPage = {};
/// 广告 SDK 曝光已上报的 trace_id;同一 session 内全局去重。
final Set<String> _reportedSdkTraceIds = {};
/// 当前已存储的广告ID总数(跨所有页面)
int get reportedCount =>
_reportedAdIdsByPage.values.fold(0, (sum, s) => sum + s.length);
/// 批量检查多个广告ID,返回在指定页面内尚未上报的列表(不修改状态)
List<String> getUnreportedAdIds(String adIds, {required String pageKey}) {
if (adIds.isEmpty) return [];
final adIdList = adIds
.split(',')
.map((id) => id.trim())
.where((id) => id.isNotEmpty)
.toList();
if (adIdList.isEmpty) return [];
final pageSet = _reportedAdIdsByPage[pageKey];
if (pageSet == null || pageSet.isEmpty) return adIdList;
return adIdList.where((id) => !pageSet.contains(id)).toList();
}
/// 在指定页面内批量标记广告ID为已上报
void markAsReportedBatch(String adIds, {required String pageKey}) {
if (adIds.isEmpty) return;
final adIdList =
adIds.split(',').map((id) => id.trim()).where((id) => id.isNotEmpty);
final pageSet = _reportedAdIdsByPage.putIfAbsent(pageKey, () => {});
for (final id in adIdList) {
if (reportedCount >= SdkConfig.maxAdImpressionCapacity) {
Logger.adImpressionManager(
'广告去重表已达上限(${SdkConfig.maxAdImpressionCapacity}),停止写入,跳过 id: $id',
level: LogLevel.warn);
break;
}
pageSet.add(id);
}
}
/// 指定 trace_id 是否已作为广告 SDK 曝光上报。
bool isSdkTraceReported(String traceId) {
return _reportedSdkTraceIds.contains(traceId.trim());
}
/// 在广告 SDK 曝光成功入队后标记其 trace_id。
void markSdkTraceReported(String traceId) {
final normalized = traceId.trim();
if (normalized.isEmpty || isSdkTraceReported(normalized)) return;
if (_reportedSdkTraceIds.length >= SdkConfig.maxAdImpressionCapacity) {
Logger.adImpressionManager(
'广告 SDK 曝光 trace_id 去重表已达上限(${SdkConfig.maxAdImpressionCapacity}),停止写入: $normalized',
level: LogLevel.warn,
);
return;
}
_reportedSdkTraceIds.add(normalized);
}
/// 清除指定页面的广告去重记录(页面退出时调用,下次进入可重新上报)
void clearPage(String pageKey) {
if (_reportedAdIdsByPage.remove(pageKey) != null) {
Logger.adImpressionManager('页面 "$pageKey" 广告去重记录已清除');
}
}
/// 清除所有页面的广告去重记录(新 session 开始时调用)
void clear() {
_reportedAdIdsByPage.clear();
_reportedSdkTraceIds.clear();
}
// ── 以下方法供测试使用 ──────────────────────────────
/// 检查广告ID在指定页面内是否已上报(不修改状态)
bool isReported(String adId, {required String pageKey}) {
return _reportedAdIdsByPage[pageKey]?.contains(adId.trim()) ?? false;
}
/// [isReported] 的别名,用于断言
bool contains(String adId, {required String pageKey}) =>
isReported(adId, pageKey: pageKey);
}