Linux 环境下 Android SDK 命令行工具安装与 CI 集成实践
2026/9/16 4:50:48 网站建设 项目流程

简介:面向 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:$PATH

JAVA_HOME 的写法取决于发行版安装 JDK 的实际路径,不要盲目复制。ANDROID_HOME 指向上一步创建的/opt/android-sdk,PATH 里把 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-image
cmdline-tools/latest/lib/r8.jar代码收缩,被 build-tools 调用误以为可java -jar r8.jar
cmdline-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-3Xbuild-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-28"
AAPT2/dx 等构建工具build-tools;34.0.0sdkmanager "build-tools;34.0.0"
模拟器程序emulatorsdkmanager "emulator"
AVD 系统镜像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 --licenses

yes会无限循环输出字符 y,--licenses进入接受流程后把每个子协议都判为同意,整个过程不会等待键盘输入。执行完成后,license 记录写到$ANDROID_HOME/licenses/下。之后安装组件时可以不再带yes |,但如果系统里换了用户,仍需重新接受一次。

也可以对单个安装命令做同样处理:

yes | sdkmanager --install "system-images;android-34;google_apis;x86_64"

这条命令专门安装模拟器系统镜像。注意--licenses--install不要在同一个命令里连用,部分版本对参数解析比较严格,分开执行最稳。

3.3 卸载、更新与幂等判断

卸载不需要二次确认,直接指定组件 id:

sdkmanager --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" fi

grep -q只判断是否存在匹配,返回 0 说明已安装,跳过安装步骤;返回非 0 才执行安装。这是保持 CI 幂等常用的手段,比每次无脑--install更节省下载时间。

更新所有组件可以用sdkmanager --update,但在生产服务器上不建议自动更新,优先固定版本号,等构建矩阵测试通过后再升。

4. 命令行工具全家桶:apkanalyzer、avdmanager、d8/r8 与 lint

4.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 -20

apk 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/r8:dex 转换要分清 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 lint:tools.lint-checks.jar 不是入口,Gradle task 才是

压缩包里的 tools.lint-checks.jar 是静态分析规则实现,被 Android Gradle Plugin 间接加载,没有独立的 bin/lint 命令。在纯命令行工程里,真正触发检查的是 Gradle task:

cd android-project ./gradlew lintRelease

lintRelease会针对 release 变体做完整检查。输出报告在app/build/reports/下,包括lint-results-release.html和同名.txt,CI 里可以直接 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-34"

set -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" fi

grep -Eq的退出码直接作为 if 条件,匹配到就跳过,匹配不到才安装。反复执行也不会重复下载。

长时间构建后,$ANDROID_HOME/.temp可能残留下载临时文件,可以放到 cron 里定期清理。最后用一行命令确认环境就绪:

sdkmanager --list_installed | grep "platforms;android-34"

只要这行能打印出组件路径,说明目录结构、JAVA_HOME、license 和 sdkmanager 链路全部正常,后面接任何依赖 SDK 的 Android 任务都可以直接继续执行。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询