
简介这是一份面向Windows平台的Android命令行工具包专为不需要安装完整Android Studio的开发者设计可解决SDK组件下载、应用编译、设备连接与调试等常用开发问题。压缩包共108个文件其中95个为jar格式的工具组件10个为bat命令入口另有1个properties配置、1个readme说明和1个txt文档整体体积136.41MB。工具集内置sdkmanager能够按需下载系统镜像、开发库、API文档与模拟器等组件避免一次性拉取整个IDE同时包含avdmanager、apkanalyzer、lint等命令用于管理虚拟设备、解析APK安装包和检查代码质量。借助这些工具即使在没有图形界面的服务器或CI环境中也可以通过命令行完成从项目编译、单元测试到打包部署的完整流程。该资源已有544人学习下载适合习惯命令行操作、需要维护多个项目或希望实现自动化构建的开发者也可作为Android开发的轻量级入门选型。1. 别急着装 Android Studio这个 zip 就能把 SDK 管起来在 Windows 上做 Android 工程的自动化打包时我第一件事不是装 Android Studio而是先找一个 zipAndroid 命令行工具commandlinetools-win-13114758-latest.zip。这个名字看着像某个不起眼的下载产物实际它是 Android SDK 的官方命令行工具集里面打包了 sdkmanager、avdmanager、apkanalyzer 等一整套东西。只要把它装好你就能在没有 IDE 的情况下完成 SDK 组件安装、模拟器创建、构建环境配置甚至跑起完整的 CI 流水线。适合三类人想在服务器或虚拟机里做安卓构建的工程师、写脚本批量管理多台机器 SDK 的人以及单纯受不了 Android Studio 那股笨重劲儿的老手。它解决的问题很朴素安卓开发工具链在命令行下能不能独立活。2. 解压与目录结构cmdline-tools 为什么必须套一层 latest2.1 先看懂压缩包里装的是什么拿到 commandlinetools-win-13114758-latest.zip 之后别急着双击解压。这个 zip 解压出来是一个名为 cmdline-tools 的文件夹里面是 bin、lib 和几个子目录。bin 下有 sdkmanager.bat、avdmanager.bat、apkanalyzer.bat 这些批处理入口lib 里是工具运行依赖的 Java 类库。也就是说这套工具本质是一个 Java 程序Windows 上靠 .bat 包装成命令行工具。文件名里的 13114758 是这次构建的构建号装好之后没有任何命令会专门引用它真正重要的是后面要讲的目录摆放规则。很多人把 zip 解压后直接扔到某个目录然后进 cmdline-tools\bin 跑 sdkmanager --version发现能输出版本号就以为装好了。等到用 sdkmanager 去安装 platforms;android-34 之类的包时要么静默失败要么把包装到了莫名其妙的位置。原因是 sdkmanager 并不是单纯的一个命令它会基于自身所在路径反推 SDK 根目录再往根目录下的 platforms、build-tools、system-images 等子目录写入内容。如果目录层级不符合它预期的结构它就找不准家在哪。2.2 标准目录结构一层 latest 是关键常见做法是先把 zip 解压再把里面的 cmdline-tools 整个移动到一个干净的 SDK 根目录下的 cmdline-tools\latest 子目录里。假设我把 SDK 根目录定在 D:\Android\Sdk那么最终结构应该是D:\Android\Sdk └── cmdline-tools └── latest ├── bin │ ├── sdkmanager.bat │ └── avdmanager.bat └── lib注意这个 latest 是怎么来的它不是 zip 里自带的而是你在 cmdline-tools 下面新建一个名为 latest 的子目录把解压出来的文件全部放进去。之后的 platform-tools、platforms、build-tools 这些目录会由 sdkmanager 自动生成在 D:\Android\Sdk 下面形成完整的 SDK 布局。zip 里解压出来的那个 cmdline-tools 文件夹本身千万不要改名为其他名字sdkmanager 对目录名有既定预期。为了快速操作我给你一段我在 PowerShell 里常用的初始化命令# 定义你的 SDK 根目录选一个干净的盘符路径别用 C:\Windows 这类系统目录 $sdkRoot D:\Android\Sdk # 解压 zip 到临时目录。这里假设 zip 已下载到 D:\Downloads Expand-Archive -Path D:\Downloads\commandlinetools-win-13114758-latest.zip -DestinationPath $env:TEMP\cmdline-tools-extract # 建立标准目录结构cmdline-tools/latest New-Item -ItemType Directory -Force -Path $sdkRoot\cmdline-tools\latest # 把解压出来的 cmdline-tools 里的内容复制到 latest 目录 Copy-Item -Path $env:TEMP\cmdline-tools-extract\cmdline-tools\* -Destination $sdkRoot\cmdline-tools\latest -Recurse -Force这段逻辑的核心是两条先创建 cmdline-tools\latest 骨架再把 zip 解压出的内容整体塞进 latest。很多教程只给一句“解压后改名”没说清楚为什么改成 latest导致我见过有人把整个 D:\Android\Sdk\cmdline-tools 目录结构搞成 D:\Android\Sdk\cmdline-tools\cmdline-tools\bin 这种嵌套。原因就是解压后没有把内层目录展开直接把外层整个目录当成工具目录了。判断方法很简单看 sdkmanager.bat 的完整路径最后两级必须分别是 cmdline-tools 和 latest。2.3 配置环境变量与最小验证目录放好之后要让工具在任何终端里都能直接调用。需要配置两个东西一个是 SDK 根目录的环境变量另一个是工具 bin 目录的 PATH。sdkmanager 在寻找 SDK 位置时会参考 ANDROID_HOME 或 ANDROID_SDK_ROOT两个变量指向同一个路径不会冲突但别一个配一个不配。# 以当前用户级别设置环境变量避免权限问题 [Environment]::SetEnvironmentVariable(ANDROID_HOME, D:\Android\Sdk, User) [Environment]::SetEnvironmentVariable(ANDROID_SDK_ROOT, D:\Android\Sdk, User) # 把 cmdline-tools/latest/bin 加进 PATH $userPath [Environment]::GetEnvironmentVariable(Path, User) [Environment]::SetEnvironmentVariable(Path, $userPath;D:\Android\Sdk\cmdline-tools\latest, User)设置完环境变量注意新开的终端才会继承这些值。验证是否装对最直接的方式是关闭旧终端重新开一个 PowerShell 窗口# 新终端里执行版本检查 sdkmanager --version如果输出类似一长串版本号说明工具本身已经能跑。如果提示找不到命令多半是 PATH 没刷新或者你还在用之前没关掉的旧终端。如果提示找不到 Java 运行时那是 JAVA_HOME 没配或者 JDK 版本不对sdkmanager 这个 Java 程序先得有 JVM 才能干活。我建议用主流的 LTS 版本 JDK太老或太新的 JDK 都有可能让它在启动阶段报奇怪异常。3. sdkmanager包管理命令与 3 个高频参数3.1 先看有哪些包可以装sdkmanager --list装好之后第一件事是拉取远端仓库里可用的组件清单。命令是 sdkmanager --list它会从 Google 的仓库拉取数据输出当前已安装的组件、可用的组件和可用的更新三部分。输出行非常多直接看会花眼。我在 Windows 上通常会过滤一下只看自己想要的那一类包# 列出所有平台的 SDK 版本。PowerShell 下用 Select-String 过滤 sdkmanager --list | Select-String platforms;android- # 只看构建工具版本 sdkmanager --list | Select-String build-tools; # 只看模拟器相关镜像system-images sdkmanager --list | Select-String system-images;如果列表拉不下来先检查网络能通到仓库再考虑是不是被代理环境挡住了。sdkmanager 默认会读系统代理设置吗不一定它更信任自己命令行里给的代理参数。公司环境普遍用内网代理时要用显式的代理参数才能拉回列表这个细节最容易让人误以为命令坏了。3.2 安装与卸载包名格式决定成败sdkmanager 的安装命令核心就一句话把包名作为参数传给 install。包名格式是分号分隔的层级路径比如 platforms;android-34 表示 34 这个 API 级别的平台组件build-tools;34.0.0 表示构建工具的具体版本emulator、platform-tools 这种不带分号的属于顶层包。# 安装一组常用组件。每个包名都必须用双引号包住原因看下方说明 sdkmanager platform-tools platforms;android-34 build-tools;34.0.0 emulator # 如果 SDK 不在默认位置显式指定根目录。这个参数我几乎每次都会带 sdkmanager --sdk_rootD:\Android\Sdk platform-tools包名必须加引号是因为分号在 PowerShell 里是语句分隔符不加引号会被拆成多条语句命令直接报错。在 cmd 里不加引号倒不会拆语句但分号也可能引发其他解析问题统一加引号最保险。--sdk_root 这个参数值得养成习惯当你机器上有多个 SDK 目录时sdkmanager 可能找到的不是你想要的那个显式指定根目录能避免很多灵异问题。安装完成后可以去 D:\Android\Sdk 下看是不是多了 platforms、build-tools 这些目录。卸载同理把 install 换成 uninstall包名要跟安装时完全一致。我只在清理旧版本构建工具时用这个功能比如一台机器上堆积了五六个 build-tools 版本磁盘吃紧时会统一清一轮。3.3 接受许可证Windows 上没有 yes 的坑装完组件第一次使用时很多命令会要求接受许可证。常见做法是看到一堆 license 提示后手动敲 y 回车。但在一台无人值守的机器上手动一条条敲会崩溃。网上常见方案是执行 yes | sdkmanager --licenses问题是 Windows 的 cmd 和 PowerShell 里根本没有 yes 这个命令。只有在 Git Bash 等环境里才有 yes 可用直接照抄这条命令在 PowerShell 里会得到“无法识别 yes”的错误。我常用的做法是循环多次自动把 y 喂给 sdkmanager# 自动接受所有许可证。原理是重复把 y 管道给 licenses 命令 # 之所以循环是因为某些版本一次只能接受一部分 license 文件 for ($i 0; $i -lt 20; $i) { y | sdkmanager --licenses }这段逻辑里循环 20 次不是玄学license 文件可能有好几个比如 androidx 的 license 和其他组件的 license 分开存放第一次接受完一部分第二次再跑还会问你剩下的循环能确保全部吃进去。如果你只想接受特定组件的 license更精准的方式是先安装组件再接受未安装的组件根本不会出现在 licenses 列表里。所以别在还没装任何包的时候去执行 licenses 命令你会疑惑为什么它瞬间结束、什么都没干。3.4 代理与更新通道两个容易被忽略的参数经过代理上网的环境还要学会给 sdkmanager 显式传代理。命令行的形式和 Maven 那套很像但参数名不一样记错了就白搭。正确参数是这三件套# http 代理示例。host 和 port 按实际内网代理配置填写 sdkmanager --proxyhttp --proxy_host10.0.0.1 --proxy_port8080 --list另一个参数是 --channel它控制拉取哪个发布通道的组件。默认值是 0表示稳定版通道。有的场景需要提前用某些 preview 功能可以临时加上 --channel1 或者 --channel3 来拉试版组件。我的建议是日常构建固定用默认通道只有确认要尝鲜某个新 API 时才临时指定通道避免因为组件版本跳变导致构建环境不可复现。4. avdmanager emulator无界面建一台模拟器4.1 先装系统镜像system-images 包的层级逻辑要让模拟器能启动光有 emulator 这个顶层组件不够还必须装对应 API 级别的系统镜像。系统镜像的包名比前几个都长比如 system-images;android-34;google_apis;x86_64。这个包名的四个分段各有含义system-images 是类型android-34 是 API 级别google_apis 表示带 Google API 的镜像x86_64 表示镜像架构。# 装 34 级别的带 Google API 的 x86_64 镜像 # 适合跑在 Windows 的 Intel/AMD 桌面 CPU 上 sdkmanager system-images;android-34;google_apis;x86_64架构字段要留意如果宿主机是 Apple Silicon需要的可能不是 x86_64但 Windows 场景基本都围绕 x86_64 展开。还有一个坑是 android 这个分段不带引号时会被 Shell 当作变量或其他含义处理所以包名一律加双引号。镜像体积不小下载时如果网络不稳定sdkmanager 卡在某个百分比不动我一般先看网络再看仓库连通性最后考虑是不是代理参数漏了。4.2 创建 AVDavdmanager 的最小参数组合镜像装好之后用 avdmanager 创建虚拟设备。这个命令在 cmdline-tools 的 bin 目录下和 sdkmanager 是同一个家。创建 AVD 的核心参数是 -n 指定名字-k 指定系统镜像的完整包名-d 指定设备定义。这里 -d 可选但你不指定的话创建出来的设备屏幕分辨率、内存这些配置会比较随意后面启动时容易出幺蛾子。# 创建一个名为 ci_test 的 AVD基于之前装好的镜像 # --device 参数可以用 pixel 这类通用设备定义具体可用值可通过 list device 查看 echo no | avdmanager create avd -n ci_test -k system-images;android-34;google_apis;x86_64 -d pixel命令里的 echo no 是为了回答 avdmanager 创建过程中会问的一个问题是否创建自定义硬件配置文件。如果你不回答它在某些版本会卡在读输入这里。直接回 no让它用默认硬件配置创建即可因为后面启动模拟器时还可以用命令行参数微调硬件表现。创建完成后AVD 会落到用户目录下的 .android\avd 里文件名和 -n 指定的名字一致。如果你打算把 AVD 放到指定位置可以设置 ANDROID_AVD_HOME 环境变量这个在 CI 场景下非常有用能避免默认路径被系统清理或权限问题挡住。4.3 从命令行启动模拟器无头模式必配参数AVD 建好不一定立刻能启动。最常见的问题出现在图形环境缺失的机器上比如一台只有命令行界面的 Windows Server。模拟器默认会窗口启动这时候必须改用 headless 模式。我平时启动模拟器的完整命令长这样# 无窗口、无音频、关启动动画、强制软件渲染 # 这一套参数在 CI 服务器上能跑得比较稳 emulator -avd ci_test -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect逐个解释这几个参数的用途。-no-window 让模拟器不创建图形窗口适合飞在后台跑。-no-audio 关掉音频子系统避免一些服务器上没有声卡导致初始化失败。-no-boot-anim 能缩短启动动画占用的等待时间。-gpu swiftshader_indirect 强制用软件渲染在没有独立显卡的机器上不至于因为 GPU 驱动问题直接崩。最后一个参数比较关键不指定的话模拟器会尝试用宿主机的 GPU 加速服务器上经常因为找不到可用 GPU 而终止。启动起来之后还不能马上跑用例要等系统真正完成 boot。只看终端输出不可靠得轮询系统属性# 先等设备被 adb 识别到 adb wait-for-device # 轮询 sys.boot_completed直到输出 1 为止 # 这里用循环等待最长等 180 秒 for ($i 0; $i -lt 180; $i) { $bootCompleted (adb shell getprop sys.boot_completed).Trim() if ($bootCompleted -eq 1) { Write-Host Boot finished break } Start-Sleep -Seconds 2 }这个等待逻辑要配合 adb wait-for-device 使用。wait-for-device 只能保证设备已经连上 adb不能保证系统启动完毕。boot_completed 这个系统属性变成 1 才代表 Launcher 已经起来可以开始装应用、跑测试。如果你在这个阶段用 adb install大概率会报设备未就绪的错误。轮询间隔我一般设 2 秒最长 3 分钟超过就报超时退出避免 CI 任务无限挂住。5. 避坑排查Windows 上装这套工具最常见的 5 个坑5.1 命令能跑但包装到了奇怪的位置现象sdkmanager --version 正常输出执行 sdkmanager platforms;android-34 也不报错但在 D:\Android\Sdk 下死活找不到 platforms 目录反而在 zip 解压后的某个临时路径下生成了新目录。原因目录结构不符合 cmdline-tools/latest 的预期sdkmanager 把临时解压目录当成了 SDK 根。解决严格按上一章的标准结构重新摆放目录然后用 --sdk_root 显式指到 D:\Android\Sdk 再装一次。这是我见过最多人踩的坑基本都是一上来就跳过目录结构直接开跑。5.2 分号引发的命令截断现象在 PowerShell 里执行 sdkmanager platforms;android-34报“表达式或语句中包含意外的标记”之类错误。原因PowerShell 用分号分隔多条语句包名里的分号被解释成了语句边界。解决包名必须用双引号完整包住。另外一个相关现象是包名里的引号在 cmd 与 PowerShell 之间复制粘贴时会变成弯引号导致参数解析断裂。解决统一在 PowerShell 里手动输入直引号。5.3 licenses 接受不彻底现象执行完 sdkmanager --licenses回头构建时依然报“LICENSE NOT ACCEPTED”或者 Jenkins 日志里提示某些组件的 license 文件缺失。原因一是 Windows 上没有 yes 命令网上的管道写法不适用二是 license 文件不止一个一条命令只接受了部分。解决在 PowerShell 里用循环把 y 管道给命令循环次数宁多勿少接受完之后再去对应目录检查 license 文件是否存在。顺带一提构建工具读取 license 的路径在 SDK 根目录下如果你手工创建了一个假的 license 文件格式不对一样会被拒绝。5.4 模拟器进程在但设备一直 offline现象emulator 进程在任务管理器里能看到adb devices 却显示 offline或者反复出现 device unauthorized。原因这台机器的虚拟化支持没开或者 Windows Hypervisor Platform 没启用。模拟器在没有硬件加速时启动很慢甚至卡在早期初始化阶段。解决先去 BIOS 确认 CPU 虚拟化已开启再在 Windows 功能里勾选 Hyper-V 相关组件。CI 环境常见的是你自己能跑、装了 CI 服务的宿主机跑不了多半是服务运行在没有虚拟化的容器里。5.5 改了环境变量但服务进程找不到命令现象手动终端里 sdkmanager 正常但 CI Agent 启动的构建任务报“sdkmanager 不是内部或外部命令”。原因CI Agent 作为服务安装时继承了 System 级别的环境变量你在 User 级别新加的 PATH 它根本看不到或者 Agent 启动后环境变化没有重新加载。解决在 CI 任务里显式设置工具路径不要依赖宿主机的环境变量。做法是在任务脚本开头重新定义 PATH 和 ANDROID_HOME保证每次构建从干净且固定的环境开始。6. 进阶把整套安装固化成一条命令这一章聊怎么把这套手工过程变成幂等脚本。所谓幂等就是同一台机器上跑十遍脚本结果应该和跑一遍一样不会因为重复创建目录或重复安装组件而报错。做法是写一个 PowerShell 脚本内部先判断目录结构是否已存在不存在才解压再判断组件是否已安装未安装才执行 sdkmanager。# install-android-sdk.ps1 param( [string]$SdkRoot D:\Android\Sdk, [string]$ZipPath D:\Downloads\commandlinetools-win-13114758-latest.zip ) $toolsDir Join-Path $SdkRoot cmdline-tools\latest if (-not (Test-Path $toolsDir\bin\sdkmanager.bat)) { Write-Host Installing cmdline-tools... $extractDir Join-Path $env:TEMP cmdline-tools-extract Expand-Archive -Path $ZipPath -DestinationPath $extractDir -Force New-Item -ItemType Directory -Force -Path $toolsDir | Out-Null Copy-Item -Path $extractDir\cmdline-tools\* -Destination $toolsDir -Recurse -Force } # 核心组件清单这些包名写在一个文本文件里方便跨机器维护 $packages Get-Content sdk-packages.txt foreach ($pkg in $packages) { Write-Host Installing $pkg sdkmanager --sdk_root$SdkRoot $pkg } for ($i 0; $i -lt 20; $i) { y | sdkmanager --sdk_root$SdkRoot --licenses }配套的 sdk-packages.txt 里我会按固定版本写上要安装的组件。这里的关键是版本号要锁定比如 platforms;android-34 和 build-tools;34.0.0而不是用 anything 之类通配。锁定版本的好处是半年后重新跑脚本装的还是同一套东西不会有“上次构建没问题今天突然报依赖缺失”的困扰。这个教训是我自己翻车翻出来的有一年我不指定 build-tools 版本让 sdkmanager 装默认最新结果某次远程仓库更新后老项目突然打包失败排查半天才意识到是新版构建工具改了旧版配置的默认行为。另一个值得养成习惯的技巧是定期把 sdk-packages.txt 纳入版本控制跟着项目仓库走。新机器加入集群时一条命令拉代码、一条命令跑脚本SDK 环境就能复现。相比每次都手动敲安装命令这套方式更接近“基础设施即代码”的思路也让接手的人少被玄学折磨。希望帮到你。本文还有配套的精品资源点击获取