杰瑞科技汇

android 编译 java

  1. 核心概念:Java 编译与 Android 构建的关系
  2. 使用命令行手动编译 (理解底层原理)
  3. 使用 Android Studio 自动化构建 (日常开发)
  4. 构建文件详解 (build.gradle)
  5. 常见问题与最佳实践

核心概念:Java 编译与 Android 构建的关系

首先要明确一个关键点:你不需要,也几乎不会手动去调用 javac 命令来编译 Android 项目中的 Java 代码。

Android 开发有一套完整的、自动化的构建系统,这个系统的核心是 Gradle

整个构建过程大致如下:

  1. 源代码:你写的 .java (或 .kt) 文件。
  2. 资源文件:布局文件 (layout.xml)、字符串 (strings.xml)、图片等。
  3. build.gradle 文件:告诉 Gradle 如何编译你的项目,比如使用哪个 JDK、依赖哪些库、编译选项是什么等。
  4. Gradle:作为构建工具,它会读取 build.gradle 文件。
    • 它会启动一个 Java 编译器 (javac),将你的 .java 文件编译成 .class 文件(Java 字节码)。
    • 它会使用 dx 工具(或 d8,现代 Android Gradle 插件默认使用)将 .class 文件转换成 Android 平台能理解的 .dex 文件
    • 它会打包资源文件,并将 .dex 文件和资源一起打包成最终的 APK (Android Package)AAB (Android App Bundle) 文件。

“编译 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 目录,里面有 d8dx 工具。

假设 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 包含:

  1. classes.dex
  2. AndroidManifest.xml
  3. 资源文件

Android SDK 的 aapt (Android Asset Packaging Tool) 工具可以用来处理资源和清单文件,但最终打包成 APK 仍然很繁琐。

手动编译虽然可行,但过程繁琐、容易出错,且无法处理复杂的依赖和资源,我们强烈推荐使用 Android Studio


方法二:使用 Android Studio 自动化构建 (日常开发)

这是目前唯一推荐的开发方式,Android Studio 集成了强大的 Gradle 支持,你只需要点击几下,所有复杂的编译、打包过程都会自动完成。

步骤:

  1. 创建项目:打开 Android Studio,创建一个新的 Android 项目。
  2. 编写代码:在 app/src/main/java 目录下编写你的 Java/Kotlin 代码。
  3. 添加依赖:在 app/build.gradle 文件的 dependencies 代码块中添加你需要的库。
  4. 构建项目
    • 方式一(推荐):点击顶部菜单栏的 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:定义不同的构建类型,如 debugrelease
      • minifyEnabled:在 release 构建中是否启用 R8 代码混淆(Proguard 的替代品)。
    • compileOptions:配置 Java 编译选项。
      • sourceCompatibilitytargetCompatibility:指定你使用的 Java 语言版本,现代 Android 项目通常使用 Java 8 或更高版本。
  • dependencies { ... }:依赖管理块。

    • implementation:最常用的依赖类型,表示这个依赖会被编译到你的 APK 中,并且你的代码和它的代码都会被编译进最终产物。
    • api:与 implementation 类似,但如果你修改了这个依赖,所有依赖你的模块都需要重新编译,适用于核心库。
    • compileOnly:只在编译时存在,运行时不会被打包进 APK。javax.annotation 注解只在编译时被检查,运行时不需要。
    • testImplementation / androidTestImplementation:分别用于单元测试和仪器测试的依赖。

常见问题与最佳实践

  1. 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 官方兼容性表格
  2. 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 位置。
  3. 如何检查编译结果?

    • 编译成功后,生成的 APK 文件位于 app/build/outputs/apk/debug/app-debug.apk (debug 版) 或 app/build/outputs/apk/release/app-release-unsigned.apk (release 版)。
  4. 最佳实践

    • 始终使用最新的 compileSdk:除非有特殊原因,否则尽量使用最新的 Android API 进行编译,以获得更好的性能、新 API 和安全修复。
    • 保持依赖更新:定期更新你的依赖库,以获取 bug 修复和安全补丁。
    • 理解依赖类型:正确使用 implementationapi,可以加快编译速度,优先使用 implementation
    • 利用 Android Studio 的提示:Android Studio 会智能地提示你配置问题,如缺少 compileSdk 版本,务必关注这些提示。

希望这份详细的指南能帮助你完全理解 Android 项目中的 Java 编译过程!

分享:
扫描分享到社交APP
上一篇
下一篇