192 lines
4.9 KiB
Dart
192 lines
4.9 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:yx_tracking_flutter/yx_tracking_flutter.dart';
|
||
|
||
Future<void> main() async {
|
||
WidgetsFlutterBinding.ensureInitialized();
|
||
|
||
await Analytics.init(
|
||
const AnalyticsConfig(
|
||
systemCode: 'DEMO_APP',
|
||
endpointBaseUrl: 'https://example.com/api/ExternalEventlogs',
|
||
clientType: 3,
|
||
enableDebug: true,
|
||
batchSize: 5,
|
||
flushInterval: 30,
|
||
),
|
||
);
|
||
|
||
runApp(const DemoApp());
|
||
}
|
||
|
||
class DemoApp extends StatelessWidget {
|
||
const DemoApp({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return const MaterialApp(
|
||
home: DemoPage(),
|
||
);
|
||
}
|
||
}
|
||
|
||
class DemoPage extends StatefulWidget {
|
||
const DemoPage({super.key});
|
||
|
||
@override
|
||
State<DemoPage> createState() => _DemoPageState();
|
||
}
|
||
|
||
class _DemoPageState extends State<DemoPage> {
|
||
int _cacheCount = 0;
|
||
List<RecentEventSummary> _recent = const <RecentEventSummary>[];
|
||
bool _flushing = false;
|
||
bool _refreshingConfig = false;
|
||
Timer? _pollTimer;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_refreshCount();
|
||
_pollTimer = Timer.periodic(const Duration(seconds: 2), (_) {
|
||
_refreshCount();
|
||
});
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_pollTimer?.cancel();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _refreshCount() async {
|
||
final results = await Future.wait(<Future<Object>>[
|
||
Analytics.cachedEventCount(),
|
||
Analytics.cachedRecentEvents(limit: 20),
|
||
]);
|
||
final count = results[0] as int;
|
||
final recent = results[1] as List<RecentEventSummary>;
|
||
if (!mounted) {
|
||
return;
|
||
}
|
||
setState(() {
|
||
_cacheCount = count;
|
||
_recent = recent;
|
||
});
|
||
}
|
||
|
||
Future<void> _trackDemoEvent() async {
|
||
await Analytics.track(
|
||
'DEMO_BUTTON_CLICK',
|
||
eventParams: const <String, dynamic>{'page': 'demo'},
|
||
customTags: const <String, dynamic>{
|
||
'tenantId': 't1',
|
||
'feature': 'demo',
|
||
},
|
||
);
|
||
await _refreshCount();
|
||
}
|
||
|
||
Future<void> _flushNow() async {
|
||
if (_flushing) {
|
||
return;
|
||
}
|
||
setState(() {
|
||
_flushing = true;
|
||
});
|
||
try {
|
||
await Analytics.flush(force: true);
|
||
} finally {
|
||
if (mounted) {
|
||
setState(() {
|
||
_flushing = false;
|
||
});
|
||
}
|
||
await _refreshCount();
|
||
}
|
||
}
|
||
|
||
Future<void> _refreshConfig() async {
|
||
if (_refreshingConfig) {
|
||
return;
|
||
}
|
||
setState(() {
|
||
_refreshingConfig = true;
|
||
});
|
||
try {
|
||
await Analytics.refreshConfig(force: true);
|
||
} finally {
|
||
if (mounted) {
|
||
setState(() {
|
||
_refreshingConfig = false;
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(title: const Text('YX Tracking Demo')),
|
||
body: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: <Widget>[
|
||
Text(
|
||
'本地缓存事件数:$_cacheCount',
|
||
style: Theme.of(context).textTheme.titleMedium,
|
||
),
|
||
const SizedBox(height: 16),
|
||
Wrap(
|
||
spacing: 12,
|
||
runSpacing: 12,
|
||
children: <Widget>[
|
||
ElevatedButton(
|
||
onPressed: _trackDemoEvent,
|
||
child: const Text('Track Demo Event'),
|
||
),
|
||
ElevatedButton(
|
||
onPressed: _flushing ? null : _flushNow,
|
||
child: Text(_flushing ? 'Flushing...' : 'Flush Now'),
|
||
),
|
||
OutlinedButton(
|
||
onPressed: _refreshingConfig ? null : _refreshConfig,
|
||
child: Text(_refreshingConfig ? 'Refreshing...' : 'Refresh Config'),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 12),
|
||
const Text(
|
||
'说明:Demo 使用 example.com 作为占位地址,'
|
||
'实际联调时请替换为真实 HTTPS 域名。',
|
||
),
|
||
const SizedBox(height: 12),
|
||
Text('最近事件(最多 20 条)', style: Theme.of(context).textTheme.titleSmall),
|
||
const SizedBox(height: 8),
|
||
Expanded(
|
||
child: _recent.isEmpty
|
||
? const Text('暂无事件')
|
||
: ListView.separated(
|
||
itemCount: _recent.length,
|
||
separatorBuilder: (_, __) => const Divider(height: 1),
|
||
itemBuilder: (context, index) {
|
||
final item = _recent[index];
|
||
return ListTile(
|
||
dense: true,
|
||
title: Text(item.eventType),
|
||
subtitle: Text(
|
||
'${item.createTime.toIso8601String()} · retry=${item.retryCount}',
|
||
),
|
||
);
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|