Ios app launch
Skill almasumdev/awesome-ios-agent-skills/.github/skills/performance/ios-app-launch
Expert guidance on optimizing iOS cold and warm launch — pre-main phases, DYLD, image loading, launch screens, and measurement with App Launch Instrument and MetricKit. Use when launch time is a concern.From its SKILL.md
npx -y skills add almasumdev/awesome-ios-agent-skills --skill ios-app-launchAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.8 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
iOS App Launch Performance
Instructions
A good launch feels instantaneous. Apple's guidance: cold launch under 400 ms on recent devices. Anything over 2 seconds is considered a poor user experience and is flagged by the system.
1. Launch Phases
| Phase | What happens |
|---|---|
| Pre-main | dyld maps and links frameworks, resolves symbols, runs +load |
| main → UI | UIApplicationMain → didFinishLaunching → first frame committed |
| Post-launch | Async work, prefetches, personalization |
2. Measuring
- Instruments → App Launch: annotated timeline of every phase.
- MetricKit (
MXAppLaunchMetric) reports real-user percentiles. - Xcode Organizer → Metrics: aggregated launch time from TestFlight/App Store builds.
- Signposts for custom phases:
import OSLog
let log = OSLog(subsystem: "app.launch", category: .pointsOfInterest)
os_signpost(.begin, log: log, name: "bootstrap")
bootstrap()
os_signpost(.end, log: log, name: "bootstrap")
3. Pre-main (Dynamic Linking)
dyld time grows with the number of embedded dynamic frameworks. Mitigations:
- Prefer static SPM products (
.library(name:..., type: .static, ...)) for internal packages. - Merge third-party libraries that permit it.
- Avoid using
+load; do initialization lazily in+initializeor on first use. - Remove unused frameworks and
@rpathentries.
4. didFinishLaunchingWithOptions Hygiene
Do the minimum to show the first frame. Move analytics initialization, SDK bootstraps, crash reporter setup to right after the first frame or to applicationDidBecomeActive.
@main
struct MyApp: App {
init() {
Bootstrap.criticalOnly() // <10 ms
}
var body: some Scene {
WindowGroup {
RootView()
.task(priority: .utility) { await Bootstrap.deferred() }
}
}
}
Bootstrap.criticalOnly() sets up the minimum DI graph. Everything else (analytics, remote config, background refresh) runs in the deferred task.
5. First Screen
- Avoid network calls on the first frame. Render cached or skeleton content instantly.
- Don't block on Keychain reads on the main actor — many of them are slow enough to matter.
- Don't instantiate heavyweight view models for screens the user isn't on.
6. Launch Screen
Use a Launch Screen storyboard or the UILaunchScreen dictionary in Info.plist. Match it pixel-close to the first real frame so transitions are invisible:
<key>UILaunchScreen</key>
<dict>
<key>UIColorName</key><string>LaunchBackground</string>
<key>UIImageName</key><string>LaunchLogo</string>
</dict>
Avoid animated splash screens; they inflate perceived launch.
7. Asset Loading
- Use asset catalogs and size classes; the system only decodes what it needs.
- Preload images asynchronously after first frame, not during launch.
- Avoid loading heavy JSON or SQLite on the main actor at startup; defer to a background
Task.
8. Swift Concurrency at Launch
Spawn startup Tasks with .utility or lower priority. Do not block the main actor with await chains:
@MainActor
func onFirstAppear() {
Task.detached(priority: .utility) {
await config.refresh()
await analytics.flush()
}
}
9. Prewarming (iOS 15+)
iOS may prewarm the app: didFinishLaunching runs with no UI intent. Detect and skip work:
func application(_ app: UIApplication,
didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if ProcessInfo.processInfo.environment["ActivePrewarm"] == "1" {
return true
}
Bootstrap.criticalOnly()
return true
}
10. Checklist During PR Review
Every PR that adds a framework, SDK, or first-launch work should answer:
- Does this add a dynamic framework? Can it be static?
- Is initialization deferrable past first frame?
- Does this touch disk or Keychain on the main actor at launch?
- Was launch time re-measured on a real device?
Checklist
- Launch is measured on a physical device in Release.
- Internal SPM products are static where possible.
-
didFinishLaunchingdoes only critical setup. - First frame renders cached/placeholder data — no network.
- Deferred bootstrap runs at
.utilitypriority post-launch. - Prewarming is detected and handled.
- MetricKit reports p50/p95 launch to a dashboard.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.