Ios app launch
Skill almasumdev/awesome-ios-agent-skills/.github/skills/performance/ios-app-launch
Curated agent skills, conventions, and workflows for building iOS apps (Swift, SwiftUI, UIKit) with AI coding agents.
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.
What its author says it does
Copied from the file, not written here
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.
SKILL.md
4.8 KB, 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.