1
1
import 'package:flutter/scheduler.dart' ;
2
+ import 'package:meta/meta.dart' ;
2
3
import 'package:sentry/sentry.dart' ;
3
4
4
5
import '../../sentry_flutter.dart' ;
@@ -23,18 +24,14 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
23
24
'Scheduler binding is null. Can\' t auto detect app start time.' );
24
25
} else {
25
26
schedulerBinding.addPostFrameCallback ((timeStamp) async {
27
+ final appStartEnd = options.clock ();
26
28
// ignore: invalid_use_of_internal_member
27
- _native.appStartEnd = options. clock () ;
29
+ _native.appStartEnd = appStartEnd ;
28
30
29
- final appStartEnd = _native.appStartEnd;
31
+ if (! _native.didFetchAppStart) {
32
+ final nativeAppStart = await _native.fetchNativeAppStart ();
33
+ final measurement = nativeAppStart? .toMeasurement (appStartEnd! );
30
34
31
- if (_native.appStartEnd != null && ! _native! .didFetchAppStart) {
32
- print ('fetch app start' );
33
- final nativeAppStart = await _native! .fetchNativeAppStart ();
34
- if (nativeAppStart == null ) {
35
- return ;
36
- }
37
- final measurement = nativeAppStart.toMeasurement (appStartEnd! );
38
35
// We filter out app start more than 60s.
39
36
// This could be due to many different reasons.
40
37
// If you do the manual init and init the SDK too late and it does not
@@ -43,49 +40,23 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
43
40
// If the system forked the process earlier to accelerate the app start.
44
41
// And some unknown reasons that could not be reproduced.
45
42
// We've seen app starts with hours, days and even months.
46
- if (measurement.value >= 60000 ) {
43
+ if (nativeAppStart == null ||
44
+ measurement == null ||
45
+ measurement.value >= 60000 ) {
46
+ AppStartTracker ().setAppStartInfo (null );
47
47
return ;
48
48
}
49
49
50
- final appStartDateTime = DateTime .fromMillisecondsSinceEpoch (
51
- nativeAppStart.appStartTime.toInt ());
52
-
53
- final transactionContext2 = SentryTransactionContext (
54
- 'root ("/")' ,
55
- 'ui.load' ,
56
- transactionNameSource: SentryTransactionNameSource .component,
57
- // ignore: invalid_use_of_internal_member
58
- origin: SentryTraceOrigins .autoNavigationRouteObserver,
50
+ final appStartInfo = AppStartInfo (
51
+ DateTime .fromMillisecondsSinceEpoch (
52
+ nativeAppStart.appStartTime.toInt ()),
53
+ appStartEnd,
54
+ measurement,
59
55
);
60
56
61
- final transaction2 = hub.startTransactionWithContext (
62
- transactionContext2,
63
- waitForChildren: true ,
64
- autoFinishAfter: Duration (seconds: 3 ),
65
- trimEnd: true ,
66
- startTimestamp: appStartDateTime,
67
- onFinish: (transaction) async {
68
- final nativeFrames = await _native
69
- ? .endNativeFramesCollection (transaction.context.traceId);
70
- if (nativeFrames != null ) {
71
- final measurements = nativeFrames.toMeasurements ();
72
- for (final item in measurements.entries) {
73
- final measurement = item.value;
74
- transaction.setMeasurement (
75
- item.key,
76
- measurement.value,
77
- unit: measurement.unit,
78
- );
79
- }
80
- }
81
- });
82
-
83
- final ttidSpan = transaction2.startChild ('ui.load.initial_display' , startTimestamp: appStartDateTime);
84
- await ttidSpan.finish (endTimestamp: appStartEnd);
85
-
86
- SentryNavigatorObserver .ttfdSpan = transaction2.startChild ('ui.load.full_display' , startTimestamp: appStartDateTime);
87
-
88
- print ('end of the road' );
57
+ AppStartTracker ().setAppStartInfo (appStartInfo);
58
+ } else {
59
+ AppStartTracker ().setAppStartInfo (null );
89
60
}
90
61
});
91
62
}
@@ -99,3 +70,40 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
99
70
100
71
/// Used to provide scheduler binding at call time.
101
72
typedef SchedulerBindingProvider = SchedulerBinding ? Function ();
73
+
74
+ @internal
75
+ class AppStartInfo {
76
+ final DateTime start;
77
+ final DateTime end;
78
+ final SentryMeasurement measurement;
79
+
80
+ AppStartInfo (this .start, this .end, this .measurement);
81
+ }
82
+
83
+ @internal
84
+ class AppStartTracker {
85
+ static final AppStartTracker _instance = AppStartTracker ._internal ();
86
+
87
+ factory AppStartTracker () => _instance;
88
+
89
+ AppStartInfo ? _appStartInfo;
90
+
91
+ AppStartInfo ? get appStartInfo => _appStartInfo;
92
+ Function (AppStartInfo ? )? _callback;
93
+
94
+ AppStartTracker ._internal ();
95
+
96
+ void setAppStartInfo (AppStartInfo ? appStartInfo) {
97
+ _appStartInfo = appStartInfo;
98
+ _notifyObserver ();
99
+ }
100
+
101
+ void onAppStartComplete (Function (AppStartInfo ? ) callback) {
102
+ _callback = callback;
103
+ _callback? .call (_appStartInfo);
104
+ }
105
+
106
+ void _notifyObserver () {
107
+ _callback? .call (_appStartInfo);
108
+ }
109
+ }
0 commit comments