- 核心概念:Java 编译与 Android 构建的关系
- 使用命令行手动编译 (理解底层原理)
- 使用 Android Studio 自动化构建 (日常开发)
- 构建文件详解 (
build.gradle) - 常见问题与最佳实践
核心概念:Java 编译与 Android 构建的关系
首先要明确一个关键点:你不需要,也几乎不会手动去调用 javac 命令来编译 Android 项目中的 Java 代码。
Android 开发有一套完整的、自动化的构建系统,这个系统的核心是 Gradle。
整个构建过程大致如下:
- 源代码:你写的
.java(或.kt) 文件。 - 资源文件:布局文件 (
layout.xml)、字符串 (strings.xml)、图片等。 build.gradle文件:告诉 Gradle 如何编译你的项目,比如使用哪个 JDK、依赖哪些库、编译选项是什么等。- Gradle:作为构建工具,它会读取
build.gradle文件。- 它会启动一个 Java 编译器 (
javac),将你的.java文件编译成.class文件(Java 字节码)。 - 它会使用
dx工具(或d8,现代 Android Gradle 插件默认使用)将.class文件转换成 Android 平台能理解的.dex文件。 - 它会打包资源文件,并将
.dex文件和资源一起打包成最终的 APK (Android Package) 或 AAB (Android App Bundle) 文件。
- 它会启动一个 Java 编译器 (
“编译 Java” 这个动作,是 Android 构建流程中被 Gradle 自动执行的第一步,你的主要工作不是编译,而是编写 build.gradle 文件来配置编译过程。
方法一:使用命令行手动编译 (理解底层原理)
虽然不推荐在日常开发中使用,但通过手动编译,你可以更好地理解 Gradle 在后台做了什么。
假设项目结构如下:
MyApp/
├── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── myapp/
│ │ │ MainActivity.java
│ │ │ MyUtils.java
│ └── AndroidManifest.xml
└── libs/ <-- 假设我们有一个第三方库
└── third-party.jar
步骤 1: 编译 Java 源码
你需要找到 JDK 的 javac 工具,假设你的 JDK 安装在 C:\Program Files\Java\jdk-17\bin。
打开命令行,进入项目根目录 (MyApp/),然后执行以下命令:
# -d 指定输出目录 # -sourcepath 指定源代码路径 # -cp (classpath) 指定依赖的 JAR 文件路径 # src/main/java 是你的源代码根目录 javac -d build/classes -sourcepath src/main/java -cp "libs/third-party.jar" src/main/java/com/example/myapp/*.java
命令解释:
javac: Java 编译器命令。-d build/classes: 将编译生成的.class文件输出到build/classes目录下,并保持原有的包结构(com/example/myapp/MainActivity.class)。-sourcepath src/main/java: 告诉编译器去哪里找.java源文件。-cp "libs/third-party.jar": Classpath,告诉编译器在编译时,如果代码中引用了third-party.jar里的类,去哪里找它,如果你的项目依赖多个库,需要用分号 (, Windows) 或冒号 (, Linux/macOS) 分隔。src/main/java/com/example/myapp/*.java: 要编译的具体 Java 文件。
执行后,你会得到 build/classes 目录,里面包含了 .class 文件。
步骤 2: 将 .class 文件打包成 .dex 文件
这一步 Android SDK 提供了工具来完成,找到 Android SDK 中的 build-tools 目录,里面有 d8 或 dx 工具。
假设 build-tools 版本为 0.1,路径为 C:\Users\YourUser\AppData\Local\Android\Sdk\build-tools\33.0.1。
# 将 build/classes 目录下的所有 .class 文件打包成 classes.dex # --output 指定输出目录 d8 build/classes --output build/dex
执行后,你会得到 build/dex/classes.dex 文件。
步骤 3: 打包成 APK (简化版)
打包 APK 还需要处理资源、签名等,这是一个非常复杂的过程,手动完成几乎不现实,这正是 Gradle 的价值所在,这一步我们只做概念演示,实际操作请交给 Android Studio。
一个最简化的 APK 包含:
classes.dexAndroidManifest.xml- 资源文件
Android SDK 的 aapt (Android Asset Packaging Tool) 工具可以用来处理资源和清单文件,但最终打包成 APK 仍然很繁琐。
手动编译虽然可行,但过程繁琐、容易出错,且无法处理复杂的依赖和资源,我们强烈推荐使用 Android Studio。
方法二:使用 Android Studio 自动化构建 (日常开发)
这是目前唯一推荐的开发方式,Android Studio 集成了强大的 Gradle 支持,你只需要点击几下,所有复杂的编译、打包过程都会自动完成。
步骤:
- 创建项目:打开 Android Studio,创建一个新的 Android 项目。
- 编写代码:在
app/src/main/java目录下编写你的 Java/Kotlin 代码。 - 添加依赖:在
app/build.gradle文件的dependencies代码块中添加你需要的库。 - 构建项目:
- 方式一(推荐):点击顶部菜单栏的 Build -> Rebuild Project,这会强制重新编译所有模块。
- 方式二:点击工具栏上的 Build Variants,选择你想要的构建变体(如 debug, release),然后点击旁边的 Build APK 按钮。
- 方式三:直接点击 Run 'app' 按钮(绿色三角形),这会编译并安装到连接的模拟器或真机上。
Android Studio 底部的 Build 窗口会实时显示编译的日志,你可以看到 Gradle 在执行哪些任务,包括 compileDebugJavaWithJavac 等任务,这正是我们之前讨论的 Java 编译过程。
构建文件详解 (build.gradle)
Android 项目的编译行为完全由 build.gradle 文件控制,一个标准的项目通常有两个主要的 build.gradle 文件。
A. 项目级 build.gradle (Project: MyApp/build.gradle)
这个文件用于配置整个项目(所有模块)的设置。
// plugins 块是 AGP 7.0+ 的标准写法
plugins {
// 在顶层应用 Android 插件
id 'com.android.application' version '8.1.0' apply false // 版本号会更新
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false // 如果使用 Kotlin
}
// 所有模块共用的配置可以在这里定义
task clean(type: Delete) {
delete rootProject.buildDir
}
plugins块:声明项目使用的插件。com.android.application表示这是一个应用程序模块。version:指定 Android Gradle Plugin (AGP) 的版本,这个版本号非常重要,它决定了你可以使用的 Gradle 和 Android API 的特性。
B. 模块级 build.gradle (app/build.gradle)
这个文件定义了单个模块(通常是 app 模块)的具体构建配置,是配置编译逻辑的核心。
plugins {
id 'com.android.application'
}
android {
// 编译配置块
compileSdk 34 // 指定使用哪个 Android API 版本进行编译
defaultConfig {
applicationId "com.example.myapp"
minSdk 21 // 最低支持的 Android 版本
targetSdk 34 // 针对、优化和测试的目标版本
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false // 是否启用代码混淆
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
// debug 构建类型的配置
debug {
// ...
}
}
// 编译选项
compileOptions {
// 指定 JDK 版本
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
// 依赖配置块
dependencies {
// 编译时、运行时都需要的依赖
implementation 'androidx.appcompat:appcompat:1.6.1'
// 仅在编译时需要,打包时不会包含
// 一些注解处理器
compileOnly 'javax.annotation:jsr250-api:1.0'
// 仅在单元测试时需要
testImplementation 'junit:junit:4.13.2'
// 仅在 Android 仪器测试时需要
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
}
关键配置解释:
-
android { ... }:Android 专有的配置块。compileSdk:最重要的配置之一,它告诉 Gradle 使用哪个版本的 Android SDK 来编译你的代码和资源,使用最新的compileSdk可以让你使用最新的 API 和功能。defaultConfig:默认的配置。minSdk:应用可以运行的最低 Android 系统版本。targetSdk:你为这个版本进行过测试和优化的版本,当你的应用在targetSdk或更高版本的系统上运行时,可能会获得新的行为(例如更严格的权限管理)。
buildTypes:定义不同的构建类型,如debug和release。minifyEnabled:在release构建中是否启用 R8 代码混淆(Proguard 的替代品)。
compileOptions:配置 Java 编译选项。sourceCompatibility和targetCompatibility:指定你使用的 Java 语言版本,现代 Android 项目通常使用 Java 8 或更高版本。
-
dependencies { ... }:依赖管理块。implementation:最常用的依赖类型,表示这个依赖会被编译到你的 APK 中,并且你的代码和它的代码都会被编译进最终产物。api:与implementation类似,但如果你修改了这个依赖,所有依赖你的模块都需要重新编译,适用于核心库。compileOnly:只在编译时存在,运行时不会被打包进 APK。javax.annotation注解只在编译时被检查,运行时不需要。testImplementation/androidTestImplementation:分别用于单元测试和仪器测试的依赖。
常见问题与最佳实践
-
com.android.tools.build:gradle版本问题- 问题:编译时提示
com.android.tools.build:gradle版本过低或与gradle版本不兼容。 - 解决:确保项目级
build.gradle中的com.android.tools.build:gradle版本与项目根目录gradle/wrapper/gradle-wrapper.properties文件中的distributionUrl指定的 Gradle 版本兼容,可以参考 Android 官方兼容性表格。
- 问题:编译时提示
-
JDK 版本问题
- 问题:编译失败,提示
error: invalid source release: 17。 - 解决:检查
app/build.gradle中的compileOptions配置的 Java 版本,确保你的 Android Studio 和项目配置的 JDK 版本一致,推荐使用 JDK 17 或 11,并确保在 Android Studio 的File -> Project Structure -> SDK Location中设置了正确的 JDK 位置。
- 问题:编译失败,提示
-
如何检查编译结果?
- 编译成功后,生成的 APK 文件位于
app/build/outputs/apk/debug/app-debug.apk(debug 版) 或app/build/outputs/apk/release/app-release-unsigned.apk(release 版)。
- 编译成功后,生成的 APK 文件位于
-
最佳实践
- 始终使用最新的
compileSdk:除非有特殊原因,否则尽量使用最新的 Android API 进行编译,以获得更好的性能、新 API 和安全修复。 - 保持依赖更新:定期更新你的依赖库,以获取 bug 修复和安全补丁。
- 理解依赖类型:正确使用
implementation和api,可以加快编译速度,优先使用implementation。 - 利用 Android Studio 的提示:Android Studio 会智能地提示你配置问题,如缺少
compileSdk版本,务必关注这些提示。
- 始终使用最新的
希望这份详细的指南能帮助你完全理解 Android 项目中的 Java 编译过程!
