Initial commit: add all skills files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
782
android-native-dev/SKILL.md
Normal file
782
android-native-dev/SKILL.md
Normal file
@@ -0,0 +1,782 @@
|
||||
---
|
||||
name: android-native-dev
|
||||
description: 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.
|
||||
license: MIT
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
category: mobile
|
||||
sources:
|
||||
- Material Design 3 Guidelines (material.io)
|
||||
- Android Developer Documentation (developer.android.com)
|
||||
- Google Play Quality Guidelines
|
||||
- WCAG Accessibility Guidelines
|
||||
---
|
||||
|
||||
## 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 assembleDebug` succeeds
|
||||
- If `gradle.properties` is 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
|
||||
|
||||
```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 `OutOfMemoryError` during build, increase `-Xmx` value. Large projects with many dependencies may require 8GB or more.
|
||||
|
||||
### 2.2 Dependency Declaration Standards
|
||||
|
||||
```kotlin
|
||||
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**:
|
||||
|
||||
```kotlin
|
||||
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**:
|
||||
|
||||
```bash
|
||||
# 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, `BuildConfig` is no longer generated by default. You must explicitly enable it in your `build.gradle.kts`:
|
||||
> ```kotlin
|
||||
> android {
|
||||
> buildFeatures {
|
||||
> buildConfig = true
|
||||
> }
|
||||
> }
|
||||
> ```
|
||||
|
||||
```kotlin
|
||||
// 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):
|
||||
|
||||
```kotlin
|
||||
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**:
|
||||
```kotlin
|
||||
// ❌ 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**:
|
||||
```kotlin
|
||||
// ❌ 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**:
|
||||
```kotlin
|
||||
// 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**:
|
||||
```kotlin
|
||||
// ❌ 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
|
||||
|
||||
```kotlin
|
||||
// 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
|
||||
|
||||
```kotlin
|
||||
// ❌ 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
|
||||
|
||||
```kotlin
|
||||
// ❌ 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
|
||||
|
||||
```kotlin
|
||||
// ❌ 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
|
||||
|
||||
```kotlin
|
||||
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
|
||||
|
||||
```kotlin
|
||||
// ❌ 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
|
||||
|
||||
```kotlin
|
||||
// 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
|
||||
|
||||
```kotlin
|
||||
// ❌ 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+):
|
||||
|
||||
```xml
|
||||
<!-- 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**:
|
||||
|
||||
```xml
|
||||
<!-- ❌ 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>
|
||||
```
|
||||
|
||||
```kotlin
|
||||
// ❌ 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
|
||||
```
|
||||
|
||||
```xml
|
||||
<!-- ❌ 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
|
||||
|
||||
1. **Read the complete error message first**: Locate file and line number
|
||||
2. **Check recent changes**: Problems usually in latest modifications
|
||||
3. **Clean Build**: `./gradlew clean assembleDebug`
|
||||
4. **Check dependency versions**: Version conflicts are common causes
|
||||
5. **Refresh dependencies if needed**: Clear cache and rebuild
|
||||
|
||||
### 6.3 Debugging Commands
|
||||
|
||||
```bash
|
||||
# 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](references/design-style-guide.md) 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](references/visual-design.md) |
|
||||
| Animation & Transitions | [Motion System](references/motion-system.md) |
|
||||
| Accessibility Guidelines | [Accessibility](references/accessibility.md) |
|
||||
| Large Screens & Foldables | [Adaptive Screens](references/adaptive-screens.md) |
|
||||
| Android Vitals & Performance | [Performance & Stability](references/performance-stability.md) |
|
||||
| Privacy & Security | [Privacy & Security](references/privacy-security.md) |
|
||||
| Audio, Video, Notifications | [Functional Requirements](references/functional-requirements.md) |
|
||||
| App Style by Category | [Design Style Guide](references/design-style-guide.md) |
|
||||
Reference in New Issue
Block a user