简介:Android(安卓)命令行工具(commandlinetools-linux-13114758-latest.zip)是一份面向Linux开发者的轻量级SDK管理资源。它省去安装完整Android Studio的负担,适用于习惯命令行操作、或在自动化构建与持续集成环境中批量管理SDK组件的开发者,尤其适合资源受限的服务器或容器场景。压缩包共包含一百零八个文件,体积约一百五十七兆,核心目录为cmdline-tools,内含sdkmanager、avdmanager、apkanalyzer、lint等可执行程序,另有九十五个jar库用于支撑编译、APK分析与代码检查功能。已有二百八十四人浏览学习。完成解压与路径配置后,开发者可通过sdkmanager按需获取平台、NDK、模拟器等组件,灵活定制精简环境;也能借助d8、r8、retrace等工具完成DEX编译、代码压缩与混淆堆栈还原。整体结构清晰,适合具有一定Linux基础、希望摆脱大型IDE并能快速搭建Android开发链路或自动化流水线的工程师,有效提升SDK管理的可控性与可配置性。
1. 命令行工具:不装 Android Studio 也能把 SDK 玩明白
在一台只有 2G 内存的 Linux 服务器上跑 Android 打包任务,第一反应是装个 Android Studio,装完就后悔了——IDE 本身就要占 1G 多内存,再开 Gradle 和模拟器,机器直接卡死。Android 命令行工具(commandlinetools)就是为这种场景准备的:它只是 SDK 管理的最小内核,核心是一个叫 sdkmanager 的命令,负责下载平台、构建工具、NDK 这些组件,全程不碰 IDE。这个 zip 解压后配置好环境变量就能跑,适合三类人:CI/CD 流水线里需要自动化装 SDK 的、在无图形界面的服务器上做构建的、以及单纯不想被 Android Studio 绑架的 Linux 老用户。下文从解压讲起,把 sdkmanager 和它几个兄弟工具的实际用法过一遍,最后给出我踩过的坑位清单。
2. 解压与目录结构:cmdline-tools 的嵌套约定与 PATH 配置
2.1 zip 里有什么:bin 与 lib 的分工
解压后第一眼看到的是cmdline-tools这个顶层目录,里面是两个子目录:bin和lib。搞清楚这两个目录的分工,后面所有问题都好理解。
bin目录放的是可执行脚本,也就是你真正会在命令行里敲的命令。这个包里常见的入口有sdkmanager、avdmanager、apkanalyzer、lint、d8、r8,每一个都对应一套独立的命令行工具。它们本质上是 shell 脚本加 Java 启动器,通过lib目录下的 jar 包来运行。
lib目录就是另一套风景了,密密麻麻全是 jar 文件。项目正文里列的那一串——r8.jar、dk8相关的框架、kotlin-compiler-mvn.jar、intellij-core-mvn.jar、bcprov-jdk18on-1.79.jar、proto.jar、tools.lint-checks.jar、kotlin-reflect-2.1.0.jar——全都躺在lib里。简单说:sdkmanager是 Java 写的,跑起来需要这些依赖,其中r8.jar是 R8 混淆器的本体,bcprov是 Bouncy Castle 加密库,kotlin-compiler-mvn.jar和kotlin-reflect-2.1.0.jar是 Kotlin 编译相关的运行时。日常使用不需要手动碰这些 jar,但理解了这一点,你就知道为什么这台机器必须先装 JDK——命令行工具的启动过程本质上就是java -jar。
2.2 解压到标准位置并配置环境变量
解压这个 zip 有一个非常容易翻车的细节:zip 内部已经包含了cmdline-tools这层目录,而你最终要的目录结构是你的SDK目录/cmdline-tools/latest/bin/sdkmanager。也就是说,不能直接解压到 SDK 根目录了事,必须在cmdline-tools下面再套一层latest。
我一般这样处理:
mkdir -p ~/android-sdk/cmdline-tools unzip commandlinetools-linux-13114758_latest.zip -d /tmp/cmdtools mv /tmp/cmdtools/cmdline-tools ~/android-sdk/cmdline-tools/latest export ANDROID_HOME=~/android-sdk export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH sdkmanager --version第一段命令先把 zip 解压到临时目录,然后把里面的cmdline-tools整体挪到~/android-sdk/cmdline-tools/latest。这个latest名字不是随便起的,sdkmanager启动时会在 SDK 根目录下找cmdline-tools/latest这个固定路径来定位自己的依赖,如果目录名不对,它连自己都找不到。后面两行是环境变量,ANDROID_HOME指向 SDK 根目录,PATH里加了两个位置:一个是cmdline-tools/latest/bin,让sdkmanager、avdmanager这些命令全局可用;另一个是platform-tools,虽然这个目录现在还不存在,装完 platform-tools 组件后adb、fastboot会出现在这里,提前加进 PATH 省得再改。
最后执行sdkmanager --version验证。正常情况下会输出类似13114758这样的版本号。如果报command not found,先去检查 PATH 写没写对;如果报 Java 相关的错误,说明 JDK 环境有问题,这个坑在第 5 章细说。
3. sdkmanager 组件管理:从 list 到 licenses 的完整链路
3.1 组件清单与版本通道:平台、构建工具和模拟器镜像的区别
sdkmanager是整个命令行工具包的核心,它的职责是管理 SDK 组件。理解它之前,先要理解 Android SDK 的组件体系——它们不是一个大包,而是按功能拆成几十个独立组件,每个组件有独立的版本号,互相之间有依赖关系。
| 组件标识 | 作用 | 典型用途 |
|---|---|---|
platform-tools | adb、fastboot、e2fsdroid 等调试工具 | 连接设备、刷机、调试 |
platforms;android-34 | 某个 API 级别的 Android 平台 | 编译时指定 targetSdk |
build-tools;34.0.0 | aapt2、zipalign、dx/d8 等构建工具 | 打包、资源编译、dex |
system-images;android-34;google_apis;x86_64 | 模拟器系统镜像 | 创建 AVD 运行模拟器 |
ndk;27.0.x | NDK 原生开发工具链 | C/C++ 代码交叉编译 |
cmdline-tools;latest | 命令行工具自身 | 通过它管理上面所有组件 |
第一次接触的人最容易混淆的是platforms和build-tools:platforms是编译时要链接的 Android 框架接口,build-tools是实际干活儿的编译工具。装一个 Android 项目常见的最小组合是platform-tools加一个platforms;android-XX加一个匹配的build-tools;XX。模拟器镜像只有在需要跑模拟器时才装,服务器上纯打包场景可以完全跳过。
版本通道用--channel参数控制:0是稳定版,1是测试版,2是 alpha 版,3是 canary 版。我一般固定用0,CI 环境里追新版本纯属自找麻烦。
3.2 安装、接受许可与卸载:稳定复现的五个命令
sdkmanager的使用就是一个命令走天下:先查、再装、最后处理许可证。下面是一套我在自动化脚本里常用的流程:
# 查看所有可用的组件,grep 过滤出你要的版本 sdkmanager --list | grep "platforms;android-34" # 首次安装必须先接受所有许可证,yes 自动确认 yes | sdkmanager --licenses # 按需安装,多个组件写在同一行 sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0" # 卸载用 --uninstall sdkmanager --uninstall "build-tools;33.0.2" # 查看当前已安装的所有组件 sdkmanager --list_installed第一行的--list会输出两大段:installed packages 和 available packages,输出很长,用grep过滤是常态。第二行的--licenses是装任何组件之前必须先过的关卡,Android SDK 的许可证协议需要逐个确认,yes |管道可以一次性全部接受,接受后的记录会写入$ANDROID_HOME/licenses目录,之后重装或者其他用户在同目录下操作都不需要再确认。第三行是安装命令的推荐写法,多个组件包名用空格分隔写在同一条命令里,sdkmanager会按依赖顺序自动处理,比一条条装更快也更不容易出错。最后两行一个是卸载,一个是核对已装列表,CI 脚本里跑完安装后执行一次--list_installed确认结果,是值得养成的习惯。
装完组件后,$ANDROID_HOME下会出现platforms、build-tools、platform-tools等目录。此时验证安装是否成功,直接检查关键二进制是否存在即可:
ls $ANDROID_HOME/platform-tools/adb ls $ANDROID_HOME/build-tools/34.0.0/aapt2如果这两个文件在,说明组件安装成功并且目录结构正常。如果报错说找不到包,大概率是包名敲错了——Android 的包名格式是类型;版本这种分号分隔的写法,用sdkmanager --list输出里的完整名字,不要自己拼接。
4. bin 目录工具箱:avdmanager、apkanalyzer 与 d8/r8 的实战边界
4.1 avdmanager:无界面模拟器的创建与配置
sdkmanager管安装,avdmanager管模拟器。很多人以为命令行环境就用不上模拟器,实际上在 CI 里跑 instrumented 测试、或者在没桌面的 Linux 机器上做 UI 自动化,都得靠命令行创建 AVD。
先安装系统镜像,再创建 AVD,这是固定的两步:
sdkmanager "system-images;android-34;google_apis;x86_64" avdmanager create avd \ -n ci_test \ -k "system-images;android-34;google_apis;x86_64" \ -d pixel_5 \ --force第一行安装模拟器需要的系统镜像,system-images后面的三段分别是 API 级别、镜像类型(google_apis带 Google 服务,default不带)、CPU 架构。服务器上如果没有硬件虚拟化支持,选x86_64镜像可能在启动时翻车,备选方案是arm64-v8a,但速度会慢不少。第二行是创建 AVD 的命令,-n是 AVD 名字,-k指定系统镜像包名,必须和第一步安装的镜像完全一致,-d指定设备配置(用avdmanager list device可以查看所有可选设备),--force表示同名 AVD 直接覆盖。
创建完成后,AVD 的配置会写入~/.android/avd目录。用命令行启动模拟器需要emulator命令,而这个命令来自emulator组件:
sdkmanager "emulator" $ANDROID_HOME/emulator/emulator -avd ci_test -no-window -no-audio -no-boot-anim &-no-window是无头模式,服务器上必须加这个参数,否则模拟器会尝试打开 X 窗口直接崩溃。启动后等待系统 boot 完成才能继续测试,判断 boot 完成的标准做法是轮询sys.boot_completed这个系统属性,但这个脚本细节放到最后一章讲。
4.2 apkanalyzer:不装 IDE 也能拆解 APK
apkanalyzer是一个经常被忽略但非常好用的工具,它的定位是替代 Android Studio 里的 Build > Analyze APK 功能。在命令行环境里分析一个 APK,它的效率比手动解压看二进制高得多。
# 查看 APK 基本信息:包名、版本号、最低 SDK apkanalyzer apk summary app-release.apk # 查看 APK 的清单文件内容 apkanalyzer manifest print app-release.apk # 列出 APK 中所有的 dex 文件并统计方法数 apkanalyzer dex packages app-release.apk第一条命令的输出包含package_name、version_code、version_name、min_sdk、target_sdk这些字段,CI 里做版本校验直接解析这个输出就行。第二条把AndroidManifest.xml的二进制格式转换成人可读的 XML 打出来,适合检查权限声明、Activity 组件、签名信息。第三条统计方法数,多 dex 的 APK 超过 65536 个方法会爆,在检查分包配置时这一条很有用。
这个工具对脚本自动化特别友好,输出是稳定的纯文本,不涉及 GUI。我在做 APK 的合规检查脚本时,就是靠它批量扫描权限清单,比逐个解压看 XML 快一个数量级。
4.3 d8/r8 与 lib 目录:从 class 到 dex 的最后一步
项目正文里那一串 jar 文件,这里的r8.jar值得单独说一下。R8 是官方推荐的混淆和压缩工具,它把 ProGuard 的混淆规则、资源压缩、dex 转换整合成一步操作。d8则是把 Java class 文件编译成 Android 可执行的 dex 文件,它是老工具dx的替代品。
# 用 d8 把 class/jar 转成 dex d8 --release \ --lib $ANDROID_HOME/platforms/android-34/android.jar \ --output build/dex/ \ build/classes/classes.jar # 用 r8 做混淆 + 裁剪 + 转 dex r8 --release \ --lib $ANDROID_HOME/platforms/android-34/android.jar \ --output build/dex/ \ --pg-conf proguard-rules.pro \ build/classes/classes.jar--release表示生产模式,会做优化和混淆(d8 跳过混淆只做优化);--lib指定 Android 平台的 jar,这是编译时解析 Android API 依赖用的,路径里的android-34需要和已安装的平台版本对应;--pg-conf是 ProGuard 规则文件,R8 完全兼容 ProGuard 的规则语法。输出目录里生成的classes.dex就是 APK 里核心的可执行文件。
至于bcprov-jdk18on-1.79.jar、proto.jar、kotlin-reflect-2.1.0.jar这些,它们都是这些工具运行时的依赖库,比如bcprov是 Bouncy Castle 加密算法实现,proto.jar是 Protocol Buffers 序列化支持。正常使用完全不需要手动加载它们,bin目录下的启动脚本会处理。了解它们的作用是为了排错——如果某个工具报ClassNotFoundException或者 NoClassDefFoundError,那就是lib目录不完整或者被清理掉了。
5. 命令行工具避坑指南:目录层级、JDK 版本与许可证的五个坑
5.1 sdkmanager 报错 not found:cmdline-tools 的 latest 嵌套陷阱
现象:解压后直接执行sdkmanager --version,终端提示找不到命令,或者报类似SDK manager not found的错误。
原因:这个 zip 解压出来的顶层目录就是cmdline-tools,如果把它直接放在 SDK 根目录下,比如~/android-sdk/cmdline-tools/bin/sdkmanager,没有中间的latest那层结构,sdkmanager脚本会尝试基于自身路径计算 SDK 根目录,找不到cmdline-tools/latest这个约定路径就罢工了。
解决:按第 2 章的方式,把解压出来的cmdline-tools移到~/android-sdk/cmdline-tools/latest。一个快速判断目录结构是否正确的命令:
find ~/android-sdk -name "sdkmanager" -type f正常输出应该是~/android-sdk/cmdline-tools/latest/bin/sdkmanager,如果路径里没有latest这一段,就是结构不对。
5.2 Unsupported class file major version:JDK 版本太老
现象:执行sdkmanager或apkanalyzer时,直接抛java.lang.UnsupportedClassFileVersionError或者UnsupportedClassVersionError,后面跟着一个 major version 的数字。
原因:命令行工具是用当前版本的 JDK 编译的,新版 cmdline-tools 要求 JDK 17 起步,机器上装的是 JDK 8 或 JDK 11 就跑不起来。major version 65 对应 JDK 21,64 对应 JDK 20,61 对应 JDK 17,看到 65 还报错说明 JVM 版本更老。
解决:安装 JDK 17,并把JAVA_HOME明确指过去。Ubuntu/Debian 上常见做法是:
sudo apt install openjdk-17-jdk export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH java -version重点确认java -version显示的是 17 或更高版本。如果机器上有多个 JDK,光改 PATH 不够,JAVA_HOME也必须同步改,很多 Java 启动脚本优先读JAVA_HOME。
5.3 Failed to install packages:许可证没接受
现象:执行sdkmanager "platforms;android-34",报错提示Failed to install packages,核心信息是licenses相关,或者直接问你是不是接受某个 license。
原因:新装的 SDK 根目录下没有licenses目录,也没有任何已接受的许可证记录。sdkmanager在安装任何组件前都会检查许可证状态,没通过就直接拒绝安装。
解决:先执行一次yes | sdkmanager --licenses,把当前 SDK 根目录下所有许可证一次性接受。接受后$ANDROID_HOME/licenses目录下会生成android-sdk-license文件。如果重装了 SDK 目录,许可证文件会丢失,需要重新接受;CI 环境里每次从零构建时,这条yes |命令必须放在安装命令之前。
5.4 adb command not found:PATH 里没有 platform-tools
现象:sdkmanager正常,组件也装了,但执行adb devices提示command not found。
原因:adb不在cmdline-tools里,它属于platform-tools组件,安装在$ANDROID_HOME/platform-tools目录。PATH 里只加了cmdline-tools/latest/bin,没加platform-tools,自然找不到。
解决:把$ANDROID_HOME/platform-tools加进 PATH。同时建议确认环境变量是 export 出去的,子 shell 和脚本里都能继承:
export PATH=$ANDROID_HOME/platform-tools:$PATH adb --version如果加了 PATH 还是找不到,检查ANDROID_HOME本身是否为绝对路径,不要用~这种 shell 才会展开的符号——在cron或 CI 的非交互 shell 里,~经常不展开导致路径失效。
5.5 下载中断后重来:sdkmanager 没有断点续传
现象:下载某个组件到 80% 时网络断了,sdkmanager报错退出。重新执行同样的命令,它不会接着下载,而是从头再来,然后又在差不多的地方断掉,形成死循环。
原因:sdkmanager的下载机制没有断点续传功能,每次中断后临时文件被清理,重试只能重新下载整个组件包。对于system-images这种动辄上 GB 的组件,这个问题特别折磨人。
解决:没有完美的命令内方案,我的惯用做法是把下载和安装分成两段。在 CI 脚本里写一个重试循环,单次下载失败就等几秒重来,并限制重试次数防止死循环:
for attempt in 1 2 3; do sdkmanager "system-images;android-34;google_apis;x86_64" && break echo "Download failed, retry $attempt/3..." sleep 10 done另一个办法是提前确认依赖完整再执行安装,sdkmanager对已有组件会跳过下载,所以重试不会浪费已经装在磁盘上的东西。如果网络环境实在差,优先装体积小的核心组件,把system-images放到网络好的时间段单独装。
6. 无头服务器一键脚本:把整套 Android SDK 装进一个 bash 脚本
最后给一个我在 CI 和新机器上反复用的完整脚本,它把一个最小可用的 Android 构建环境塞进一个 bash 脚本里,适合 Ubuntu/Debian 系的 Linux 服务器。核心思路是三段式:装 JDK、解压命令行工具、装构建组件。
#!/bin/bash set -euo pipefail SDK_ROOT="${ANDROID_HOME:-$HOME/android-sdk}" CMDTOOLS_VERSION="13114758" # 1. 安装 JDK 17 if ! command -v java || [[ $(java -version 2>&1 | head -1) != *"17"* ]]; then sudo apt-get update sudo apt-get install -y openjdk-17-jdk unzip fi export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 # 2. 检查并安装 cmdline-tools if [ ! -x "$SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" ]; then mkdir -p "$SDK_ROOT/cmdline-tools" wget -q "https://dl.google.com/android/repository/commandlinetools-linux-${CMDTOOLS_VERSION}_latest.zip" -O /tmp/cmdtools.zip unzip -q /tmp/cmdtools.zip -d /tmp/cmdtools mv /tmp/cmdtools/cmdline-tools "$SDK_ROOT/cmdline-tools/latest" fi # 3. 安装构建组件 yes | "$SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" --licenses > /dev/null "$SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" \ "platform-tools" \ "platforms;android-34" \ "build-tools;34.0.0" echo "Android SDK is ready at $SDK_ROOT"这个脚本有四个关键设计。第一,set -euo pipefail是 bash 脚本的保险丝,任何一条命令失败立即退出,避免在坏环境里继续跑出一堆莫名单错误。第二,JDK 版本检查用java -version的输出字符串判断,只认 17,不满足就装,这样脚本可以重复执行。第三,cmdline-tools的安装做了存在性判断,已经装过就直接跳过,整个脚本天然幂等。第四,sdkmanager 用绝对路径调用,不依赖 PATH 是否配置完整,这在刚拉下来的新机器上特别有用——脚本里我顺手把 PATH 省略了,让读者看到它并不是必须的。
顺便说一下,这是我对这个工具整体印象还不错的一个原因:整个 Android 命令行生态,从下载到构建,没有一个环节要求你在终端之外做任何手工操作。Android Studio 把这一切包装成了图形界面,而 commandlinetools 把这些都还原成了原始的、可脚本化的命令。
有一次我在新机器上配环境,照着旧笔记一条条敲命令,结果sdkmanager一直报错,折腾了半小时才发现是上次手滑把目录结构搞错了,少了一层latest。从那以后,我每次在新机器上装 Android 环境都直接跑一遍脚本,从解压到sdkmanager --version输出版本号,全程不手工改路径,再也没被这种低级错误卡过。希望这个脚本和前面这些坑位记录能帮你少走几步弯路。
本文还有配套的精品资源,点击获取