“Install Error(-10)” Got You Stuck? The Hidden Trick to Beat Google Play’s Pre-launch Test

 

🤔 Why the “App Not Owned” Error Happens

If your app fails the Google Play Pre-launch Test with this scary message —

u9.a: -10: Install Error(-10): The app is not owned by any user on this device.
An app is "owned" if it has been acquired from Play.

— you’re not alone.

This happens because the Pre-launch Test runs on Google’s own test devices, which aren’t linked to your Play account or purchase history.
So, if your app uses Play Core libraries (like AppUpdateManager or AppReviewManager), the “ownership check” fails, and your app never even gets installed.

It’s one of those bugs that make you scream: “But it works fine on my phone!” 😩

 

🤔 The Secret Fix Google Never Told You

Here’s the insider trick that devs have quietly been using:


Settings.System.getString(context.contentResolver, "firebase.test.lab")

This line reveals whether your app is currently running inside Firebase Test Lab — the same environment used for Pre-launch Tests.
If the value is "true", you’re in a test device.
That means you can safely skip anything that requires Play services or user ownership checks.

Here’s how to use it:


val isTestLab = Settings.System.getString(context.contentResolver, "firebase.test.lab") == "true"
if (!isTestLab) {
    // Run Play Core logic only in real user environments
}

Boom. 💣
No more random -10 install errors.
Your Pre-launch Test will finally pass like a charm.

 

⚡ Summary

The “Install Error(-10)” is not a bug in your code — it’s a Play Console quirk.
By detecting the Test Lab environment with:


Settings.System.getString(context.contentResolver, "firebase.test.lab")

you can bypass Play-related ownership checks and let your app install smoothly during the Pre-launch Test.

A single line of code could be the difference between “Test failed 🚫” and “Release ready ✅” — now that’s a win worth sharing.

👉 Firebase Test Lab × リリース前レポート環境を見分けるKotlin実装


Activity x Compose Lifecycle: The Complete Visual Guide 🚀

 

👨‍💻 Activity Lifecycle


Activity.onCreate() <- Activity is created

↓

Activity.onStart() <- Preparing to become visible on screen

↓

Activity.onResume() <- Foreground state (interactive)

↓

Activity.onPause() <- Partially visible

↓

Activity.onStop() <- No longer visible

↓

Activity.onDestroy() <- Activity is destroyed

 

👨‍💻 Compose Lifecycle


[First Composition]
  - Composable is evaluated, Compose tree is built
  - LaunchedEffect -> Runs once after the commit
  - SideEffect -> Runs after every commit
  - DisposableEffect -> onDispose is called upon disposal

↓

[Recomposition]
  - UI is re-evaluated in response to state or data changes
  - Only the necessary parts are recomposed (efficient update)
  - SideEffect and DisposableEffect are also re-evaluated during recomposition

↓

[Dispose]
  - Depends on the ComposeView's disposal condition
  - DisposableEffect's onDispose is executed
  - Disposal timing is determined by the ViewCompositionStrategy

 

👨‍💻 Activity x Compose Lifecycle


Activity.onCreate() setContent { ... } <- Sets the ComposeView

↓

[First Composition]
  - Evaluates Composables and builds the UI
  - LaunchedEffect -> Runs once after commit
  - SideEffect -> Runs after each commit
  - DisposableEffect -> Defines onDispose

↓

Activity.onStart()

↓

Activity.onResume()

↓

[Recomposition]
  - Re-evaluates necessary parts in response to state changes
  - LaunchedEffect is not re-executed (only if its key changes)
  - SideEffect / DisposableEffect are re-evaluated

↓

Activity.onPause()

↓

(ComposeView is retained)
  - UI becomes partially obscured
  - State is maintained within the Composition

↓

Activity.onStop()

↓

[Preparing for Dispose (Detection)]
  - ViewCompositionStrategy monitors disposal conditions

↓

Activity.onDestroy()

↓

[Dispose]
  - ComposeView is destroyed
  - DisposableEffect.onDispose() is executed

This is the general flow.

Here are the notes for each item:

Activity.onCreate() A lifecycle method called when an Android app's Activity is created.

    setContent { ... }: Sets the UI using Jetpack Compose. This sets a ComposeView as the Activity's content view. The Compose lifecycle begins.

  • First Composition The Composable functions set in setContent are evaluated for the first time, and the UI is built.

LaunchedEffect: An Effect used for asynchronous processing. Runs only once after the first composition.

SideEffect: Runs after every composition commit (the timing when UI changes are applied).

DisposableEffect: An Effect used for resource cleanup. The logic defined in onDispose is executed when the Composition is disposed.

Activity.onStart() A lifecycle method called just before the Activity becomes visible to the user.

Activity.onResume() The Activity moves to the foreground and becomes fully interactive with the user.

  • Recomposition Only the necessary Composable functions are re-evaluated in response to changes in State.

LaunchedEffect: It is not re-executed during recomposition. However, it will be re-executed if its key changes.

SideEffect: It is re-evaluated on every recomposition.

DisposableEffect: It is re-evaluated on recomposition, and the cleanup logic (onDispose) from the old Effect is called.

Activity.onPause() The Activity enters a paused state and becomes partially obscured.

ComposeView Retention: The UI is not destroyed; it is retained. The state is also maintained within the Composition, allowing it to be reused upon re-display.

Activity.onStop() The Activity is no longer visible. A time to prepare for cleaning up state and resources.

Preparing for Dispose (Detection) ViewCompositionStrategy: A mechanism that monitors the conditions under which the ComposeView should be disposed. It triggers the Composition's disposal based on the View's lifecycle.

Activity.onDestroy() The timing when the Activity is completely destroyed.

  • Dispose The ComposeView is destroyed: The UI and state are completely released.
  • DisposableEffect.onDispose(): The resource cleanup logic is called.

 

👨‍💻 Summary

The Jetpack Compose and Activity lifecycles are closely linked, with specific processes occurring at each stage, from UI initialization (setContent) to disposal (Dispose).

It is especially important to understand the differences between effects like LaunchedEffect, SideEffect, and DisposableEffect, and to manage them appropriately.

Furthermore, by efficiently reusing the UI in response to Activity state changes (like onResume or onPause) and cleaning up resources as needed, you can achieve stable application behavior.


初回コンポーズは Activity.onStart() までに終わる

 

🤔 Activity x Compose のライフサイクル


Activity.onCreate()
  setContent { ... }   ← ComposeView をセット

    ↓

  [初回コンポーズ(First Composition)]
    ・Composable を評価し UI を構築
    ・LaunchedEffect → コミット後に一度実行
    ・SideEffect → 各コミットごとに実行
    ・DisposableEffect → onDispose 定義

    ↓

Activity.onStart()

    ↓

Activity.onResume()

    ↓

  [再コンポーズ(Recomposition)]  
    ・状態変更に応じて必要部分のみ再評価
    ・LaunchedEffect は再実行されない(Key 変更時のみ)
    ・SideEffect / DisposableEffect は再評価

    ↓

Activity.onPause()

    ↓

  (ComposeView は保持)
    ・UI は部分的に見えなくなる
    ・状態は Composition 内で維持

    ↓

Activity.onStop() 

    ↓

  [破棄準備(Dispose 検知)]
    ・ViewCompositionStrategy による破棄条件監視

    ↓

Activity.onDestroy()

    ↓

  [破棄(Dispose)]
    ・ComposeView が破棄される
    ・DisposableEffect.onDispose() 実行

 

🤔 まとめ

初回コンポーズは Activity.onStart() までに終わる。

👉 これだけでわかる!Activity × Compose のライフサイクル完全図解 🚀


IDE × AIモデル別:プロンプトに食わせるべきファイルまとめ

主要IDEごとに、連携AI・推奨ファイル・目的・補足を整理した表です。プログラミング中心にまとめています。

1. 基本のセット

  • プロジェクト概要・設計
    README.md, architecture.md
    AIに全体像・設計方針・責務を理解させる
  • 依存・環境情報
    build.gradle(.kts), package.json, Podfile, .env.example
    SDK・ライブラリ・環境変数を正確に認識させる
  • コーディング方針・ルール
    .prompt.yaml, .copilot-instructions.md, .editorconfig
    命名規則、禁止API、コードスタイルを統一

2. IDE × AIモデル別の推奨ファイルと効果

IDE 推奨AIモデル 重点ファイル 効果 補足
Android Studio / IntelliJ Gemini Code Assist, Copilot .prompt.yaml, build.gradle, architecture.md Androidプロジェクト全体を理解した補完・設計提案 プロジェクト全体の構造を解析可能。方針ファイルで安定化。
Xcode Copilot, GPT-5 .prompt.yaml, Package.swift, README.md SwiftUI/MVVM設計に沿った正確なコード生成 Xcodeは依存解析が弱めなので .prompt.yaml を明示すると効果大。
VS Code Copilot Chat, GPT-5 .copilot-instructions.md, package.json, README.md 軽量環境で多言語対応、チーム開発の方針共有に有効 拡張機能単位でAI切替可能。指示ファイルが最重要。
Cursor / Windsurf / Aider GPT-5 / Claude 3.5 / Gemini 1.5 .prompt.yaml / .cursorconfig, README.md, architecture.md, build設定 設計・生成・リファクタを自動で分担 ファイル単位でAIが文脈キャッシュを保持。設計書参照可。
Jupyter / DataSpell / VSCode + Python GPT-4 Turbo, Gemini Advanced .ipynb / .csv / .xlsx, analysis.md / README.md, .prompt.yaml データ解析・統計・グラフ生成 データ+分析目的+出力形式を渡すと的確に解析可能。
Figma / Webflow / Framer Gemini 1.5 Pro (Vision), GPT-5 Vision .fig / .svg / layout.json, style_reference.jpg, .prompt.yaml UIデザイン→コード変換・スタイル抽出 構図+目的+出力フォーマット指定でSwiftUIやComposeコード化が容易。

3. 実務での運用Tips

  • サンプルコードを渡す
    /sample_code に小さな動作例を置くと、AIが文体やパターンを模倣しやすい
  • 変更履歴を渡す
    CHANGELOG.md や feature_list.md を読むことで、過去の修正意図を理解し、安全な提案が可能
  • 大きなファイルは要約して渡す
    設計書や長文ドキュメントは、AIの文脈理解の負荷を減らすために必要部分だけ渡す
  • 依存関係やAPI仕様は明示
    未定義関数や古いAPIの誤提案を防ぐため、build.gradle や .env.example を食わせる

4. まとめ

プログラミングAIを「単なるコード補完」ではなく、プロジェクト理解型のアシスタントとして活用するには、

「概要 + 環境 + 方針」をAIに与えることが最も重要です。

  • IDEや言語に合わせたファイルを食わせる
  • 設計方針と依存関係を明確化する
  • サンプルコードや履歴で文脈を補完する

この3ステップで、AIは理解に基づいたコード生成・設計提案を行い、開発効率と品質を大幅に向上させられます。


3大 AIプラグイン ショートカット比較表(Copilot / JetBrains AI / Gemini)

 

🤔 3大AIプラグイン ショートカット比較表(Copilot / JetBrains AI / Gemini)

機能 GitHub Copilot JetBrains AI Assistant Gemini for Android Studio
AIコード補完の表示 ⌥](次候補)
⌥[(前候補)
⌥Space ⌘I または Ctrl+I
AI候補を確定 Tab または Enter Enter Enter
補完候補を拒否 Esc Esc Esc
AIチャットを開く ⌘⇧I ⌥⇧A ⌘⇧.
選択コードの説明 / 修正 ⌘⇧\\ ⌥Enter → 「AI提案」 ⌘⇧L
コメントからコード生成 // コメント後に Enter AIチャットから「コード生成」 コメント入力 → ⌘Enter
コードの最適化・修正 ⌘.(Quick Fix) ⌥Enter → 「AIでリファクタ」 ⌘⇧M
ドキュメント生成 / 説明追加 ⌘⇧/ AIチャット「この関数を説明して」 ⌘⇧D
選択範囲に対するAI操作 ⌘⇧\\(説明・修正) ⌥Enter ⌘⇧L
ファイル全体を改善 なし(コメントから提案) ⌥⇧A → 「ファイルを改善」 ⌘⇧F

 

🤔 AIプラグイン運用おすすめ(衝突回避パターン)

利用スタイル 構成 特徴・おすすめポイント
① コーディング中心型
(AI補完を重視)
Copilot + JetBrains AI(Copilot優先) Copilotの補完をメインに、JetBrains AIは「説明」「修正」時のみ使用。
⌥EnterをAI専用に割り当てると安定。
② 設計・レビュー重視型
(AI説明とチャットを多用)
JetBrains AI + Gemini(Copilotオフ) チャットでの説明・リファクタが中心。GeminiでAndroid特有の質問も可能。
⌥⇧A⌘⇧. の競合に注意。
③ Android特化開発型
(Geminiメイン)
Geminiのみ or Gemini + Copilot Android Studio統合が深く、ComposeやAPI質問が即答。
Copilotを補完専用に使うと最も安定。
④ 学習・試行型
(全部試すタイプ)
Copilot + JetBrains AI + Gemini(全併用) ショートカット競合が多発。どれを「補完用」「チャット用」にするか明確化必須。
設定から「Keymapのカスタム」を推奨。

 

🤔 AIプラグイン ショートカット競合リスク表

組み合わせ 競合リスク 主な衝突ショートカット 対策・回避策
Copilot + JetBrains AI ★★★☆(中〜高) ⌥Enter, Tab, ⌘. JetBrains側のAI提案を「右クリック呼び出し」に変更推奨。
CopilotをTab確定中心に設定。
JetBrains AI + Gemini ★★★(中) ⌥⇧A, ⌘⇧. どちらを「チャット起動」に使うか決める。
Geminiを ⌘⇧; にリマップ推奨。
Copilot + Gemini ★★(低〜中) Enter, ⌘I 競合は軽度。Copilotを補完専用・Geminiをチャット専用に分離。
Copilot + JetBrains AI + Gemini ★★★★(高) ⌘⇧I, ⌥Enter, Enter 全AIのショートカットを手動で再割り当て必須。
Preferences → Keymapで確認・上書きを推奨。

 

🤔 まとめ:

・同時導入するなら「補完」「チャット」「リファクタ」の役割を分ける。
・競合は特に ⌥Enter⌘⇧I に集中。
・キー設定は Keymap → Search: “AI” で全体を確認しておくのが安全。

Copilot:補完が最速で自然、Tab確定中心の軽快操作。
JetBrains AI:リファクタやドキュメント生成など開発支援が得意。
Gemini:Android Studioに最も深く統合され、自然言語操作が強力。