Android | 创建第一个项目、AAPT2的两个阶段(编译、链接)

55 阅读16分钟

一、创建第一个Android项目

1.1 环境搭建

1.1.1 准备工具

  • Android Studio - 核心开发环境

    • 是什么:Google 官方推出的集成开发环境,基于 JetBrains 的 IntelliJ IDEA 构建。你所有的编码、设计、调试和测试工作都将在这里完成。

    • 下载地址developer.android.com/studio

      image-20251101170538426

    • 说明:它内置了接下来要提到的 Android SDK 和模拟器,所以你只需要下载这个,大部分依赖都会自动搞定。

      image-20251101163847697

  • Java Development Kit 或 Kotlin - 编程语言

    • 是什么

      • JDK:如果你选择使用 Java 语言进行开发,需要安装 JDK。

      • Kotlin:这是 Google 官方推荐的 Android 开发语言,更现代、更安全、更简洁。好消息是,Android Studio 已经内置了 Kotlin,所以你不需要单独安装。

      建议:对于新手,强烈推荐直接学习 Kotlin。它是未来的趋势。

    • 推荐使用OpenJDK:我选择的是zulu-17,下载地址Java 8, 11, 17, 21, 25 Download for Linux, Windows and macOS,选择**.msi安装包**,直接自动安装即可。

      image-20251101164508258

  • Android SDK - 软件开发工具包

    • 是什么:包含了编译、调试和运行 Android 应用所需的所有库、API 和工具。

    • 说明:Android Studio 在安装过程中会自动下载最新的 SDK,所以你通常不需要手动处理。

      image-20251119003612507

  • 可用于测试的 Android 设备

    • 选择一:物理安卓手机或平板(推荐给新手)

      • 优点:性能真实,感受直接。

      • 准备工作

        1. 开启手机的“开发者选项”。(通常是在“关于手机”里连续点击“版本号”10次,不同品牌会具备不同的差异)
        2. 在开发者选项中开启“USB 调试”。
        3. 用 USB 数据线连接电脑和手机。
    • 选择二:Android 虚拟设备 - 模拟器

      • 是什么:在电脑上模拟一台安卓手机。

      • 优点:无需实体设备,可以创建不同型号和系统版本的手机进行测试。

      • 缺点:比较占用电脑资源,运行速度可能较慢。

      • 创建方法

        • (1)在 Android Studio 的 AVD Manager 中创建。

        • (2)使用 雷电模拟器,就是同样的也需要和 选择一打开 开发者模式的步骤一样,就在设备选择出选择雷电模拟器出现的模拟器。

1.1.2 推荐工具

  • 反编译工具

    Android 反编译工具,能把 APK、DEX、JAR 等字节码文件直接转换成可读的 Java 源码

  • PxCook - 像素大厨

    像素大厨,是一款交互流畅、全平台支持的切图设计工具,专为UI设计师所设计

1.2 创建一个Android程序

1.2.1 创建一个HelloWorld项目

在Android Studio的窗口点击【New Project】选项,进入【Empty Views Activity】选项

image-20251101201905114

  • Package name(包名),这是最重要规则最严格的字段,它作为应用的唯一标识。
    • 唯一性: 在整个Google Play商店中必须是唯一的。如果com.itzy.application已被占用,你的应用将无法上传。
    • 逆向域名规则: 通常使用你拥有的或你公司拥有的域名的逆向形式,以确保唯一性。例如,如果你的网站是itzy.com,包名就应该是com.itzy.yourappname
    • 永久性: 一旦应用发布,绝对不要更改包名。更改包名等同于创建一个全新的应用,会失去所有已有的用户和下载数据。
  • Minimum SDK(最低SDK版本),在 “设备覆盖率”“能使用的新API功能” 之间进行权衡。
    • 遵守API级别约束: 在代码中,如果你调用的API级别高于你设置的最低SDK,必须进行版本检查,否则应用在旧系统上会崩溃。
    • 推荐选择: 通常建议选择当前有足够市场占有率且能支持你所需功能的版本。
      • 版本选得越低,能覆盖的设备越多,但你不能使用很多新的、好用的API。
      • 版本选得越高,能使用更多现代API,开发更便捷,但会放弃一部分使用旧系统的用户。
    • image-20251101203632480
  • Build configuration language(构建配置语言)
    • Groovy DSL“经典模式”:成熟、灵活、脚本简洁,但工具支持弱。
    • Kotlin DSL“现代模式”:类型安全、工具支持强大、重构友好。

