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,189 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:analytics_sdk/const/event_type.dart';
|
||||
import 'package:analytics_sdk/manager/sdk_context.dart';
|
||||
|
||||
/// 应用生命周期事件。
|
||||
///
|
||||
/// `app_lifecycle` 的子事件字段写入 `payload`。每个工厂方法只写入该
|
||||
/// 子事件文档定义的字段。
|
||||
class AppLifecycleEvent {
|
||||
final String event = EventType.appLifecycle.event;
|
||||
final String lifecycleEventKey;
|
||||
final Map<String, dynamic> _fields;
|
||||
|
||||
late final String eventId;
|
||||
late final Map<String, dynamic> _commonFields;
|
||||
|
||||
AppLifecycleEvent._(
|
||||
this.lifecycleEventKey,
|
||||
Map<String, dynamic> fields,
|
||||
) : _fields = Map<String, dynamic>.from(fields)
|
||||
..removeWhere((_, value) => value == null) {
|
||||
_commonFields = SdkContext.generateCommonFields(event);
|
||||
eventId = SdkContext.generateEventIdFromCommonFields(_commonFields, [
|
||||
lifecycleEventKey,
|
||||
jsonEncode(_stableFields),
|
||||
]);
|
||||
}
|
||||
|
||||
factory AppLifecycleEvent.coldStart({
|
||||
required int coldStartDurationMs,
|
||||
String lastExitType = 'unknown',
|
||||
int bootTime = 0,
|
||||
}) =>
|
||||
AppLifecycleEvent._('cold_start', {
|
||||
'cold_start_duration_ms': _nonNegative(coldStartDurationMs),
|
||||
'last_exit_type': _allowedString(
|
||||
lastExitType,
|
||||
const {'normal', 'killed', 'crash', 'unknown'},
|
||||
'unknown',
|
||||
),
|
||||
'boot_time': bootTime > 0 ? bootTime : 0,
|
||||
});
|
||||
|
||||
factory AppLifecycleEvent.webLoad({
|
||||
required String pageUrl,
|
||||
required int pageLoadTimeMs,
|
||||
required int viewportWidth,
|
||||
required int viewportHeight,
|
||||
}) =>
|
||||
AppLifecycleEvent._('web_load', {
|
||||
'page_url': pageUrl,
|
||||
'page_load_time_ms': _nonNegative(pageLoadTimeMs),
|
||||
'viewport_width': viewportWidth,
|
||||
'viewport_height': viewportHeight,
|
||||
});
|
||||
|
||||
factory AppLifecycleEvent.warmStart({
|
||||
required int backgroundDurationMs,
|
||||
String resumeReason = 'unknown',
|
||||
}) =>
|
||||
AppLifecycleEvent._('warm_start', {
|
||||
'background_duration_ms': _nonNegative(backgroundDurationMs),
|
||||
'resume_reason': _allowedString(
|
||||
resumeReason,
|
||||
const {'user', 'push', 'scheme', 'unknown'},
|
||||
'unknown',
|
||||
),
|
||||
});
|
||||
|
||||
factory AppLifecycleEvent.foreground({
|
||||
required int foregroundCountInSid,
|
||||
}) =>
|
||||
AppLifecycleEvent._('foreground', {
|
||||
'foreground_count_in_sid':
|
||||
foregroundCountInSid < 1 ? 1 : foregroundCountInSid,
|
||||
'is_foreground': 1,
|
||||
});
|
||||
|
||||
factory AppLifecycleEvent.background({
|
||||
required int foregroundDurationMs,
|
||||
required String lastActivePageKey,
|
||||
}) =>
|
||||
AppLifecycleEvent._('background', {
|
||||
'is_foreground': 0,
|
||||
'foreground_duration_ms': _nonNegative(foregroundDurationMs),
|
||||
'last_active_page_key': lastActivePageKey,
|
||||
});
|
||||
|
||||
factory AppLifecycleEvent.webUnload({
|
||||
required String pageUrl,
|
||||
required String lastActivePageKey,
|
||||
required int pageStayDurationMs,
|
||||
String unloadReason = 'unknown',
|
||||
required int scrollDepthPercentAtUnload,
|
||||
required String webVisibilityState,
|
||||
}) =>
|
||||
AppLifecycleEvent._('web_unload', {
|
||||
'page_url': pageUrl,
|
||||
'last_active_page_key': lastActivePageKey,
|
||||
'page_stay_duration_ms': _nonNegative(pageStayDurationMs),
|
||||
'unload_reason': _allowedString(
|
||||
unloadReason,
|
||||
const {
|
||||
'normal',
|
||||
'visibility_hidden',
|
||||
'navigation',
|
||||
'tab_close',
|
||||
'unknown',
|
||||
},
|
||||
'unknown',
|
||||
),
|
||||
'scroll_depth_percent_at_unload':
|
||||
scrollDepthPercentAtUnload.clamp(0, 100),
|
||||
'web_visibility_state': _allowedString(
|
||||
webVisibilityState,
|
||||
const {'visible', 'hidden', 'unknown'},
|
||||
'unknown',
|
||||
),
|
||||
});
|
||||
|
||||
factory AppLifecycleEvent.terminate({
|
||||
required String lastActivePageKey,
|
||||
String terminateType = 'unknown',
|
||||
required int sessionDurationMs,
|
||||
required int terminateTs,
|
||||
}) =>
|
||||
AppLifecycleEvent._('terminate', {
|
||||
'last_active_page_key': lastActivePageKey,
|
||||
'terminate_type': _allowedString(
|
||||
terminateType,
|
||||
const {'user_quit', 'system_kill', 'app_finish', 'unknown'},
|
||||
'unknown',
|
||||
),
|
||||
'session_duration_ms': _nonNegative(sessionDurationMs),
|
||||
'terminate_ts': terminateTs > 0
|
||||
? terminateTs
|
||||
: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
});
|
||||
|
||||
factory AppLifecycleEvent.unknown({
|
||||
String unknownReason = 'unknown',
|
||||
}) =>
|
||||
AppLifecycleEvent._('unknown', {
|
||||
'unknown_reason': _allowedString(
|
||||
unknownReason,
|
||||
const {
|
||||
'callback_missing',
|
||||
'state_conflict',
|
||||
'unsupported_platform',
|
||||
'sdk_not_ready',
|
||||
'system_restricted',
|
||||
'route_unrecognized',
|
||||
'collect_error',
|
||||
'unknown',
|
||||
},
|
||||
'unknown',
|
||||
),
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
..._commonFields,
|
||||
'event_id': eventId,
|
||||
'payload': {
|
||||
'lifecycle_event_key': lifecycleEventKey,
|
||||
..._fields,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> get _stableFields {
|
||||
final sortedKeys = _fields.keys.toList()..sort();
|
||||
return {
|
||||
for (final key in sortedKeys) key: _fields[key],
|
||||
};
|
||||
}
|
||||
|
||||
static int _nonNegative(int value) => value < 0 ? 0 : value;
|
||||
|
||||
static String _allowedString(
|
||||
String value,
|
||||
Set<String> allowed,
|
||||
String fallback,
|
||||
) {
|
||||
final normalized = value.trim();
|
||||
return allowed.contains(normalized) ? normalized : fallback;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user