模块 03:项目结构与 Gradle 构建系统
目标:深入理解 Android 项目的文件组织方式和 Gradle 构建系统,能够独立阅读和修改项目配置。
与前端项目结构对比
先看整体对照,建立直觉:
前端项目 (React/Vue) Android 项目
├── package.json ├── build.gradle (项目级)
├── tsconfig.json ├── settings.gradle
├── .env / .env.local ├── gradle.properties
├── node_modules/ ├── .gradle/ (构建缓存)
├── public/ ├── app/ (主模块)
│ ├── index.html │ ├── build.gradle (模块级)
│ └── favicon.ico │ ├── src/
├── src/ │ │ ├── main/
│ ├── main.ts │ │ │ ├── AndroidManifest.xml
│ ├── App.tsx │ │ │ ├── java/ (源代码)
│ ├── components/ │ │ │ ├── res/ (资源文件)
│ ├── pages/ │ │ │ └── assets/
│ ├── styles/ │ │ ├── test/ (单元测试)
│ ├── utils/ │ │ └── androidTest/ (设备测试)
│ └── assets/ │ └── proguard-rules.pro
├── dist/ / build/ └── build/ (构建产物)
├── vite.config.ts
└── webpack.config.js1. 目录结构详解
1.1 项目根目录
MyApp/
├── .gradle/ # Gradle 缓存(类似 node_modules/.cache)
├── .idea/ # Android Studio 配置(类似 .vscode/)
├── app/ # 主模块(类似前端项目的 src/)
├── build/ # 构建产物(类似 dist/)
├── gradle/ # Gradle Wrapper 文件
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties # ⭐ 锁定 Gradle 版本
├── build.gradle # 项目级构建配置
├── settings.gradle # 模块声明
├── gradle.properties # Gradle 全局属性
├── local.properties # 本地环境配置(SDK 路径,不提交到 Git)
├── gradlew # Gradle Wrapper 脚本 (Unix)
├── gradlew.bat # Gradle Wrapper 脚本 (Windows)
└── proguard-rules.pro # 代码混淆规则1.2 app 模块目录(重点)
app/
├── build.gradle # ⭐ 模块级构建配置(最常用)
├── proguard-rules.pro # 混淆规则
└── src/
├── main/ # 主要源代码
│ ├── AndroidManifest.xml # ⭐ 应用清单文件
│ ├── java/ # Java 源码
│ │ └── com/example/myapp/
│ │ ├── MainActivity.java
│ │ ├── model/ # 数据模型
│ │ ├── network/ # 网络请求
│ │ ├── adapter/ # 列表适配器
│ │ ├── fragment/ # Fragment 页面
│ │ ├── activity/ # Activity 页面
│ │ └── util/ # 工具类
│ ├── res/ # ⭐ 资源文件
│ │ ├── layout/ # XML 布局文件(类似 HTML 模板)
│ │ ├── values/ # 字符串、颜色、尺寸、样式
│ │ ├── drawable/ # 图片、形状、选择器
│ │ ├── mipmap/ # 应用图标
│ │ ├── menu/ # 菜单定义
│ │ ├── anim/ # 动画定义
│ │ ├── xml/ # XML 配置文件
│ │ ├── raw/ # 原始资源文件
│ │ └── navigation/ # 导航图(Jetpack Navigation)
│ └── assets/ # 原始资源(不会编译,直接打包)
├── test/ # 单元测试(JVM 上运行)
│ └── java/
└── androidTest/ # 设备测试(需要 Android 设备)
└── java/1.3 多模块项目
大型老项目通常有多个模块(类似前端的 monorepo):
MyApp/
├── settings.gradle # 声明所有模块
├── app/ # 主应用模块
├── library-core/ # 核心库模块
├── library-network/ # 网络库模块
├── library-ui/ # UI 组件库模块
└── feature-login/ # 登录功能模块// settings.gradle
include ':app'
include ':library-core'
include ':library-network'
include ':library-ui'
include ':feature-login'2. AndroidManifest.xml
这是 Android 应用的"身份证"和"路由表",类似前端项目中的 index.html + 路由配置。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<!-- 权限声明(类似浏览器的权限请求) -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- 应用全局配置 -->
<application
android:name=".MyApplication" <!-- 自定义 Application 类 -->
android:icon="@mipmap/ic_launcher" <!-- 应用图标 -->
android:label="@string/app_name" <!-- 应用名称 -->
android:theme="@style/Theme.MyApp" <!-- 全局主题 -->
android:allowBackup="true"
android:supportsRtl="true">
<!-- Activity 声明(类似路由注册) -->
<activity
android:name=".MainActivity"
android:exported="true"> <!-- 允许外部启动 -->
<intent-filter>
<!-- 标记为启动入口(类似前端首页) -->
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 其他 Activity -->
<activity android:name=".LoginActivity" />
<activity android:name=".SettingsActivity" />
<!-- Service 声明 -->
<service android:name=".service.SyncService" />
<!-- BroadcastReceiver 声明 -->
<receiver android:name=".receiver.NetworkReceiver" />
<!-- ContentProvider 声明 -->
<provider
android:name=".provider.DataProvider"
android:authorities="com.example.myapp.provider" />
<!-- meta-data:给组件传递额外配置 -->
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="your_api_key" />
</application>
</manifest>四大组件
AndroidManifest 中注册了四大组件,这是 Android 应用的骨架:
| 组件 | 作用 | 前端对应 |
|---|---|---|
| Activity | 一个屏幕/页面 | 路由页面(/home, /login) |
| Service | 后台长时间运行的任务 | Web Worker / Service Worker |
| BroadcastReceiver | 监听系统或应用事件 | window.addEventListener |
| ContentProvider | 跨应用数据共享 | REST API / IndexedDB |
接手老项目时:首先看 AndroidManifest.xml,它能告诉你应用有哪些页面、用了哪些权限、有哪些后台服务。
2.2 Manifest Merger(清单合并)
当项目包含多个模块或依赖库时,每个模块都可能有自己的 AndroidManifest.xml。构建时 Gradle 会将它们合并成最终的清单文件:
app/src/main/AndroidManifest.xml
library-core/src/main/AndroidManifest.xml
依赖库 A 的 AndroidManifest.xml
↓
合并工具(Manifest Merger)
↓
app/build/intermediates/merged_manifest/...合并冲突常见场景:
| 冲突 | 原因 | 解决 |
|---|---|---|
android:allowBackup 冲突 | 多个模块声明不同值 | 在 app 的 manifest 中用 tools:replace="android:allowBackup" |
| 权限重复 | 多个库声明同一权限 | 通常自动去重,必要时用 tools:node="remove" |
android:exported 冲突 | Activity/Service 导出属性不一致 | 在 app 的 manifest 中显式覆盖 |
<application
android:allowBackup="false"
tools:replace="android:allowBackup">
<!-- 显式覆盖库中的 allowBackup 设置 -->
</application>调试技巧:合并后的清单在
app/build/intermediates/merged_manifest/...,出问题时先检查这里。
3. Gradle 构建系统
3.1 Gradle 是什么?
Gradle 是 Android 的构建工具,相当于前端的 npm + webpack/vite 的组合:
| Gradle 功能 | 前端对应 |
|---|---|
| 依赖管理 | npm install / package.json |
| 编译 Java 代码 | tsc (TypeScript 编译) |
| 打包 APK | npm run build |
| 运行测试 | npm test |
| 代码签名 | (发布流程) |
3.2 Gradle Wrapper
# gradle/wrapper/gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists类似前端的
.nvmrc或engines字段:确保团队使用相同版本的 Gradle。
重要:不要随意修改 Gradle Wrapper 版本!老项目可能依赖特定 Gradle 版本。
3.3 settings.gradle
// settings.gradle(Groovy DSL,老项目常用)
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "MyApp"
include ':app'// settings.gradle.kts(Kotlin DSL,新项目常用)
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "MyApp"
include(":app")3.4 项目级 build.gradle
// build.gradle(项目根目录)
// 这里配置所有模块共享的插件
plugins {
id 'com.android.application' version '8.2.0' apply false
id 'com.android.library' version '8.2.0' apply false
}3.5 模块级 build.gradle(最重要!)
这是你修改最频繁的文件,相当于模块的 package.json + tsconfig.json:
// app/build.gradle
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.myapp'
compileSdk 34 // 编译目标 API 级别
defaultConfig {
applicationId "com.example.myapp" // 应用唯一标识(包名)
minSdk 24 // 最低支持版本
targetSdk 34 // 目标运行版本
versionCode 1 // 版本号(整数,用于商店)
versionName "1.0.0" // 版本名(字符串,显示给用户)
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
// 构建类型(类似前端的 .env.development / .env.production)
buildTypes {
release {
minifyEnabled true // 启用代码混淆/压缩
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
signingConfig signingConfigs.debug // 签名配置
}
debug {
minifyEnabled false
debuggable true
applicationIdSuffix ".debug" // 调试包名后缀
}
}
// 风味维度(如免费版 vs 付费版,国内版 vs 国际版)
flavorDimensions "version"
productFlavors {
free {
dimension "version"
applicationIdSuffix ".free"
}
paid {
dimension "version"
applicationIdSuffix ".paid"
}
}
// Java 编译选项
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
// 视图绑定(替代 findViewById)
buildFeatures {
viewBinding true
}
// 资源压缩
buildTypes {
release {
shrinkResources true
}
}
// 源集配置:不同 build type / flavor 可拥有独立源码和资源
sourceSets {
main {
java.srcDirs = ['src/main/java']
res.srcDirs = ['src/main/res']
}
debug {
// src/debug/java、src/debug/res 会自动被识别
}
}
}
// 依赖(类似 package.json 的 dependencies)
dependencies {
// AndroidX 核心库
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
// Jetpack 组件
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.7.0'
implementation 'androidx.lifecycle:lifecycle-livedata:2.7.0'
implementation 'androidx.navigation:navigation-fragment:2.7.6'
implementation 'androidx.navigation:navigation-ui:2.7.6'
implementation 'androidx.room:room-runtime:2.6.1'
// 网络请求
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
// 图片加载
implementation 'com.github.bumptech.glide:glide:4.16.0'
// JSON 解析
implementation 'com.google.code.gson:gson:2.10.1'
// 老项目中常见的依赖
implementation 'com.jakewharton:butterknife:10.2.3' // 视图绑定(老项目)
// 测试依赖
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:5.8.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}Build Variants 与 Source Sets
结合 buildTypes 和 productFlavors,Gradle 会生成所有可能的构建变体(Build Variants):
buildTypes: debug, release
productFlavors: free, paid
生成的变体:
- freeDebug
- freeRelease
- paidDebug
- paidRelease每个变体可以有自己的源码目录:
app/src/
├── main/ # 所有变体共享
├── debug/ # 仅 debug 变体
├── release/ # 仅 release 变体
├── free/ # 仅 free flavor
├── paid/ # 仅 paid flavor
├── freeDebug/ # 仅 free + debug 组合
└── paidRelease/ # 仅 paid + release 组合// src/debug/java/com/example/myapp/Config.java
public class Config {
public static final String API_BASE_URL = "https://api-staging.example.com";
}
// src/release/java/com/example/myapp/Config.java
public class Config {
public static final String API_BASE_URL = "https://api.example.com";
}前端对照:类似
.env.development和.env.production,但更强大——可以替换整个类或资源文件。
3.6 依赖配置类型
| Gradle 配置 | 含义 | npm 对应 |
|---|---|---|
implementation | 编译和运行时可用,不暴露给依赖者 | dependencies |
api | 同 implementation,但暴露给依赖者 | 无直接对应 |
compileOnly | 仅编译时可用 | devDependencies(近似) |
runtimeOnly | 仅运行时可用 | 无直接对应 |
testImplementation | 仅测试时可用 | devDependencies(测试相关) |
androidTestImplementation | 仅设备测试时可用 | devDependencies(E2E 测试) |
3.7 依赖仓库
repositories {
google() // Google Maven 仓库(AndroidX、Material)
mavenCentral() // Maven Central(大部分开源库)
jcenter() // ⚠️ 已废弃,但老项目可能还在用
maven { url 'https://jitpack.io' } // JitPack(GitHub 项目直接引用)
}3.8 常用 Gradle 命令
# 清理构建(类似 rm -rf dist/ node_modules/.cache)
./gradlew clean
# 构建 Debug APK
./gradlew assembleDebug
# 构建 Release APK
./gradlew assembleRelease
# 安装到设备
./gradlew installDebug
# 运行单元测试
./gradlew test
# 运行设备测试
./gradlew connectedAndroidTest
# 查看所有可用任务
./gradlew tasks
# 查看依赖树(类似 npm ls)
./gradlew app:dependencies
# 查看构建时间
./gradlew assembleDebug --profile4. 资源系统(res/)
Android 的资源系统非常结构化,类似前端项目中的 public/ + src/styles/ + src/assets/ 的组合。
4.1 res/ 目录结构
res/
├── layout/ # XML 布局文件(页面/组件的 UI 定义)
│ ├── activity_main.xml
│ ├── fragment_home.xml
│ └── item_user.xml # 列表项布局
├── values/ # 值资源(字符串、颜色、尺寸、样式)
│ ├── strings.xml # 字符串常量
│ ├── colors.xml # 颜色定义
│ ├── dimens.xml # 尺寸定义
│ ├── themes.xml # 主题定义
│ └── styles.xml # 样式定义
├── drawable/ # 可绘制资源
│ ├── ic_home.xml # 矢量图标
│ ├── bg_button.xml # 按钮背景形状
│ └── selector_tab.xml # 状态选择器
├── mipmap-xxxhdpi/ # 应用图标(不同分辨率)
├── menu/ # 菜单定义
├── anim/ # 动画定义
├── xml/ # XML 配置文件
├── raw/ # 原始资源(音频、视频等)
└── navigation/ # 导航图4.2 资源引用
在 Java 代码和 XML 中通过 R 类引用资源:
// R 类是自动生成的,包含所有资源的 ID
// 格式:R.资源类型.资源名称
// 在 Java 代码中引用
setContentView(R.layout.activity_main); // 引用布局文件
String appName = getString(R.string.app_name); // 引用字符串
int color = getColor(R.color.primary); // 引用颜色
imageView.setImageResource(R.drawable.ic_home); // 引用图片<!-- 在 XML 中引用 -->
<TextView
android:text="@string/hello_world"
android:textColor="@color/primary"
android:textSize="@dimen/text_size_large"
android:background="@drawable/bg_button" />R.java 的生成机制
编译时,AAPT2(Android Asset Packaging Tool)会扫描 res/ 目录,为每个资源生成一个整数 ID,最终汇总到自动生成的 R.java 中:
// 自动生成,不要手动修改
public final class R {
public static final class layout {
public static final int activity_main = 0x7f030004;
}
public static final class id {
public static final int tv_title = 0x7f080059;
}
public static final class string {
public static final int app_name = 0x7f0b001f;
}
// ...
}前端对照:类似 Webpack/Vite 给资源文件生成一个
import.meta.glob或模块 ID,让你可以通过符号名引用资源。
常见 R 文件错误:
| 错误 | 原因 | 解决 |
|---|---|---|
cannot find symbol class R | 资源编译失败或缓存问题 | Build → Clean Project / Rebuild |
R.id.xxx 找不到 | 布局中 ID 写错或未编译 | 检查 XML、重新 Sync |
AAPT: resource not found | 引用了不存在的资源 | 检查资源文件名和 ID |
4.3 values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">我的应用</string>
<string name="hello_world">你好,世界!</string>
<!-- 带参数的字符串 -->
<string name="welcome_message">欢迎,%1$s!你有 %2$d 条消息。</string>
<!-- 字符串数组 -->
<string-array name="week_days">
<item>周一</item>
<item>周二</item>
<item>周三</item>
</string-array>
</resources>// 使用
String appName = getString(R.string.app_name);
String welcome = getString(R.string.welcome_message, "张三", 5);
// → "欢迎,张三!你有 5 条消息。"
String[] days = getResources().getStringArray(R.array.week_days);4.4 values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primary">#FF6200EE</color>
<color name="primary_dark">#FF3700B3</color>
<color name="accent">#FF03DAC5</color>
<color name="text_primary">#DE000000</color>
<color name="text_secondary">#99000000</color>
<color name="background">#FFFFFFFF</color>
<!-- 带透明度的颜色 (AARRGGBB) -->
<color name="overlay">#80000000</color>
</resources>4.5 values/dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- dp:密度无关像素,用于布局尺寸(类似 CSS 的 rem) -->
<dimen name="padding_small">8dp</dimen>
<dimen name="padding_medium">16dp</dimen>
<dimen name="padding_large">24dp</dimen>
<dimen name="button_height">48dp</dimen>
<!-- sp:缩放像素,用于字体大小(会随系统字体设置缩放) -->
<dimen name="text_size_small">12sp</dimen>
<dimen name="text_size_medium">16sp</dimen>
<dimen name="text_size_large">20sp</dimen>
</resources>单位说明:
| Android 单位 | 说明 | CSS 对应 |
|---|---|---|
dp (density-independent pixel) | 不随屏幕密度变化的像素 | rem(近似) |
sp (scale-independent pixel) | 类似 dp,但跟随系统字体大小设置 | rem(用于字体) |
px | 物理像素 | px(不推荐) |
经验法则:布局尺寸用
dp,字体大小用sp,永远不要用px。
4.6 values/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- 应用主题(类似 CSS 的 :root 变量 + 全局样式) -->
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primary_dark</item>
<item name="colorAccent">@color/accent</item>
<!-- 状态栏颜色 -->
<item name="android:statusBarColor">?attr/colorPrimaryDark</item>
</style>
</resources>5. BuildConfig 与版本管理
5.1 BuildConfig
Gradle 会自动生成 BuildConfig 类,包含构建配置信息:
// BuildConfig 是自动生成的
public final class BuildConfig {
public static final boolean DEBUG = true;
public static final String APPLICATION_ID = "com.example.myapp.debug";
public static final String BUILD_TYPE = "debug";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0.0";
}
// 在代码中使用
if (BuildConfig.DEBUG) {
Log.d("App", "这是调试版本");
}
String baseUrl = BuildConfig.DEBUG
? "https://api-staging.example.com"
: "https://api.example.com";5.2 自定义 BuildConfig 字段
// app/build.gradle
android {
defaultConfig {
buildConfigField "String", "API_BASE_URL", '"https://api.example.com"'
buildConfigField "int", "MAX_RETRY_COUNT", "3"
buildConfigField "boolean", "ENABLE_ANALYTICS", "false"
}
buildTypes {
debug {
buildConfigField "String", "API_BASE_URL", '"https://api-staging.example.com"'
buildConfigField "boolean", "ENABLE_ANALYTICS", "false"
}
release {
buildConfigField "String", "API_BASE_URL", '"https://api.example.com"'
buildConfigField "boolean", "ENABLE_ANALYTICS", "true"
}
}
}6. 签名配置
发布到应用商店需要签名:
// app/build.gradle
android {
signingConfigs {
release {
storeFile file("keystore/release.jks")
storePassword "your_store_password"
keyAlias "your_key_alias"
keyPassword "your_key_password"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}安全提示:不要把签名文件和密码提交到 Git。使用
local.properties或环境变量管理敏感信息。
7. ProGuard / R8 代码混淆
# proguard-rules.pro
# 保留所有实现 Serializable 的类
-keepclassmembers class * implements java.io.Serializable { *; }
# 保留 Gson 模型类
-keep class com.example.myapp.model.** { *; }
# 保留 Retrofit 接口
-keep,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# 保留枚举
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}类似前端的:Terser / UglifyJS 压缩和混淆。
8. 接手老项目时的 Gradle 检查清单
打开一个老项目时,按以下顺序检查:
gradle-wrapper.properties:确认 Gradle 版本,不要随意升级- 项目级
build.gradle:确认 Android Gradle Plugin (AGP) 版本 - 模块级
build.gradle:compileSdk:编译目标版本minSdk:最低支持版本targetSdk:目标运行版本dependencies:使用的第三方库
settings.gradle:确认模块结构gradle.properties:确认全局配置
AGP 与 Gradle 版本对照表
| AGP 版本 | 最低 Gradle 版本 | 最低 JDK |
|---|---|---|
| 8.2.x | 8.2 | 17 |
| 8.1.x | 8.0 | 17 |
| 8.0.x | 8.0 | 17 |
| 7.4.x | 7.5 | 11 |
| 7.3.x | 7.4 | 11 |
| 7.2.x | 7.3.3 | 11 |
| 7.1.x | 7.2 | 11 |
| 7.0.x | 7.0 | 11 |
| 4.2.x | 6.7.1 | 8 |
| 4.1.x | 6.5 | 8 |
常见 Sync 失败及解决
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
Could not find com.android.tools.build:gradle:X.X.X | AGP 版本与 Gradle 版本不匹配 | 检查版本对照表 |
Unsupported class file major version XX | JDK 版本太低 | 升级 JDK |
Could not resolve all files for configuration | 依赖下载失败 | 检查网络/镜像配置 |
SDK location not found | 未配置 SDK 路径 | 检查 local.properties |
Duplicate class found | 依赖冲突,两个库包含同名类 | 使用 ./gradlew app:dependencies 排查并排除 |
Manifest merger failed | 多模块清单属性冲突 | 查看 app/build/intermediates/merged_manifest |
AAPT2 error: check logs for details | 资源文件命名或格式错误 | 检查 res/ 目录下的文件名、XML 语法 |
Method count exceeded 64K | 方法数超过 65536 | 启用 multiDexEnabled true |
# 查看完整依赖树,排查冲突
./gradlew app:dependencies --configuration releaseRuntimeClasspath
# 只查看有冲突的依赖
./gradlew app:dependencies --configuration releaseRuntimeClasspath | grep "\->" | sort | uniq前端开发者备忘
| 前端概念 | Android 对应 | 备注 |
|---|---|---|
package.json | build.gradle | 依赖和项目配置 |
npm install | Gradle Sync | 下载依赖 |
dependencies | implementation 'group:artifact:version' | 依赖声明格式不同 |
.env | buildConfigField + BuildConfig | 环境配置 |
index.html | AndroidManifest.xml + activity_main.xml | 入口定义 |
| 路由配置 | AndroidManifest.xml 中的 <activity> | 页面注册 |
dist/ | build/outputs/apk/ | 构建产物 |
.nvmrc | gradle-wrapper.properties | 工具版本锁定 |
| CSS 变量 | values/colors.xml + values/dimens.xml | 全局样式变量 |
@media 查询 | 资源限定符(values-xxhdpi/ 等) | 适配不同屏幕 |
public/ | assets/ | 不编译的原始资源 |
| Tree-shaking | R8 / ProGuard | 移除未使用的代码 |
下一步
了解了项目结构后,接下来学习 模块 04:Activity 与 Fragment,理解 Android 应用的页面和生命周期。