image-20251101210941349

1.2.2 启动模拟器

​ Hello World程序已经在Android Studio自动为我们生成项目的过程中就已经具备了。

​ 当我们通过一个展示的运行程序的Android手机媒体(载体)呈现就好了,在这里我们就启动Android模拟器就行。

方式一:创建虚拟设备

image-20251101220305785

image-20251101211957476

我们看到以下

image-20251101212338373

  • Google APIs 镜像 = AOSP系统 + Google服务框架和API

  • Google Play 镜像 = AOSP系统 + Google服务框架和API + Google Play商店及相关认证

方式二:连接远程设备

前提条件

  • 手机和电脑在同一 Wi-Fi
  • 手机已开启开发者选项USB 调试

无线调试 是 Android 11 及以上系统版本引入的一项原生开发功能。它允许开发者通过 WiFi 网络,而非传统的 USB 数据线,将电脑与安卓设备连接,以使用 Android 调试桥 (ADB) 执行所有调试命令。

image-20251101220554024转存失败,建议直接上传图片文件
  • 方法一:QR配对操作方法:
  • 方法二:配对码配对:

    PS:注意下方两图,仅仅为展示如何操作,配对码并无对应关系。

    • 移动端

      image-20251101222833466

    • 电脑端

image-20251101222408683转存失败,建议直接上传图片文件

1.2.3 运行程序

当前我们的模拟器已经启动,图标为▶️,更下拉列表的右侧,会显示可用的设备。

image-20251101225244894

可以看到,项目已经运行成功,并且在模拟器或者我们的物理的手机上会已经安装上应用程序名称My Application的启动器。

image-20251101232122334

1.3 分析此Android程序

​ Android应用启动时,系统根据AndroidManifest.xml中注册的MainActivity配置(其中声明了该Activity为LAUNCHER入口),调用其onCreate()方法,通过setContentView()加载并显示定义在activity_main.xml中的布局文件,从而规范地展示首页面,进而显示的“Hello World“的页面。

​ 在AndroidManifest.xml中,通过<intent-filter>标签将MainActivity定义为首页面,其中指定该Activity为主要入口点,<category android:name="android.intent.category.LAUNCHER" />使其出现在应用启动器中,这样系统在应用启动时就会首先加载并显示这个Activity。

二、项目结构概览

当该Android程序运行时候,我们需要将Androd结构改为项目级结构。

image-20251101233924866

2.1 项目目录项目文件

2.1.1 根目录项目文件 & 文件夹

  • .gradle & .idea

    • IDE(Android Studio)自动生成的配置和缓存文件。
  • app/

    • 主要的应用模块,包含应用的代码和资源。我们今后的开发工作也基本是和这个打交道。
  • build/

    • 说明: 这是Gradle构建过程的输出目录
    • 与app/build的区别:这个是项目级别的,app/build是模块级别的
  • gradle/

    • 包含 Gradle 包装器(Wrapper)文件,用于确保构建环境一致。重要性:确保团队成员使用相同版本的Gradle

      • wrapper/gradle-wrapper.jar - Gradle包装器JAR文件,被命令行脚本直接调用

        image-20251102023819621

      • wrapper/gradle-wrapper.properties - 指定使用的Gradle版本,被Gradle包装器运行时读取。

        构建项目时会自动根据gradle-wrapper.properties属性查找是否下载相应的gradle版本,如果没有就distributionUrl的网址

      • libs.versions.toml → 在Gradle配置文件中被引用,管理所有依赖版本, Gradle Version Catalogs 的核心

        libs.versions.tomlGradle版本目录文件,它的主要目的是集中统一管理项目中的所有依赖库版本

        image-20251102024412851

