Skip to content

Customize app launch end time #6886

Description

@noahsmartin

We start measuring app launch from the moment the process is created, which seems pretty obvious. Less obvious though is when to consider app launch finished. Some devs want to know "time to initial display (TTID)" and "time to full display (TTFD)", but this just makes the situation even more confusing because neither have a real definition. We have defined "launch" in two ways. Before V9 we used UIWindow's hidden property, considering the app launched when the window's hidden property was set to true. Since V9 the default changed to use a CADisplayLink, the app is launched on the first callback from the display link.

These methods have problems though. For example if the app is launched in the background it might never "display" but it definitely was still launched and that launch time is still important to track. Even worse - we sometimes consider it a very long app launch because we start when the process is created in the background and end app launch when the user manually brings it to the foreground triggering it to be displayed. There is no universal way to know if the app was launched for a background task or to come to the foreground.

This issue is to track a more customizable way to measure app launch. By default I propose we end app launch on receiving UIApplication.didFinishLaunchingNotification. This is universally understood and won't have edge cases. However, it also won't capture what some would consider a "full" launch, if some code is dispatched to the main thread asynchronously before that point. For instance consider this code:

func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    DispatchQueue.main.async {
      sleep(10)
    }
}

This will "launch" quickly by our default metric but obviously not appear to be launched quickly to a user. There is a fine line between this and a hang, if that async call was delayed by a few seconds you'd say the app launched but then hung, rather than had a slow launch.

One way to handle this would be to have a runloop observer and consider the app launched after the runloop enters a waiting state (meaning it has no events left to process).

I suggest we introduce an API like this:

// This must be called before the applicationDidFinishLaunching notification is received
let launchTask = SentrySDK.extendAppLaunch()

...

// Call this when you want to mark the app as launched
launchTask.finishLaunch()


// If we want to have a special "full display" span we can support this
launchTask.fullyDisplayed()

This is similar to how apple lets you extend launch time for metrics reported in Xcode, so it's already familiar to some developers.

We should only bother to build this API for the new way of measuring app launch: #6883

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions