android-native-dev
Android native application development and UI design guide. Covers Material Design 3, Kotlin/Compose development, project configuration, accessibility, and build troubleshooting. Read this before Android native application development.
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o android-native-dev.zip https://jpskill.com/download/19690.zip && unzip -o android-native-dev.zip && rm android-native-dev.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/19690.zip -OutFile "$d\android-native-dev.zip"; Expand-Archive "$d\android-native-dev.zip" -DestinationPath $d -Force; ri "$d\android-native-dev.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
android-native-dev.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
android-native-devフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 10
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
[Skill 名] android-native-dev
1. プロジェクトシナリオの評価
開発を開始する前に、現在のプロジェクトの状態を評価します。
| シナリオ | 特徴 | アプローチ |
|---|---|---|
| 空のディレクトリ | ファイルが存在しない | Gradle Wrapperを含む完全な初期化が必要です |
| Gradle Wrapperがある | gradlewとgradle/wrapper/が存在する |
ビルドには./gradlewを直接使用します |
| Android Studioプロジェクト | 完全なプロジェクト構造ですが、Wrapperがない場合があります | Wrapperを確認し、必要に応じてgradle wrapperを実行します |
| 不完全なプロジェクト | 部分的なファイルが存在する | 不足しているファイルを確認し、設定を完了します |
主要な原則:
- ビジネスロジックを記述する前に、
./gradlew assembleDebugが成功することを確認します gradle.propertiesがない場合は、まず作成し、AndroidXを設定します
1.1 必要なファイルのチェックリスト
MyApp/
├── gradle.properties # AndroidXやその他の設定を構成します
├── settings.gradle.kts
├── build.gradle.kts # ルートレベル
├── gradle/wrapper/
│ └── gradle-wrapper.properties
├── app/
│ ├── build.gradle.kts # モジュールレベル
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── java/com/example/myapp/
│ │ └── MainActivity.kt
│ └── res/
│ ├── values/
│ │ ├── strings.xml
│ │ ├── colors.xml
│ │ └── themes.xml
│ └── mipmap-*/ # アプリアイコン
2. プロジェクト設定
2.1 gradle.properties
# 必須設定
android.useAndroidX=true
android.enableJetifier=true
# ビルド最適化
org.gradle.parallel=true
kotlin.code.style=official
# JVMメモリ設定 (プロジェクトサイズに応じて調整)
# 小規模プロジェクト: 2048m, 中規模: 4096m, 大規模: 8192m+
# org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
注: ビルド中に
OutOfMemoryErrorが発生した場合は、-Xmxの値を増やしてください。多くの依存関係を持つ大規模プロジェクトでは、8GB以上が必要になる場合があります。
2.2 依存関係の宣言基準
dependencies {
// BOMを使用してComposeのバージョンを管理します
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
// Activity & ViewModel
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
}
2.3 ビルドバリアントとプロダクトフレーバー
プロダクトフレーバーを使用すると、アプリの異なるバージョン(例:無料版/有料版、開発版/ステージング版/製品版)を作成できます。
app/build.gradle.ktsでの設定:
android {
// フレーバーディメンションを定義します
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
// フレーバーごとに異なる設定値
buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
// 異なるリソース
resValue("string", "app_name", "MyApp Dev")
}
create("staging") {
dimension = "environment"
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
buildConfigField("String", "API_BASE_URL", "\"https://staging-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
resValue("string", "app_name", "MyApp Staging")
}
create("prod") {
dimension = "environment"
// 製品版にはサフィックスなし
buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "false")
resValue("string", "app_name", "MyApp")
}
}
buildTypes {
debug {
isDebuggable = true
isMinifyEnabled = false
}
release {
isDebuggable = false
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
ビルドバリアントの命名: {flavor}{BuildType} → 例: devDebug, prodRelease
Gradleビルドコマンド:
# 利用可能なすべてのビルドバリアントをリスト表示します
./gradlew tasks --group="build"
# 特定のバリアント(フレーバー + ビルドタイプ)をビルドします
./gradlew assembleDevDebug # Devフレーバー、Debugビルド
./gradlew assembleStagingDebug # Stagingフレーバー、Debugビルド
./gradlew assembleProdRelease # Prodフレーバー、Releaseビルド
# 特定のフレーバーのすべてのバリアントをビルドします
./gradlew assembleDev # すべてのDevバリアント (debug + release)
./gradlew assembleProd # すべてのProdバリアント
# 特定のビルドタイプのすべてのバリアントをビルドします
./gradlew assembleDebug # すべてのフレーバー、Debugビルド
./gradlew assembleRelease # すべてのフレーバー、Releaseビルド
# 特定のバリアントをデバイスにインストールします
./gradlew installDevDebug
./gradlew installProdRelease
# ビルドとインストールを1つのコマンドで実行します
./gradlew installDevDebug && adb shell am start -n com.example.myapp.dev/.MainActivity
コードでのBuildConfigへのアクセス:
注: AGP 8.0以降、
BuildConfigはデフォルトでは生成されなくなりました。build.gradle.ktsで明示的に有効にする必要があります。android { buildFeatures { buildConfig = true } }
// コードでビルド設定値を使用します
val apiUrl = BuildConfig.API_BASE_URL
val isLoggingEnabled = BuildConfig.ENABLE_LOGGING
if (BuildConfig.DEBUG) {
// デバッグ専用コード
}
フレーバー固有のソースセット:
app/src/
├── main/ # すべてのフレーバーで共有されるコード
├── dev/ # Dev専用のコードとリソース
│ ├── java/
│ └── res/
├── staging/ # Staging専用のコードとリソース
├── prod/ # Prod専用のコードとリソース
├── debug/ # Debug b 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
1. Project Scenario Assessment
Before starting development, assess the current project state:
| Scenario | Characteristics | Approach |
|---|---|---|
| Empty Directory | No files present | Full initialization required, including Gradle Wrapper |
| Has Gradle Wrapper | gradlew and gradle/wrapper/ exist |
Use ./gradlew directly for builds |
| Android Studio Project | Complete project structure, may lack wrapper | Check wrapper, run gradle wrapper if needed |
| Incomplete Project | Partial files present | Check missing files, complete configuration |
Key Principles:
- Before writing business logic, ensure
./gradlew assembleDebugsucceeds - If
gradle.propertiesis missing, create it first and configure AndroidX
1.1 Required Files Checklist
MyApp/
├── gradle.properties # Configure AndroidX and other settings
├── settings.gradle.kts
├── build.gradle.kts # Root level
├── gradle/wrapper/
│ └── gradle-wrapper.properties
├── app/
│ ├── build.gradle.kts # Module level
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── java/com/example/myapp/
│ │ └── MainActivity.kt
│ └── res/
│ ├── values/
│ │ ├── strings.xml
│ │ ├── colors.xml
│ │ └── themes.xml
│ └── mipmap-*/ # App icons
2. Project Configuration
2.1 gradle.properties
# Required configuration
android.useAndroidX=true
android.enableJetifier=true
# Build optimization
org.gradle.parallel=true
kotlin.code.style=official
# JVM memory settings (adjust based on project size)
# Small projects: 2048m, Medium: 4096m, Large: 8192m+
# org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
Note: If you encounter
OutOfMemoryErrorduring build, increase-Xmxvalue. Large projects with many dependencies may require 8GB or more.
2.2 Dependency Declaration Standards
dependencies {
// Use BOM to manage Compose versions
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
// Activity & ViewModel
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
}
2.3 Build Variants & Product Flavors
Product Flavors allow you to create different versions of your app (e.g., free/paid, dev/staging/prod).
Configuration in app/build.gradle.kts:
android {
// Define flavor dimensions
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
// Different config values per flavor
buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
// Different resources
resValue("string", "app_name", "MyApp Dev")
}
create("staging") {
dimension = "environment"
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
buildConfigField("String", "API_BASE_URL", "\"https://staging-api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
resValue("string", "app_name", "MyApp Staging")
}
create("prod") {
dimension = "environment"
// No suffix for production
buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "false")
resValue("string", "app_name", "MyApp")
}
}
buildTypes {
debug {
isDebuggable = true
isMinifyEnabled = false
}
release {
isDebuggable = false
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
Build Variant Naming: {flavor}{BuildType} → e.g., devDebug, prodRelease
Gradle Build Commands:
# List all available build variants
./gradlew tasks --group="build"
# Build specific variant (flavor + buildType)
./gradlew assembleDevDebug # Dev flavor, Debug build
./gradlew assembleStagingDebug # Staging flavor, Debug build
./gradlew assembleProdRelease # Prod flavor, Release build
# Build all variants of a specific flavor
./gradlew assembleDev # All Dev variants (debug + release)
./gradlew assembleProd # All Prod variants
# Build all variants of a specific build type
./gradlew assembleDebug # All flavors, Debug build
./gradlew assembleRelease # All flavors, Release build
# Install specific variant to device
./gradlew installDevDebug
./gradlew installProdRelease
# Build and install in one command
./gradlew installDevDebug && adb shell am start -n com.example.myapp.dev/.MainActivity
Access BuildConfig in Code:
Note: Starting from AGP 8.0,
BuildConfigis no longer generated by default. You must explicitly enable it in yourbuild.gradle.kts:android { buildFeatures { buildConfig = true } }
// Use build config values in your code
val apiUrl = BuildConfig.API_BASE_URL
val isLoggingEnabled = BuildConfig.ENABLE_LOGGING
if (BuildConfig.DEBUG) {
// Debug-only code
}
Flavor-Specific Source Sets:
app/src/
├── main/ # Shared code for all flavors
├── dev/ # Dev-only code and resources
│ ├── java/
│ └── res/
├── staging/ # Staging-only code and resources
├── prod/ # Prod-only code and resources
├── debug/ # Debug build type code
└── release/ # Release build type code
Multiple Flavor Dimensions (e.g., environment + tier):
android {
flavorDimensions += listOf("environment", "tier")
productFlavors {
create("dev") { dimension = "environment" }
create("prod") { dimension = "environment" }
create("free") { dimension = "tier" }
create("paid") { dimension = "tier" }
}
}
// Results in: devFreeDebug, devPaidDebug, prodFreeRelease, etc.
3. Kotlin Development Standards
3.1 Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Class/Interface | PascalCase | UserRepository, MainActivity |
| Function/Variable | camelCase | getUserName(), isLoading |
| Constant | SCREAMING_SNAKE | MAX_RETRY_COUNT |
| Package | lowercase | com.example.myapp |
| Composable | PascalCase | @Composable fun UserCard() |
3.2 Code Standards (Important)
Null Safety:
// ❌ Avoid: Non-null assertion !! (may crash)
val name = user!!.name
// ✅ Recommended: Safe call + default value
val name = user?.name ?: "Unknown"
// ✅ Recommended: let handling
user?.let { processUser(it) }
Exception Handling:
// ❌ Avoid: Random try-catch in business layer swallowing exceptions
fun loadData() {
try {
val data = api.fetch()
} catch (e: Exception) {
// Swallowing exception, hard to debug
}
}
// ✅ Recommended: Let exceptions propagate, handle at appropriate layer
suspend fun loadData(): Result<Data> {
return try {
Result.success(api.fetch())
} catch (e: Exception) {
Result.failure(e) // Wrap and return, let caller decide handling
}
}
// ✅ Recommended: Unified handling in ViewModel
viewModelScope.launch {
runCatching { repository.loadData() }
.onSuccess { _uiState.value = UiState.Success(it) }
.onFailure { _uiState.value = UiState.Error(it.message) }
}
3.3 Threading & Coroutines (Critical)
Thread Selection Principles:
| Operation Type | Thread | Description |
|---|---|---|
| UI Updates | Dispatchers.Main |
Update View, State, LiveData |
| Network Requests | Dispatchers.IO |
HTTP calls, API requests |
| File I/O | Dispatchers.IO |
Local storage, database operations |
| Compute Intensive | Dispatchers.Default |
JSON parsing, sorting, encryption |
Correct Usage:
// In ViewModel
viewModelScope.launch {
// Default Main thread, can update UI State
_uiState.value = UiState.Loading
// Switch to IO thread for network request
val result = withContext(Dispatchers.IO) {
repository.fetchData()
}
// Automatically returns to Main thread, update UI
_uiState.value = UiState.Success(result)
}
// In Repository (suspend functions should be main-safe)
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
api.getData()
}
Common Mistakes:
// ❌ Wrong: Updating UI on IO thread
viewModelScope.launch(Dispatchers.IO) {
val data = api.fetch()
_uiState.value = data // Crash or warning!
}
// ❌ Wrong: Executing time-consuming operation on Main thread
viewModelScope.launch {
val data = api.fetch() // Blocking main thread! ANR
}
// ✅ Correct: Fetch on IO, update on Main
viewModelScope.launch {
val data = withContext(Dispatchers.IO) { api.fetch() }
_uiState.value = data
}
3.4 Visibility Rules
// Default is public, declare explicitly when needed
class UserRepository { // public
private val cache = mutableMapOf<String, User>() // Visible only within class
internal fun clearCache() {} // Visible only within module
}
// data class properties are public by default, be careful when used across modules
data class User(
val id: String, // public
val name: String
)
3.5 Common Syntax Pitfalls
// ❌ Wrong: Accessing uninitialized lateinit
class MyViewModel : ViewModel() {
lateinit var data: String
fun process() = data.length // May crash
}
// ✅ Correct: Use nullable or default value
class MyViewModel : ViewModel() {
var data: String? = null
fun process() = data?.length ?: 0
}
// ❌ Wrong: Using return in lambda
list.forEach { item ->
if (item.isEmpty()) return // Returns from outer function!
}
// ✅ Correct: Use return@forEach
list.forEach { item ->
if (item.isEmpty()) return@forEach
}
3.6 Server Response Data Class Fields Must Be Nullable
// ❌ Wrong: Fields declared as non-null (server may not return them)
data class UserResponse(
val id: String = "",
val name: String = "",
val avatar: String = ""
)
// ✅ Correct: All fields declared as nullable
data class UserResponse(
@SerializedName("id")
val id: String? = null,
@SerializedName("name")
val name: String? = null,
@SerializedName("avatar")
val avatar: String? = null
)
3.7 Lifecycle Resource Management
// ❌ Wrong: Only adding Observer, not removing
class MyView : View {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
activity?.lifecycle?.addObserver(this)
}
// Memory leak!
}
// ✅ Correct: Paired add and remove
class MyView : View {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
activity?.lifecycle?.addObserver(this)
}
override fun onDetachedFromWindow() {
activity?.lifecycle?.removeObserver(this)
super.onDetachedFromWindow()
}
}
3.8 Logging Level Usage
import android.util.Log
// Info: Key checkpoints in normal flow
Log.i(TAG, "loadData: started, userId = $userId")
// Warning: Abnormal but recoverable situations
Log.w(TAG, "loadData: cache miss, fallback to network")
// Error: Failure/error situations
Log.e(TAG, "loadData failed: ${error.message}")
| Level | Use Case |
|---|---|
i (Info) |
Normal flow, method entry, key parameters |
w (Warning) |
Recoverable exceptions, fallback handling, null returns |
e (Error) |
Request failures, caught exceptions, unrecoverable errors |
4. Jetpack Compose Standards
4.1 @Composable Context Rules
// ❌ Wrong: Calling Composable from non-Composable function
fun showError(message: String) {
Text(message) // Compile error!
}
// ✅ Correct: Mark as @Composable
@Composable
fun ErrorMessage(message: String) {
Text(message)
}
// ❌ Wrong: Using suspend outside LaunchedEffect
@Composable
fun MyScreen() {
val data = fetchData() // Error!
}
// ✅ Correct: Use LaunchedEffect
@Composable
fun MyScreen() {
var data by remember { mutableStateOf<Data?>(null) }
LaunchedEffect(Unit) {
data = fetchData()
}
}
4.2 State Management
// Basic State
var count by remember { mutableStateOf(0) }
// Derived State (avoid redundant computation)
val isEven by remember { derivedStateOf { count % 2 == 0 } }
// Persist across recomposition (e.g., scroll position)
val scrollState = rememberScrollState()
// State in ViewModel
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}
4.3 Common Compose Mistakes
// ❌ Wrong: Creating objects in Composable (created on every recomposition)
@Composable
fun MyScreen() {
val viewModel = MyViewModel() // Wrong!
}
// ✅ Correct: Use viewModel() or remember
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
// ...
}
5. Resources & Icons
5.1 App Icon Requirements
Must provide multi-resolution icons:
| Directory | Size | Purpose |
|---|---|---|
| mipmap-mdpi | 48x48 | Baseline |
| mipmap-hdpi | 72x72 | 1.5x |
| mipmap-xhdpi | 96x96 | 2x |
| mipmap-xxhdpi | 144x144 | 3x |
| mipmap-xxxhdpi | 192x192 | 4x |
Recommended: Use Adaptive Icon (Android 8+):
<!-- res/mipmap-anydpi-v26/ic_launcher.xml -->
<adaptive-icon>
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
5.2 Resource Naming Conventions
| Type | Prefix | Example |
|---|---|---|
| Layout | layout_ | layout_main.xml |
| Image | ic, img, bg_ | ic_user.png |
| Color | color_ | color_primary |
| String | - | app_name, btn_submit |
5.3 Avoid Android Reserved Names (Important)
Variable names, resource IDs, colors, icons, and XML elements must not use Android reserved words or system resource names. Using reserved names causes build errors or resource conflicts.
Common Reserved Names to Avoid:
| Category | Reserved Names (Do NOT Use) |
|---|---|
| Colors | background, foreground, transparent, white, black |
| Icons/Drawables | icon, logo, image, drawable |
| Views | view, text, button, layout, container |
| Attributes | id, name, type, style, theme, color |
| System | app, android, content, data, action |
Examples:
<!-- ❌ Wrong: Using reserved names -->
<color name="background">#FFFFFF</color>
<color name="icon">#000000</color>
<!-- ✅ Correct: Add prefix or specific naming -->
<color name="app_background">#FFFFFF</color>
<color name="icon_primary">#000000</color>
// ❌ Wrong: Variable names conflict with system
val icon = R.drawable.my_icon
val background = Color.White
// ✅ Correct: Use descriptive names
val appIcon = R.drawable.my_icon
val screenBackground = Color.White
<!-- ❌ Wrong: Drawable name conflicts -->
<ImageView android:src="@drawable/icon" />
<!-- ✅ Correct: Add prefix -->
<ImageView android:src="@drawable/ic_home" />
6. Build Error Diagnosis & Fixes
6.1 Common Error Quick Reference
| Error Keyword | Cause | Fix |
|---|---|---|
Unresolved reference |
Missing import or undefined | Check imports, verify dependencies |
Type mismatch |
Type incompatibility | Check parameter types, add conversion |
Cannot access |
Visibility issue | Check public/private/internal |
@Composable invocations |
Composable context error | Ensure caller is also @Composable |
Duplicate class |
Dependency conflict | Use ./gradlew dependencies to investigate |
AAPT: error |
Resource file error | Check XML syntax and resource references |
6.2 Fix Best Practices
- Read the complete error message first: Locate file and line number
- Check recent changes: Problems usually in latest modifications
- Clean Build:
./gradlew clean assembleDebug - Check dependency versions: Version conflicts are common causes
- Refresh dependencies if needed: Clear cache and rebuild
6.3 Debugging Commands
# Clean and build
./gradlew clean assembleDebug
# View dependency tree (investigate conflicts)
./gradlew :app:dependencies
# View detailed errors
./gradlew assembleDebug --stacktrace
# Refresh dependencies
./gradlew --refresh-dependencies
7. Material Design 3 Guidelines
Review Android UI files for compliance with Material Design 3 Guidelines and Android best practices.
Design Philosophy
M3 Core Principles
| Principle | Description |
|---|---|
| Personal | Dynamic color based on user preferences and wallpaper |
| Adaptive | Responsive across all screen sizes and form factors |
| Expressive | Bold colors and typography with personality |
| Accessible | Inclusive design for all users |
M3 Expressive (Latest)
The latest evolution adds emotion-driven UX through:
- Vibrant, dynamic colors
- Intuitive motion physics
- Adaptive components
- Flexible typography
- Contrasting shapes (35 new shape options)
App Style Selection
Critical Decision: Match visual style to app category and target audience.
| App Category | Visual Style | Key Characteristics |
|---|---|---|
| Utility/Tool | Minimalist | Clean, efficient, neutral colors |
| Finance/Banking | Professional Trust | Conservative colors, security-focused |
| Health/Wellness | Calm & Natural | Soft colors, organic shapes |
| Kids (3-5) | Playful Simple | Bright colors, large targets (56dp+) |
| Kids (6-12) | Fun & Engaging | Vibrant, gamified feedback |
| Social/Entertainment | Expressive | Brand-driven, gesture-rich |
| Productivity | Clean & Focused | Minimal, high contrast |
| E-commerce | Conversion-focused | Clear CTAs, scannable |
See Design Style Guide for detailed style profiles.
Quick Reference: Key Specifications
Color Contrast Requirements
| Element | Minimum Ratio |
|---|---|
| Body text | 4.5:1 |
| Large text (18sp+) | 3:1 |
| UI components | 3:1 |
Touch Targets
| Type | Size |
|---|---|
| Minimum | 48 × 48dp |
| Recommended (primary actions) | 56 × 56dp |
| Kids apps | 56dp+ |
| Spacing between targets | 8dp minimum |
8dp Grid System
| Token | Value | Usage |
|---|---|---|
| xs | 4dp | Icon padding |
| sm | 8dp | Tight spacing |
| md | 16dp | Default padding |
| lg | 24dp | Section spacing |
| xl | 32dp | Large gaps |
| xxl | 48dp | Screen margins |
Typography Scale (Summary)
| Category | Sizes |
|---|---|
| Display | 57sp, 45sp, 36sp |
| Headline | 32sp, 28sp, 24sp |
| Title | 22sp, 16sp, 14sp |
| Body | 16sp, 14sp, 12sp |
| Label | 14sp, 12sp, 11sp |
Animation Duration
| Type | Duration |
|---|---|
| Micro (ripples) | 50-100ms |
| Short (simple) | 100-200ms |
| Medium (expand/collapse) | 200-300ms |
| Long (complex) | 300-500ms |
Component Dimensions
| Component | Height | Min Width |
|---|---|---|
| Button | 40dp | 64dp |
| FAB | 56dp | 56dp |
| Text Field | 56dp | 280dp |
| App Bar | 64dp | - |
| Bottom Nav | 80dp | - |
Anti-Patterns (Must Avoid)
UI Anti-Patterns
- More than 5 bottom navigation items
- Multiple FABs on same screen
- Touch targets smaller than 48dp
- Inconsistent spacing (non-8dp multiples)
- Missing dark theme support
- Text on colored backgrounds without contrast check
Performance Anti-Patterns
- Startup time > 2 seconds without progress indicator
- Frame rate < 60 FPS (> 16ms per frame)
- Crash rate > 1.09% (Google Play threshold)
- ANR rate > 0.47% (Google Play threshold)
Accessibility Anti-Patterns
- Missing contentDescription on interactive elements
- Element type in labels (e.g., "Save button" instead of "Save")
- Complex gestures in kids apps
- Text-only buttons for non-readers
Review Checklist
- [ ] 8dp spacing grid compliance
- [ ] 48dp minimum touch targets
- [ ] Proper typography scale usage
- [ ] Color contrast compliance (4.5:1+ for text)
- [ ] Dark theme support
- [ ] contentDescription on all interactive elements
- [ ] Startup < 2 seconds or shows progress
- [ ] Visual style matches app category
Design References
| Topic | Reference |
|---|---|
| Colors, Typography, Spacing, Shapes | Visual Design |
| Animation & Transitions | Motion System |
| Accessibility Guidelines | Accessibility |
| Large Screens & Foldables | Adaptive Screens |
| Android Vitals & Performance | Performance & Stability |
| Privacy & Security | Privacy & Security |
| Audio, Video, Notifications | Functional Requirements |
| App Style by Category | Design Style Guide |
8. Testing
Note: Only add test dependencies when the user explicitly asks for testing.
A well-tested Android app uses layered testing: fast local unit tests for logic, instrumentation tests for UI and integration, and Gradle Managed Devices to run emulators reproducibly on any machine — including CI.
8.1 Test Dependencies
Before adding test dependencies, inspect the project's existing versions to avoid conflicts:
- Check
gradle/libs.versions.toml— if present, add test deps using the project's version catalog style - Check existing
build.gradle.ktsfor already-pinned dependency versions - Match version families using the table below
Version Alignment Rules:
| Test Dependency | Must Align With | How to Check |
|---|---|---|
kotlinx-coroutines-test |
Project's kotlinx-coroutines-core version |
Search for kotlinx-coroutines in build files or version catalog |
compose-ui-test-junit4 |
Project's Compose BOM or compose-compiler |
Search for compose-bom or compose.compiler in build files |
espresso-* |
All Espresso artifacts must use the same version | Search for espresso in build files |
androidx.test:runner, rules, ext:junit |
Should use compatible AndroidX Test versions | Search for androidx.test in build files |
mockk |
Must support the project's Kotlin version | Check kotlin version in root build.gradle.kts or version catalog |
Dependencies Reference — add only the groups you need:
dependencies {
// --- Local unit tests (src/test/) ---
testImplementation("junit:junit:<version>") // 4.13.2+
testImplementation("org.robolectric:robolectric:<version>") // 4.16.1+
testImplementation("io.mockk:mockk:<version>") // match Kotlin version
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:<version>") // match coroutines-core
testImplementation("androidx.arch.core:core-testing:<version>") // InstantTaskExecutorRule for LiveData
testImplementation("app.cash.turbine:turbine:<version>") // Flow/StateFlow testing
// --- Instrumentation tests (src/androidTest/) ---
androidTestImplementation("androidx.test.ext:junit:<version>")
androidTestImplementation("androidx.test:runner:<version>")
androidTestImplementation("androidx.test:rules:<version>")
androidTestImplementation("androidx.test.espresso:espresso-core:<version>")
androidTestImplementation("androidx.test.espresso:espresso-contrib:<version>") // RecyclerView, Drawer
androidTestImplementation("androidx.test.espresso:espresso-intents:<version>") // Intent verification
androidTestImplementation("androidx.test.espresso:espresso-idling-resource:<version>")
androidTestImplementation("androidx.test.uiautomator:uiautomator:<version>")
// --- Compose UI tests (only if project uses Compose) ---
androidTestImplementation("androidx.compose.ui:ui-test-junit4") // version from Compose BOM
debugImplementation("androidx.compose.ui:ui-test-manifest") // required for createComposeRule
}
Note: If the project uses a Compose BOM,
ui-test-junit4andui-test-manifestdon't need explicit versions — the BOM manages them.
Enable Robolectric resource support in the android block:
android {
testOptions {
unitTests.isIncludeAndroidResources = true // required for Robolectric
}
}
8.2 Testing by Layer
| Layer | Location | Runs On | Speed | Use For |
|---|---|---|---|---|
| Unit (JUnit) | src/test/ |
JVM | ~ms | ViewModels, repos, mappers, validators |
| Unit + Robolectric | src/test/ |
JVM + simulated Android | ~100ms | Code needing Context, resources, SharedPrefs |
| Compose UI (local) | src/test/ |
JVM + Robolectric | ~100ms | Composable rendering & interaction |
| Espresso | src/androidTest/ |
Device/Emulator | ~seconds | View-based UI flows, Intents, DB integration |
| Compose UI (device) | src/androidTest/ |
Device/Emulator | ~seconds | Full Compose UI flows with real rendering |
| UI Automator | src/androidTest/ |
Device/Emulator | ~seconds | System dialogs, notifications, multi-app |
| Managed Device | src/androidTest/ |
Gradle-managed AVD | ~minutes (first run) | CI, matrix testing across API levels |
See Testing for detailed examples, code patterns, and Gradle Managed Device configuration.
8.3 Testing Commands
# Local unit tests (fast, no emulator)
./gradlew test # all modules
./gradlew :app:testDebugUnitTest # app module, debug variant
# Single test class
./gradlew :app:testDebugUnitTest --tests "com.example.myapp.CounterViewModelTest"
# Instrumentation tests (requires device or managed device)
./gradlew connectedDebugAndroidTest # on connected device
./gradlew pixel6Api34DebugAndroidTest # on managed device
# Both together
./gradlew test connectedDebugAndroidTest
# Test with coverage report (JaCoCo)
./gradlew testDebugUnitTest jacocoTestReport 同梱ファイル
※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。
- 📄 SKILL.md (28,621 bytes)
- 📎 references/accessibility.md (5,732 bytes)
- 📎 references/adaptive-screens.md (6,098 bytes)
- 📎 references/design-style-guide.md (10,126 bytes)
- 📎 references/functional-requirements.md (6,175 bytes)
- 📎 references/motion-system.md (5,443 bytes)
- 📎 references/performance-stability.md (6,334 bytes)
- 📎 references/privacy-security.md (6,667 bytes)
- 📎 references/testing.md (17,568 bytes)
- 📎 references/visual-design.md (7,523 bytes)