2.1.2 根目录配置文件

  • .gitignore

    • 说明Git版本控制系统的忽略配置文件

    • 作用: 告诉Git哪些文件或目录不应该被跟踪和提交到代码仓库。例如,它会忽略 .gradle/, .idea/, build/, local.properties 等自动生成或包含本地环境信息的文件,避免污染代码库。

      # 忽略的文件示例
      .gradle/
      .idea/
      *.iml
      local.properties
      .DS_Store
      build/
      
  • build.gradle(项目级)

    • 定义整个项目的 Gradle 构建配置。

    • 作用

      • 定义所有模块共用的构建脚本依赖(如Android Gradle插件)。
      • 配置所有模块共用的仓库(如Google, Maven Central)和依赖项。
      // 顶层构建文件,您可以在其中添加所有子项目/模块共用的配置选项。
      buildscript {
          repositories {
              google() // 引入Google的Maven仓库
              mavenCentral() // 引入Maven中央仓库
          }
          dependencies {
              classpath "com.android.tools.build:gradle:7.0.4" // 指定Android Gradle插件版本
          }
      }
      
  • settings.gradle

    • 说明: 这个文件用于告诉Gradle本项目包含了哪些模块
    • 作用: 当你创建一个新的模块(例如 library)时,需要在这里通过 include ‘:app’, ‘:library’ 来声明,Gradle才会在构建时将其包含进来。
  • gradle.properties

    • gradle.properties 是 Gradle 构建工具的配置文件,主要用于管理项目的全局设置和构建环境。

      • gradle.properties:管构建"怎么运行"(环境、性能、开关)- 构建过程配置构建工具的工作方式

        # 影响Gradle如何"工作"
        org.gradle.jvmargs=-Xmx2048m        # Gradle进程的内存大小
        org.gradle.caching=true             # 是否启用构建缓存
        android.nonTransitiveRClass=true    # 资源处理方式
        
      • libs.versions.toml:管项目"用什么库"(依赖版本、插件版本)- 项目依赖配置项目需要哪些第三方库

        # 影响项目"包含什么"
        [versions]
        kotlin = "1.9.0"                    # 使用的Kotlin版本
        
        [libraries]
        retrofit = "2.9.0"                  # 网络库版本
        glide = "4.15.1"                    # 图片加载库版本
        
  • gradlew & gradlew.bat

    • gradlew (用于 macOS/Linux/Unix 系统)
    • gradlew.bat (用于 Windows 系统)
  • local.properties

    • 说明: 这个文件包含了本地开发环境的配置

    • 作用: 最主要的是配置了本机 Android SDK 的路径(例如 sdk.dir=D\:\\develop\\Android\\sdk)。

    • 注意事项: 因为这个路径每台电脑都可能不同,所以绝对不能提交到版本控制中。

2.1.3 应用模块 (app/) 详解

  • **app/src/**这是源代码的根目录,它被分为几个“源代码集”:

    • app/src/main/ - 主源代码集,存放应用的主要代码和资源。

      • java/: 存放所有的Java或Kotlin源代码文件,按照包名结构组织。你的 MainActivity 等类都在这里。

      • res/: 存放所有的静态资源文件

        • layout/: XML布局文件。

          image-20251102032327139

        • drawable//mipmap/: 图片、图标和矢量图资源。

        • values/: 字符串(strings.xml)、颜色(colors.xml)、尺寸(dimens.xml)等常量定义。

          <resources>
              <string name="app_name">My Application</string>
          </resources>
          

          image-20251102032415278

      • AndroidManifest.xml: 应用的“身份证”。它向Android系统声明应用的基本信息,如包名、组件(Activity, Service等)、所需权限、最低API级别等。

        • <?xml version="1.0" encoding="utf-8"?>
          <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.example.myapp"> <!-- 应用的唯一包名 -->
          
              <application
                  android:allowBackup="true"
                  android:icon="@mipmap/ic_launcher" <!-- 应用图标 -->
                  android:label="@string/app_name" <!-- 应用名称,引用自 strings.xml -->
                  android:theme="@style/Theme.MyApp">
                  
                  <!-- 声明一个 Activity(应用的一个界面) -->
                  <activity
                      android:name=".MainActivity"
                      android:exported="true"> <!-- 该 Activity 是否允许其他应用启动 -->
                      <intent-filter>
                          <!-- 指定这个 Activity 是应用的“主入口” -->
                          <action android:name="android.intent.action.MAIN" />
                          <!-- 将其放入应用的启动器中 -->
                          <category android:name="android.intent.category.LAUNCHER" />
                      </intent-filter>
                  </activity>
              </application>
          
              <!-- 声明应用需要的权限 -->
              <uses-permission android:name="android.permission.INTERNET" />
          </manifest>
          
    • app/src/androidTest/ - 仪器化测试源代码集。

      • 这些测试需要运行在Android设备或模拟器上,可以测试与Android框架交互的代码。
    • app/src/test/ - 本地单元测试源代码集。

      • 这些测试运行在本地JVM上,速度很快,用于测试不依赖于Android框架的业务逻辑。
  • build/

    • 作用: 当你编译项目时,所有生成的文件都会放在这里,例如编译后的类文件(.class)、资源文件(经过处理的)、以及最终的APK或AAB安装包。

      文件类型典型位置 (在 app/ Module 内)备注
      APK 文件build/outputs/apk/[buildVariant]/构建变体可以是 debug, release, 或 yourFlavorDebug 等。
      .class 文件build/intermediates/javac/[buildVariant]/classes/Java 编译后的字节码。
      .class 文件 (Kotlin)build/tmp/kotlin-classes/[buildVariant]/Kotlin 编译后的字节码。
    • 注意事项: 这是一个“生成”目录,可以随时安全删除(Clean Project 操作就是删除它),重建后会再次生成。必须列入 .gitignore

      • (1)APK 文件的位置

        • 在新版本中,APK 默认生成在项目的 build 目录下,并且根据构建变体(Build Variant)进行了细分。

          典型路径结构:

          依次展开目录:app -> build -> outputs -> apk。在这里你可以看到所有生成的 APK。

          根据构建类型(debug, release)产品风味(flavor) 命名的子文件夹。

          你的项目根目录 / app / build / outputs / apk /
          

          调试版 APK:你的项目根目录/app/build/outputs/apk/debug/app-debug.apk

          发布版 APK:你的项目根目录/app/build/outputs/apk/release/app-release.apk

          多个风味(Flavors):你的项目根目录/app/build/outputs/apk/yourFlavorName/debug/

          image-20251102005926807

        • 手动构建 APK

          点击菜单栏的 BuildBuild Bundle(s) / APK(s)APK(s)

          image-20251102005600257

      • (2).class 文件的位置

      .class 文件是 Java/Kotlin 代码编译后的字节码文件。在 Android 中,它们最终会被打包进 DEX 文件中,然后放入 APK。所以你通常不需要直接操作它们。

      它们位于项目的 build 目录下的 intermediates 文件夹里。

      典型路径:

      你的项目根目录 / app / build / intermediates / javac / 
      

      在这个 javac 目录下,你会找到根据构建变体命名的文件夹,里面包含编译后的 .class 文件。

      例如,对于调试版本: 你的项目根目录/app/build/intermediates/javac/debug/classes/

      image-20251102005516348

      在这个 classes 目录下,你会看到与你项目包名对应的目录结构,里面就是所有的 .class 文件。

      对于 Kotlin 代码: 路径类似,但在 kotlin 目录下: 你的项目根目录/app/build/tmp/kotlin-classes/debug/

      image-20251102005449754

      重要提示build 目录是编译时自动生成的。你可以通过菜单栏的 “Build” -> “Rebuild Project” 来确保所有文件都是最新的。如果你执行了 “Build” -> “Clean Project”,这个 build 文件夹会被删除,并在下次编译时重新生成。

2.2 资源的管理使用

Android程序在使用资源(即:代码使用的外部文件),这些文件作为了我们实现代码效果的一部分,经过编译过程到了app中。

2.2.1 规范

(1)命名规范
- 使用小写字母、数字和下划线
- 描述性名称:`模块_用途_状态`
  • 图片:ic_ (图标), bg_ (背景), img_ (图片)
  • 颜色:color_primary, color_text_secondary
  • 尺寸:padding_medium, text_size_large
  • 字符串:title_main, message_welcome
(2)多资源分配 - 资源限定符

在深入分类之前,必须理解 资源限定符。它是通过为 res/ 子目录添加后缀(如 -en, -hdpi, -land),来为不同设备配置提供替代资源的关键机制。系统会根据当前设备配置自动选择最匹配的资源。

res/
├── values/                 # 默认资源
├── values-zh/             # 中文
├── values-en/             # 英文
├── layout/                # 默认布局
├── layout-land/           # 横屏布局
├── layout-sw600dp/        # 7寸平板
├── drawable-mdpi/         # 中等密度
└── drawable-xxhdpi/       # 超高密度
限定符用途示例
-en语言values-en/
-night主题values-night/
-sw600dp最小宽度layout-sw600dp/
-land横屏layout-land/
-v26API级别values-v26/
(3) 资源引用方式总结
资源类型XML中引用代码中引用
字符串@string/nameR.string.name
颜色@color/nameR.color.name
尺寸@dimen/nameR.dimen.name
图片@drawable/nameR.drawable.name
布局@layout/nameR.layout.name
样式@style/nameR.style.name
(4)为什么没有R.java,反而是R.txt

Android Gradle 插件直接生成相应的字节码,不会制作中间R.java文件。

Android Developers Blog: Android Studio 3.6

image-20251115135405092

  • R.java 源文件不再生成到 build/generated/... 目录下

  • 资源 ID 仍然存在,但直接以 .class 字节码 形式生成(例如 R.class),而不是 .java 源码。

    image-20251115140418445

  • 这是为了加快编译速度、减少 I/O 和避免不必要的源码处理。

(5)AAPT2介绍

AAPT2(Android 资源打包工具)是一种构建工具,Android Studio 和 Android Gradle 插件使用它来编译和打包应用的资源

AAPT2 会解析资源、为资源编制索引,并将资源编译为针对 Android 平台进行过优化的二进制格式。

image-20251115141459989

image-20251115141548336

2.2.2 资源调用

在Android中,资源是一类代码使用过程中附加的文件和静态内容,例如位图、布局定义、用户界面字符串、动画指令等。我们将资源放置在项目目录的 res/ 下特定子目录中。Android 资源编译工具 aapt2 会在编译时将其编译,并生成一个名为 R 的 Java类(或 R.java),作为访问这些资源的桥梁。

【0】将它们独立出来的核心目的在于
  1. 解耦与可维护性:将内容与逻辑分离。修改UI样式无需改动Java/Kotlin代码,反之亦然。
  2. 国际化与本地化:为不同语言、地区提供替代资源,系统会根据设备设置自动匹配。
  3. 设备兼容性:为不同屏幕尺寸、密度、方向、API等级等提供替代资源,实现自适应UI。
  4. 减少代码冗余:在多个地方使用的值(如主色调#3F51B5)只需定义一次,方便统一修改。
【1】编译阶段 - 生成 .flat 中间文件

在构建APK时,Android的构建工具(此时主要为AAPT2):

  • 命令格式:

    aapt2 compile [options] -o <输出目录> <输入文件>
    

PixPin_2025-11-03_13-17-58

// 输入:原始资源文件
resources/
  ├── values/strings.xml
  ├── layout/activity_main.xml  
  ├── drawable/ic_launcher.png
  └── ...

// 输出:编译后的中间格式
build/intermediates/
  ├── flat_files/
  │   ├── values_strings.arsc.flat
  │   ├── layout_activity_main.xml.flat
  │   └── drawable_ic_launcher.png.flat
  └── ...
  • 编译

    • 将XML资源文件(如布局、动画、菜单)编译成更高效的二进制XML格式。

    • 将值资源(如 strings.xml, colors.xml)编译成二进制格式。

    • 输入文件输出文件
      XML 资源文件,均位于 res/values/ 目录下。*.arsc.flat 作为扩展名的资源表。
      其他所有资源文件。res/values/ 目录下的文件以外的其他所有文件都将转换为扩展名为 *.flat 的二进制 XML 文件。
【2】链接阶段(Linking Phase)
# 链接所有编译后的资源
aapt2 link \
  -o build/outputs/apk/debug/app-debug.ap_ \
  --java build/generated/source/r/debug \
  --manifest src/main/AndroidManifest.xml \
  build/intermediates/res/*.flat
  • 将所有.flat文件合并成单个资源包

  • 分配唯一的资源ID(0x7fXXXXXX格式)

    • 资源ID结构:

      0xPPTTNNNN
      
      • PP: package id
      • TT: type id
      • NNNN: entry id

      image-20251102235308691

  • 生成R.txt文件(记录所有资源ID映射)

  • 创建resources.arsc资源索引表

他所有资源文件。 | 除 res/values/ 目录下的文件以外的其他所有文件都将转换为扩展名为 *.flat 的二进制 XML 文件。 |

【2】链接阶段(Linking Phase)
# 链接所有编译后的资源
aapt2 link \
  -o build/outputs/apk/debug/app-debug.ap_ \
  --java build/generated/source/r/debug \
  --manifest src/main/AndroidManifest.xml \
  build/intermediates/res/*.flat
  • 将所有.flat文件合并成单个资源包

  • 分配唯一的资源ID(0x7fXXXXXX格式)

    • 资源ID结构:

      0xPPTTNNNN
      
      • PP: package id
      • TT: type id
      • NNNN: entry id

      [外链图片转存中...(img-BmD3MpTa-1763515307649)]

  • 生成R.txt文件(记录所有资源ID映射)

  • 创建resources.arsc资源索引表

    • 包含所有资源的ID、类型、名称、路径、配置(如语言、分辨率)等。