第一次用 Android Studio 打开项目,左侧那一长串
app、res、manifests、gradle、build,是不是有点眼花?其实可以把一个 Android 工程想象成盖房子:
AndroidManifest.xml是报建蓝图,java/kotlin是水电管线(逻辑),res是装修材料(资源),build.gradle是施工合同(怎么盖、用什么材料、盖几层),而build/则是盖好之后的成品。搞清楚每个文件夹的角色,你才知道东西该往哪儿放。
本文带你把 Android 标准工程的目录结构一次理清:模块划分、资源限定符、测试目录分工、Gradle 与 Manifest 的关系,以及那些"约定优于配置"的潜规则。
一、Android Studio 视图的"障眼法"
刚上手时最容易踩的坑:你在 Android Studio 里看到的目录树,并不是磁盘上真实的文件结构。
Android Studio 默认使用Android 视图,它会把分散在磁盘各处的文件,按"逻辑用途"重新聚合展示,看起来更整洁。如果你想看磁盘上真实的物理结构,把左上角的下拉框从Android切到Project即可。
| 视图 | 看到的 | 用途 |
|---|---|---|
| Android(默认) | 逻辑聚合后的结构,隐藏构建产物 | 日常开发,找文件快 |
| Project | 磁盘真实目录 | 排查路径问题、改 Gradle、看build/产物 |
很多新手可能会问"为什么我的
AndroidManifest.xml和MainActivity不在同一层却显示在一起"——答案就是 Android 视图做了聚合。
二、典型模块与目录树
一个最小应用的app模块,磁盘上大致长这样:
app/ ├── src/main/ │ ├── AndroidManifest.xml # 应用蓝图:声明组件与权限 │ ├── java/ # Java/Kotlin 源码(按包名组织) │ │ └── com/example/helloworld/ │ │ ├── MainActivity.kt │ │ └── DetailsActivity.kt │ └── res/ # 资源目录(编译为 R 类) │ ├── drawable/ # 位图/矢量/形状/选择器 │ ├── layout/ # UI 布局 XML │ ├── mipmap/ # 启动图标(建议放这里,而非 drawable) │ ├── values/ # 字符串/颜色/尺寸/样式 │ ├── xml/ # 通用配置(备份规则、网络安全等) │ ├── font/ # 字体(可选) │ ├── raw/ # 原始资源:音频、JSON(可选) │ └── menu/ # 菜单资源(可选) ├── src/test/ # 本地单元测试(跑在 JVM 上) │ └── java/com/example/helloworld/ExampleUnitTest.kt ├── src/androidTest/ # 仪器化测试(跑在设备/模拟器上) │ └── java/com/example/helloworld/ExampleInstrumentedTest.kt ├── build.gradle.kts # 模块级构建脚本 ├── proguard-rules.pro # R8/ProGuard 混淆规则 └── lint.xml # Lint 配置(可选)往上一层,是项目根目录:
MyApp/ ├── app/ # 应用模块(上面那棵树) ├── build.gradle.kts # 项目级构建脚本(全局配置) ├── settings.gradle.kts # 声明有哪些模块、仓库源 ├── gradle.properties # Gradle 全局属性(JVM 参数、开关) ├── gradle/ │ └── libs.versions.toml # 版本目录(Version Catalog,集中管理依赖版本) ├── gradlew / gradlew.bat # Gradle Wrapper 脚本(保证团队用同一版本 Gradle) └── local.properties # 本地 SDK 路径(不提交 Git)注意:
local.properties记录的是你这台机器的 SDK 路径,每个人都不一样,所以它默认被.gitignore忽略,千万别提交到 Git。
三、res资源目录与限定符
res是 Android 最有特色的设计之一。它不只是"放图片的文件夹",而是一套自动适配机制:你为不同屏幕、语言、深色模式准备多套资源,系统在运行时根据设备配置自动挑选合适的那一份。
常见资源类型
| 目录 | 放什么 | 备注 |
|---|---|---|
drawable/ | 位图、矢量图、shape、selector | 优先用矢量图 |
mipmap/ | 应用启动图标ic_launcher | 图标专用,系统会保留更高密度版本 |
layout/ | 界面布局 XML | 可按方向/尺寸做变体 |
values/ | strings.xml、colors.xml、dimens.xml、themes.xml | 简单键值 |
xml/ | 备份规则、网络安全配置等 | 通用配置 |
raw/ | 音频、视频、JSON 等原始文件 | 不会被编译,原样打包 |
限定符(Qualifier)
在目录名后加-限定符,就能为特定配置提供专属资源:
| 维度 | 示例目录 | 含义 |
|---|---|---|
| 屏幕密度 | drawable-xxhdpi | 超高密度屏专用位图 |
| 屏幕方向 | layout-land | 横屏专用布局 |
| 深色模式 | values-night | 深色主题颜色 |
| 语言/区域 | values-zh-rCN、values-en-rUS | 多语言文案 |
| API 版本 | values-v26 | 仅 API 26+ 生效 |
举例:你把中文文案放values-zh/strings.xml,英文放values-en/strings.xml,系统会根据手机语言自动选择,代码完全不用改。
[!warning]
限定符有优先级和组合规则,多个限定符要按官方规定的顺序排列(如values-zh-rCN-night-v26),顺序写错会导致目录不被识别。
四、两种测试目录:test与androidTest
这是初学者最容易混淆的两个文件夹,它们跑在完全不同的地方:
| 维度 | src/test(本地单测) | src/androidTest(仪器化测试) |
|---|---|---|
| 运行环境 | 本地 JVM | 真机 / 模拟器 |
| 速度 | 快(毫秒级) | 慢(要装 APK、启动设备) |
| 能否用 Android API | 不能(默认是桩) | 能(真实系统环境) |
| 适用场景 | 业务逻辑、工具类、ViewModel | UI 测试、数据库、文件、权限 |
| 常用框架 | JUnit、Mockito、MockK | Espresso、UI Automator |
遵循"测试金字塔"策略:大量快速的单元测试打底,少量关键路径的 UI 测试封顶。别把所有逻辑都丢给昂贵的仪器化测试。
五、Gradle 与 Manifest 的关系
很多人疑惑:版本号、包名到底写在build.gradle还是AndroidManifest.xml?
现代 Android(AGP 7+)的答案:交给 Gradle。
// app/build.gradle.ktsandroid{namespace="com.example.helloworld"// 代码包名空间,取代 Manifest 里的 packagedefaultConfig{applicationId="com.example.helloworld"// 应用唯一标识(上架商店用)minSdk=24targetSdk=34versionCode=1// 内部版本号,每次发版递增versionName="1.0.0"// 用户看到的版本名}}注意namespace和applicationId的区别:
namespace:决定生成的R类和BuildConfig在哪个包下,纯粹是代码组织概念。applicationId:应用在设备和商店里的唯一身份证,可以和包名不一样(比如多渠道打包时给不同渠道不同的 ID)。
Manifest 合并(Manifest Merger)
你引入的每个第三方库可能都有自己的AndroidManifest.xml,构建时它们会被合并成最终的清单。冲突时可以用tools:命名空间干预:
<applicationxmlns:tools="http://schemas.android.com/tools"tools:replace="android:label"><!-- tools:replace 表示用本工程的值覆盖库里的同名属性 --></application>想看合并后的最终结果?打开AndroidManifest.xml,点击底部的Merged Manifest标签页。
六、图标、主题与可访问性
- 自适应图标:放在
mipmap-anydpi-v26/,分前景层 + 背景层,系统会根据厂商裁剪成圆形、方形、水滴形等。 - 主题:在
values/themes.xml与values-night/themes.xml分别定义浅色/深色主题,不要在布局里硬编码颜色,否则深色模式适配会变成噩梦。 - 多语言:所有用户可见文字都进
strings.xml,再配多语言副本。 - 无障碍:给有意义的图片设
android:contentDescription,纯装饰图设为@null,避免读屏软件念出无意义内容。
参考来源:
- Android 项目概览 · 官方文档
- 应用资源概览 · 官方文档
- 配置构建变体 · 官方文档
- 测试应用 · 官方文档