agentsclimarketplace

Cold start optimization

Skill almasumdev/awesome-mobile-performance-agent-skills/.github/skills/startup/cold-start-optimization

Reduce cold start time (TTID and TTFD) on iOS and Android using baseline profiles, main-thread hygiene, and selective pre-warming. Use when launch latency exceeds the budget in Agent.md.From its SKILL.md

Install
npx -y skills add almasumdev/awesome-mobile-performance-agent-skills --skill cold-start-optimization

Assembled 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

5.0 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it

Cold Start Optimization

Instructions

Optimize cold start — the scenario where the OS creates a new process and your app draws its first meaningful frame. Cold start is what app-store reviewers and lab devices measure, so it is the number that matters for reviews and rankings.

1. Define the Target Metrics

Two numbers matter:

  • TTID (Time To Initial Display) — first frame drawn. On Android this is Displayed in logcat. On iOS it is the moment UIWindow commits its first frame.
  • TTFD (Time To Full Display) — first useful frame with real data. On Android call Activity.reportFullyDrawn(). On iOS emit an os_signpost event named TTFD.

Targets (p50 device, release build):

MetriciOS budgetAndroid budget
TTID1.2 s1.5 s
TTFD2.0 s2.5 s

2. Baseline First

Before changing code, capture a baseline.

Android (Macrobenchmark):

@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
  @get:Rule val rule = MacrobenchmarkRule()

  @Test fun coldStartup() = rule.measureRepeated(
      packageName = "com.example.app",
      metrics = listOf(StartupTimingMetric()),
      iterations = 10,
      startupMode = StartupMode.COLD,
  ) { pressHome(); startActivityAndWait() }
}

iOS (XCTest):

func testLaunchPerformance() {
    measure(metrics: [XCTApplicationLaunchMetric()]) {
        XCUIApplication().launch()
    }
}

3. Make the Main Thread Boring

Every millisecond before the first frame is paid on the main thread. Audit and remove:

  • Disk IO in Application.onCreate / UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:).
  • Synchronous network calls, feature-flag fetches, remote-config SDK init.
  • Eager DI container construction (Hilt @EntryPoint, Swinject assembler, get_it registrations) for features not on the start screen.
  • JSON parsing of cached payloads. Defer to Dispatchers.IO / a background DispatchQueue.
  • Heavy reflection or annotation scanning (Jackson, Gson with @SerializedName at startup).

Android pattern — use Initializer from androidx.startup and disable default init for expensive libs:

class AnalyticsInitializer : Initializer<Analytics> {
  override fun create(ctx: Context): Analytics = Analytics.init(ctx)
  override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}

iOS pattern — replace +[load] with +initialize or lazy static let. Never do work in +[load].

enum FeatureFlags {
    static let shared = FeatureFlagsClient()   // lazily created on first access
}

4. Ship a Baseline Profile (Android)

Baseline Profiles AOT-compile the hot startup path and typically reduce cold start by 15–30%.

@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
  @get:Rule val rule = BaselineProfileRule()

  @Test fun generate() = rule.collect(packageName = "com.example.app") {
    pressHome(); startActivityAndWait()
    device.findObject(By.res("feed")).scroll(Direction.DOWN, 0.8f)
  }
}

Commit the produced baseline-prof.txt into src/main/ and add androidx.profileinstaller.

5. Pre-warm Only What the First Frame Needs

  • iOS: prebuild the root UIView / SwiftUI View tree off the critical path using Task.detached for side data only — never for the first frame's view tree.
  • Android: in Application.onCreate, post non-critical work with Handler(Looper.getMainLooper()).post {} so it runs after first frame.
  • Flutter: use SchedulerBinding.instance.addPostFrameCallback to defer work until after the first frame; mark shell route with HeroMode(enabled: false) during launch.
  • React Native: enable Hermes; move bridge-heavy native modules to lazy registration via TurboModule on the New Architecture.

6. Splash Screen, Not Blank Window

Use the OS-provided splash APIs — SplashScreen on Android 12+, LaunchScreen.storyboard / .xcassets on iOS. A themed splash hides the process-creation window and improves perceived TTID without adding real time.

7. Measure Again, Record in CI

Add the benchmark to CI. Fail the build on > 5% regression vs a committed baseline JSON. See startup-profiling skill.

Checklist

  • TTID and TTFD budgets documented.
  • Baseline numbers captured on a p50 device in release/profile mode.
  • No disk IO, network, or JSON parsing on the main thread before first frame.
  • Expensive SDK initializers moved off the startup path (AndroidX Startup, lazy singletons).
  • Android: Baseline Profile generated and installed via androidx.profileinstaller.
  • iOS: no work in +[load]; Task.detached used for side effects only.
  • Splash theme / launch screen configured to avoid white flash.
  • CI benchmark fails on > 5% regression.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.