Linux 环境下 Android SDK 命令行工具安装与 CI 集成实践
简介面向 Linux 平台的 Android 命令行工具包专为需要在终端环境中管理 Android SDK 的开发者设计。借助内置的 sdkmanager可绕过 Android Studio 图形界面直接安装、更新 NDK、模拟器、平台工具等组件适合资源受限的开发机、脚本化部署及持续集成流水线。压缩包内含 108 个文件95 个 jar 库构成核心逻辑涵盖 r8、d8、lint、retrace 等编译、混淆与静态检查工具另有 sdkmanager、avdmanager、apkanalyzer、screenshot2、profgen 等可执行命令整体体积约 157MB。包内还附带 readme 与 properties 配置说明解压后配置环境变量即可使用目录结构清晰。目前已有 282 人学习下载对于习惯 Linux 命令行、希望精细控制 SDK 版本和组件或在 CI 中自动完成环境准备与构建的开发者这份工具包能明显提高效率并降低系统占用。1. 没有 Android Studio 的 Linux 上SDK 管理靠什么一台 2C4G 的 Linux 服务器要跑 APK 构建装 Android Studio 是最不划算的IDE、模拟器、插件加起来十几个 GB纯命令行又用不上。Android 官方提供的 commandlinetools-linux-13114758-latest.zip 才是这类场景的正确入口。它体积小解压后只有 cmdline-tools 目录里面是 sdkmanager、apkanalyzer、avdmanager、d8/r8 相关 jar 和 lint 依赖库。职责很明确把 SDK 平台、build-tools、模拟器镜像装到指定目录同时提供 APK 解析、AVD 创建、dex 处理等底层能力。适合不想碰 IDE 的 Linux 开发、写 CI 流水线的运维以及要精确控制 SDK 版本的团队。下面这些操作在 Linux x86_64 上可以直接复现。2. 解压后必须纠正目录层级否则 sdkmanager 只有一个报错2.1 为什么解压完不能直接跑很多人拿到 zip 后的第一反应是unzip commandlinetools-linux-13114758_latest.zip -d /opt/android-sdk接着执行/opt/android-sdk/cmdline-tools/bin/sdkmanager --version。这个姿势在旧版 SDK Tools 里可以在 cmdline-tools 13114758 上会直接报错找不到预期的latest目录。新版命令行工具把安装位置从“解压到哪都能跑”改成了“必须落在 SDK 根目录的固定层级”。sdkmanager 脚本在运行时解析$ANDROID_HOME/cmdline-tools/latest下的结构Gradle Android 插件同样引用这个路径来定位构建工具。正确做法是解压到临时目录再把内部的 cmdline-tools 目录移动成latest这样最终路径就是/opt/android-sdk/cmdline-tools/latest/bin/sdkmanager。完整命令mkdir -p /opt/android-sdk/cmdline-tools unzip commandlinetools-linux-13114758_latest.zip -d /tmp/cmdtools mv /tmp/cmdtools/cmdline-tools /opt/android-sdk/cmdline-tools/latest第一行创建 SDK 根目录下的 cmdline-tools 层第二行把 zip 解压到/tmp/cmdtools避免直接污染目标目录第三行把临时目录里的 cmdline-tools 整层改名为latest。如果/opt/android-sdk为 root 所有要在 mv 之前确认当前用户有写权限否则先sudo chown -R $USER /opt/android-sdk再用普通用户执行后续命令。注意不要始终用 sudo 执行 sdkmanager否则生成的 package 目录和 license 文件都归 root后续 CI 用户无法更新。另外lib 目录下的 kotlin-compiler-mvn.jar、kotlin-reflect-2.1.0.jar、bcprov-jdk18on-1.79.jar、proto.jar 等是 sdkmanager 与 apkanalyzer 的运行时依赖不是给项目直接引用的库不需要手动加入 classpath。2.2 ANDROID_HOME 与 JAVA_HOME 一起配好目录层级纠正后还要保证 Java 环境正确。命令行工具要求 JDK 17 及以上JDK 11 以下会直接启动失败安装前先确认java -version echo $JAVA_HOME如果java -version输出 OpenJDK 17 或 21但$JAVA_HOME为空后面 sdkmanager 仍然可能找不到正确运行时。这时需要在~/.bashrc或/etc/profile.d/android.sh里补上两行export JAVA_HOME/usr/lib/jvm/java-17-openjdk-amd64 export ANDROID_HOME/opt/android-sdk export PATH$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATHJAVA_HOME 的写法取决于发行版安装 JDK 的实际路径不要盲目复制。ANDROID_HOME 指向上一步创建的/opt/android-sdkPATH 里把 cmdline-tools 和 platform-tools 放在最前面可以避免系统里其他旧版 SDK 工具抢优先级。修改后执行source ~/.bashrc重新加载环境。2.3 关键文件清单与首轮验证下表能帮你快速判断解压包里哪些文件该入 PATH哪些只是辅助工具路径用途常见误用cmdline-tools/latest/bin/sdkmanager安装、更新、卸载 SDK 组件目录缺少 latest 时报路径错误cmdline-tools/latest/bin/apkanalyzer分析 APK 清单、文件列表依赖 JAVA_HOME缺了报错cmdline-tools/latest/bin/avdmanager创建/删除 AVD 虚拟设备需要先装 system-imagecmdline-tools/latest/lib/r8.jar代码收缩被 build-tools 调用误以为可java -jar r8.jarcmdline-tools/latest/lib/tools.lint-checks.jarlint 检查规则库真正入口是 Gradle lint task验证链路是否打通直接跑sdkmanager --version能输出版本号说明目录层级、Java 环境都正常。如果卡住或提示找不到主类优先检查$JAVA_HOME是否真的指向 JDK而不是 JRE。接着用sdkmanager --list | head看看组件仓库是否可访问这一步也为下一章的安装操作做准备。3. sdkmanager 的组件安装、卸载与 license 确认3.1 组件标识是一种坐标sdkmanager 没有“下载 zip 包”这种语义一切按组件标识定位。platform-tools、platforms;android-34、build-tools;34.0.0、emulator 和 system-images;android-34;google_apis;x86_64 都是这类坐标。标点里的分号必须保留命令行中最好给整体加双引号避免 shell 把分号当作控制字符。先看当前仓库有哪些可用组件sdkmanager --list | grep -E platforms;android-3[0-9]|build-tools;3[0-9]--list会输出所有通道里的 SDK 包grep 过滤器只保留platforms;android-3X和build-tools;3X的行2 分钟就能知道 target 和构建工具还能装什么版本。输出中如果出现Press Enter to see more在管道里通常不影响 grep 结果。常用组件可以对照下表场景组件 ID安装命令adb、fastbootplatform-toolssdkmanager platform-tools编译 targetplatforms;android-34sdkmanager platforms;android-34低版本 targetplatforms;android-28sdkmanager platforms;android-28AAPT2/dx 等构建工具build-tools;34.0.0sdkmanager build-tools;34.0.0模拟器程序emulatorsdkmanager emulatorAVD 系统镜像system-images;android-34;google_apis;x86_64sdkmanager system-images;android-34;google_apis;x86_64组件 id 中的版本号以sdkmanager --list实际输出为准。安装命令可以一次传多个 id逐个用空格分隔。3.2 用管道自动接受 license首次安装组件时若 user 的 license 未接受sdkmanager 会停在[y/N]提示上。手动按 y 在本地开发无所谓但 CI 脚本里完全不可控。常见做法是用管道把 yes 输入送进去yes | sdkmanager --licensesyes会无限循环输出字符 y--licenses进入接受流程后把每个子协议都判为同意整个过程不会等待键盘输入。执行完成后license 记录写到$ANDROID_HOME/licenses/下。之后安装组件时可以不再带yes |但如果系统里换了用户仍需重新接受一次。也可以对单个安装命令做同样处理yes | sdkmanager --install system-images;android-34;google_apis;x86_64这条命令专门安装模拟器系统镜像。注意--licenses和--install不要在同一个命令里连用部分版本对参数解析比较严格分开执行最稳。3.3 卸载、更新与幂等判断卸载不需要二次确认直接指定组件 idsdkmanager --uninstall build-tools;34.0.0查看本机已经装了什么用--list_installed它比--list快很多也适合被脚本解析sdkmanager --list_installed | grep build-tools如果希望在流水线里避免重复安装可以这样写if ! sdkmanager --list_installed | grep -q platforms;android-34; then sdkmanager platforms;android-34 figrep -q只判断是否存在匹配返回 0 说明已安装跳过安装步骤返回非 0 才执行安装。这是保持 CI 幂等常用的手段比每次无脑--install更节省下载时间。更新所有组件可以用sdkmanager --update但在生产服务器上不建议自动更新优先固定版本号等构建矩阵测试通过后再升。4. 命令行工具全家桶apkanalyzer、avdmanager、d8/r8 与 lint4.1 apkanalyzer一条命令读 APK 的内幕apkanalyzer 位于cmdline-tools/latest/bin下不需要额外的 Gradle 工程直接给定一个 APK 就能分析。三个最常用的子命令apkanalyzer apk summary app-release.apk apkanalyzer manifest min-sdk app-release.apk apkanalyzer files list app-release.apk | head -20apk summary输出 application id、versionName、versionCode是 CI 自动生成版本信息的基础manifest min-sdk单独拉出 minSdkVersion用于校验产物是否满足用户设备的准入规则files list列出 APK 包内全部文件并配合 head 取前 20 行适合快速确认 x86 或 arm64 so 是否打进去。子命令结构可以归纳如下子命令作用常用场景apk summary包名、版本信息构建后展示产物详情manifest min-sdkminSdk 版本兼容性检查files list包内文件清单检查重复/缺失资源若遇到Unable to access jarfile报错先回看 2.2 节的JAVA_HOME。apkanalyzer 是打包在 cmdline-tools 里的独立程序不需要安装 build-tools 也能跑。4.2 avdmanager在无显示器 Linux 上创建 AVD服务器上运行 UI 测试需要先有 AVD。avdmanager 可以完全脱离显示环境创建虚拟设备。不过系统镜像需要先用 sdkmanager 安装然后执行avdmanager create avd -n ci_pixel6 \ -k system-images;android-34;google_apis;x86_64 \ -d pixel_6 --force-n指定设备名后续启动模拟器时用这个名称定位 AVD-k必须和已安装的 system-image id 精确一致-d是设备 profile比如pixel_6决定屏幕分辨率、内存大小--force允许覆盖同名 AVD。创建好的配置落在~/.android/avd/与 Android Studio 完全兼容。用下面命令查看设备 profile 的完整清单avdmanager list device | grep -E id:.*pixel | head在 Linux 服务器上真正启动模拟器还需要 KVM 加速。ls /dev/kvm无输出时不要强行跑 x86_64 镜像性能会低到不可用建议换 arm64 镜像或改用云真机方案。4.3 d8/r8dex 转换要分清 jar 和可执行脚本cmdline-tools/lib 下的 d8.jar 和 r8.jar 是供 Gradle 插件使用的基础库直接java -jar并不是正确入口。命令行调用 d8/r8 时可执行脚本在 build-tools 里。先安装指定版本sdkmanager build-tools;34.0.0再用 d8 把 class/jar 脱糖并转成 dex$ANDROID_HOME/build-tools/34.0.0/d8 --release --output build/ \ --lib $ANDROID_HOME/platforms/android-34/android.jar app.jar--release表示按 release 模式输出并启用优化--output指向产物目录--lib指定 android.jar 作为依赖库app.jar是输入文件。最终生成的build/classes.dex需要打包到 APK 的 dex 槽位里这段逻辑通常由 AGP 在后台完成。r8 用于代码收缩和资源裁剪命令行形态和 d8 很像$ANDROID_HOME/build-tools/34.0.0/r8 --release --output build/ \ --lib $ANDROID_HOME/platforms/android-34/android.jar \ --pg-conf proguard_rules.pro app.jar--pg-conf指向 ProGuard 规则文件规则决定哪些类保留、哪些类移除。如果项目中已经有 release 构建通常不需要单独跑 r8只有在处理小型 jar 库或做插件化合并时才需要用这条命令。4.4 linttools.lint-checks.jar 不是入口Gradle task 才是压缩包里的 tools.lint-checks.jar 是静态分析规则实现被 Android Gradle Plugin 间接加载没有独立的 bin/lint 命令。在纯命令行工程里真正触发检查的是 Gradle taskcd android-project ./gradlew lintReleaselintRelease会针对 release 变体做完整检查。输出报告在app/build/reports/下包括lint-results-release.html和同名.txtCI 里可以直接 grep 小结里Error的数量。如果只想看某个 issue例如 MissingTranslation可以用lintOptions配置在 build.gradle 中而不是硬改命令行参数。若你在服务器的 cmdline-tools 里找不到 lint不要以为自己装错了。这是官方对工具链做了拆分规则库在 cmdline-tools执行权在 Gradle 插件。能接受这一点后续排查路径就会顺畅很多。5. 把 commandlinetools 嵌进 CI无侵入安装与增量更新技巧5.1 一条命令完成安装与激活在全新 Linux 服务器上可以把解压、目录纠正、环境变量配置和基础组件安装打包成脚本。下面是我常用的一份粘贴到 Jenkins 或 GitLab CI 里即可#!/bin/bash set -euo pipefail ANDROID_HOME${ANDROID_HOME:-/opt/android-sdk} LATEST$ANDROID_HOME/cmdline-tools/latest if [ ! -x $LATEST/bin/sdkmanager ]; then mkdir -p $ANDROID_HOME/cmdline-tools unzip -q commandlinetools-linux-13114758_latest.zip -d /tmp/cmdtools mv /tmp/cmdtools/cmdline-tools $LATEST fi export PATH$LATEST/bin:$ANDROID_HOME/platform-tools:$PATH yes | sdkmanager --licenses /dev/null sdkmanager --install platform-tools platforms;android-34set -euo pipefail让脚本遇到未定义变量或失败的管道命令时立即退出-x判断 sdkmanager 是否已经存在已存在就跳过解压保证幂等yes | sdkmanager --licenses /dev/null丢弃大量 license 输出只保留安装日志。最后的--install会自动跳过已安装到最新版的组件不需要额外加--update。5.2 增量更新与产物验证当组件列表越来越长全量安装越来越慢可以精确判断后再装if ! sdkmanager --list_installed | grep -Eq build-tools;34.0.0; then sdkmanager --install build-tools;34.0.0 figrep -Eq的退出码直接作为 if 条件匹配到就跳过匹配不到才安装。反复执行也不会重复下载。长时间构建后$ANDROID_HOME/.temp可能残留下载临时文件可以放到 cron 里定期清理。最后用一行命令确认环境就绪sdkmanager --list_installed | grep platforms;android-34只要这行能打印出组件路径说明目录结构、JAVA_HOME、license 和 sdkmanager 链路全部正常后面接任何依赖 SDK 的 Android 任务都可以直接继续执行。本文还有配套的精品资源点击获取