ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-06-23上級

インストール直後だけ起動が一拍遅い — Baseline Profile で Android のコールドスタートを実測で詰めた手順

更新直後やインストール直後だけ Android アプリの起動が一拍もたつく原因を JIT と Cloud Profile の観点で切り分け、Baseline Profile でコールドスタートを実測で詰めた手順を、Macrobenchmark の構築から段階公開での監視まで個人開発の視点でまとめました。

Android15Baseline ProfileMacrobenchmarkパフォーマンス最適化2コールドスタート

プレミアム記事

新しい端末に壁紙アプリを入れ直してタップした最初の一回だけ、ホームのグリッドが出るまでに半呼吸の間があく。二回目以降は引っかかりません。リリースビルドでだけ、しかも「入れたて」のときだけ重い、という症状に半年ほど薄く悩まされていました。

個人開発で同じアプリを長く運営していると、自分の端末ではプロファイルが育ちきっているので、この遅さに気づけません。気づいたのは、レビューに「最初だけ重い」と書かれていたのを見たときでした。原因は JIT と Cloud Profile の届くタイミングにあり、Baseline Profile を入れることで実測で縮められました。その手順を、測る土台づくりから順に残しておきます。

なぜ「入れたて」のときだけ遅いのか

Android アプリのコードは、インストール直後の段階ではほとんどが解釈実行か JIT(実行時コンパイル)で動いています。よく通る経路は使われるうちに ART が少しずつ AOT 化していくので、使い込んだ端末では起動が速くなります。これが「二回目以降は引っかからない」正体です。

Google Play には Cloud Profiles という仕組みがあり、多くのユーザーの実行プロファイルを集約して、新規インストール時にある程度ウォームな状態を配ってくれます。ただしこれは、リリースから時間が経って母数が集まるまで効きません。リリース直後の新規インストールと、アプリ更新直後(プロファイルがリセットされた状態)では、この恩恵が薄いのです。

Baseline Profile は、起動とよく使う画面の「ホットパス」を開発側であらかじめ列挙し、APK / AAB に同梱して、インストール時に AOT コンパイルさせる仕組みです。Cloud Profiles が育つのを待たずに、最初の一回目から温まった状態を配れます。私の症状はまさにこの「最初だけ冷えている」状態だったので、噛み合いました。

先に「測れる土台」を作る — Macrobenchmark モジュール

最適化に手をつける前に、まず数値で再現できる状態を作ります。これをやらずにプロファイルだけ入れると、効いたのか気のせいなのか永久に分かりません。私自身、最初に Baseline Profile を入れたときは体感でしか語れず、説得力のないメモになってしまいました。

計測には Macrobenchmark を使います。アプリ本体とは別に、計測専用の com.android.test モジュールを足します。

// :macrobenchmark モジュールの build.gradle.kts
plugins {
    id("com.android.test")
    id("org.jetbrains.kotlin.android")
}
 
android {
    namespace = "com.example.wallpaper.macrobenchmark"
    compileSdk = 35
    defaultConfig {
        minSdk = 24
        targetSdk = 35
        // 物理端末で実行する。テスト対象はリリースに近い構成
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    targetProjectPath = ":app"
    // 計測ビルドは難読化済みのリリース寄りを使う
    experimentalProperties["android.experimental.self-instrumenting"] = true
}
 
dependencies {
    implementation("androidx.test.ext:junit:1.2.1")
    implementation("androidx.test.uiautomator:uiautomator:2.3.0")
    implementation("androidx.benchmark:benchmark-macro-junit4:1.3.3")
}

計測対象のアプリ側は、ベンチマークから起動・計測できるよう profileable を有効にします。デバッグビルドではなく、リリースに近い benchmark ビルドタイプを切る方が現実に即した数字になります。

<!-- app/src/main/AndroidManifest.xml -->
<application ...>
    <profileable
        android:shell="true"
        tools:targetApi="29" />
</application>

起動時間そのものを測るテストはこう書きます。StartupTimingMetric が、タップから最初の描画までの時間(Time To Initial Display)を中央値つきで出してくれます。

// StartupBenchmark.kt
@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
    @get:Rule val rule = MacrobenchmarkRule()
 
    private fun measure(mode: CompilationMode) = rule.measureRepeated(
        packageName = "com.example.wallpaper",
        metrics = listOf(StartupTimingMetric()),
        iterations = 15,             // 分散を見たいので回数は多めに
        startupMode = StartupMode.COLD,
        compilationMode = mode,
    ) {
        pressHome()
        startActivityAndWait()
    }
 
    // プロファイルなしの素の状態(最悪値の基準)
    @Test fun coldStartupNone() = measure(CompilationMode.None())
 
    // Baseline Profile を必須として使った状態
    @Test fun coldStartupBaselineProfile() =
        measure(CompilationMode.Partial(BaselineProfileMode.Require))
}

iterations を 15 にしているのは、コールドスタートは端末の状態に左右されて分散が大きいからです。1〜2 回では中央値が安定せず、改善幅を見誤ります。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
インストール直後だけ起動が遅くなる原因を JIT と Cloud Profile の観点で切り分け、自分のアプリの症状が Baseline Profile で改善するか判断できるようになります
Macrobenchmark モジュールと CompilationMode を使い、起動時間を Before/After で再現性のある数値として測れるようになります
生成した Baseline Profile を AAB に組み込み、段階公開で起動指標を監視しながら安全にロールアウトする手順を、自分のプロジェクトに適用できます
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

アプリ開発2026-06-22
アプリ内の言語切り替えを、端末の言語設定と切り離して実装する — Android Per-App Language の実装メモ
Android のアプリ内言語切り替えを AppCompatDelegate.setApplicationLocales と locales_config で実装する手順と、API 33 未満の互換・プロセス再生成・AdMob まわりの落とし穴を実装視点でまとめた記録です。
アプリ開発2026-06-21
Play Store の密度分割で、特定の端末だけ内蔵壁紙が消えた — drawable と nodpi の境界設計
App Bundle の密度分割は、密度別に分けてはいけない画像まで分けてしまうと、特定の密度バケットの端末からだけリソースを取りこぼします。bundletool で再現し、drawable-nodpi への移動か密度分割の無効化で直すまでを、判断基準ごと残しました。
アプリ開発2026-06-18
AI Studio のネイティブ Android 生成コードを本番アプリに入れる前の検め方
AI Studio のネイティブ Android vibe coding は驚くほど速く動く画面を出します。ただ、稼働中のアプリへ取り込む前には専用の検めが要ります。生成 Kotlin を本番に入れる前のレビュー設計をまとめます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →