
简介AndroidSDKTools26.1.1 压缩包面向使用 Unity 2018/2019 打包安卓 APK 的开发者重点解决旧版工具版本兼容与配置繁琐的问题也适合需要稳定构建环境、排查打包链路的移动开发学习者以及讲授旧版构建流程的教学场景和需要复现旧环境的团队。包内共 1828 个文件约 146.29MB以 jar 库、xml 与 html 页面、png 截图及 exe、bat 脚本等为主覆盖工具程序、许可说明与文档资源目录体量完整便于按组件查找内容并减少环境搭建阻力。内容围绕工具管理、设备调试与包体优化等核心能力展开可辅助理解安卓平台组件、安装测试和版本兼容之间的关系适合对照检查工具路径、组件缺失和报错原因并提升排错效率。已有 2833 人学习也可作为旧项目维护、打包环境复现与团队内部培训的参考资料。1. Android SDK Tools 26.1.1 是什么Unity 打包 APK 的底层支撑而不是完整 SDK多人协作的 Unity 工程里经常出现这类情况代码在本地能跑一到打包就弹Android SDK not found或者sdkmanager窗口闪一下就消失日志里只剩一行java.lang.NoClassDefFoundError。此时缺的往往不是整个 SDK而是一个能用的 Android 命令行工具集。AndroidSDKTools26.1.1.rar 解开的正是这套工具里面是sdkmanager、avdmanager、adb、aapt以及一批批处理脚本处在 Unity3D 打包 apk 流程的最底层。它并不完整platform-tools、build-tools、platforms都要靠它自己拉取。这个包适合仍维护老版本 Unity 工程、需要离线或半离线搭一套可控 Android 环境的人。2. 解压后的目录与三条必通命令把 sdkmanager 跑起来拿到压缩包后第一件事往往容易做错很多人直接解压到C:\Program Files\Android\sdk然后在 Unity 里填路径结果后面每一步都报错。原因是这个包里只有tools它是个“安装器外壳”真正的adb、aapt2、android.jar都不在里面。先弄清目录结构再决定放哪儿。2.1 目录布局tools 只是外壳platform-tools 和 build-tools 要自己装解压后能看到的核心目录只有tools其下是bin、lib、source.properties。bin里放着 Windows 的.bat和类 Unix 的 shell 脚本sdkmanager、avdmanager、sdkmanager.bat都在这里source.properties记录了这套工具的版本号26.1.1 就是从这儿读出来的。剩下那些platform-tools、build-tools、platforms、extras、ndk-bundle目录解压出来是空的或者干脆不存在。原因很直接26.x 时代的 SDK Tools 发布包只分发工具本体组件全部走远程仓库拉取。这就决定了安装位置的两条硬性限制。第一条路径不能带非 ASCII 字符和空格老版本aapt和 Gradle 的路径解析在这方面有历史问题一旦带空格就会在链接阶段报找不到文件。第二条路径要短Windows 的 260 字符限制在 Gradle 缓存和 NDK 目录叠加时很容易触发。我一般会放在D:\android-sdk这类位置把整个 SDK 根目录当成一个可以随时删掉重来的目录不要和系统盘里的其他工具混在一起。放好之后确认一下 Windows 下的关键文件tools\bin\sdkmanager.bat、tools\bin\avdmanager.bat。如果这两个文件不在或者被杀毒软件隔离了后面所有步骤都无从谈起。2.2 JAVA_HOME 与 ANDROID_HOME两个变量决定 sdkmanager 能不能启动sdkmanager本身是个 Java 程序启动脚本会去读JAVA_HOME。26.1.1 这一代工具编译时用的是 JDK 8 的类库所以JAVA_HOME必须指向 JDK 8。如果指向 JDK 11 或更高版本启动时会直接抛NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema因为 JAXB 在 Java 11 里已经从标准库移除。有血泪教训的是机器上装了多个 JDK 时PATH里java -version显示的是 8但JAVA_HOME指向 17一样报错脚本认的是后者。ANDROID_HOME指向刚解压的 SDK 根目录也就是tools的上一级。新老 Unity 对这个变量的读取顺序有差异老版本认ANDROID_HOME新版本优先ANDROID_SDK_ROOT。两个都设成同一个值最省事但千万别设成两个不同的路径否则 Unity 和 Gradle 会各读各的出现“编辑器里显示 SDK 正常、打包时却说找不到”的玄学现象。# Windows 命令行临时生效验证用 set JAVA_HOMED:\jdk8 set ANDROID_HOMED:\android-sdk set ANDROID_SDK_ROOT%ANDROID_HOME% set PATH%JAVA_HOME%\bin;%ANDROID_HOME%\tools\bin;%ANDROID_HOME%\platform-tools;%PATH% java -version sdkmanager --version# macOS / Linux写进 ~/.bashrc 或 ~/.zshrc 才是永久的 export JAVA_HOME/opt/jdk8 export ANDROID_HOME/opt/android-sdk export ANDROID_SDK_ROOT$ANDROID_HOME export PATH$JAVA_HOME/bin:$ANDROID_HOME/tools/bin:$ANDROID_HOME/platform-tools:$PATH参数说明只有三点JAVA_HOME必须是 JDK 8 的根目录而不是binANDROID_HOME必须是tools的上一级PATH里tools\bin要排在前面否则机器上如果另装过一个新版 SDKsdkmanager命令可能被解析到别的版本上去。验证成功的标志是sdkmanager --version输出版本号而不是一堆堆栈。2.3 sdkmanager 装组件与 licenses 落地变量通了之后第一件事不是急着装组件而是先看一眼仓库能不能连上。sdkmanager --list会输出已安装和可安装的组件清单如果卡住不动或者报 SSL 相关错误多半是网络层的问题此时不要反复重试先确认代理设置和证书链是否正常。我一般会先跑--list确认能拿到远端清单再执行安装。# 指定 sdk_root避免 sdkmanager 猜错安装位置 sdkmanager --sdk_rootD:/android-sdk --list # 安装最小可用组合平台工具 一个 build-tools 一个 platform sdkmanager --sdk_rootD:/android-sdk platform-tools build-tools;26.0.1 platforms;android-26 # 接受许可交互式逐条回车 sdkmanager --sdk_rootD:/android-sdk --licenses--sdk_root这个参数值得单独说不加它的时候sdkmanager会根据自身所在路径往上推断 SDK 根目录。如果你把tools单独拷出来放在别处推断就会错位组件被装到一个谁也找不到的目录里。加上它等于显式告诉工具“根目录在这儿”是离线分发场景下最稳的做法。--licenses会在 SDK 根目录下生成licenses文件夹里面是几个文本文件内容是对应许可证的哈希值。Unity 打包时会检查这些文件缺了就卡在license not accepted。无交互环境比如自动化脚本里可以用管道批量确认# Linux / macOS yes | sdkmanager --sdk_root/opt/android-sdk --licenses # Windows 命令行的等价写法 for /l %i in (1,1,30) do echo y| sdkmanager --sdk_rootD:/android-sdk --licenses装完立刻验证三个命令adb version、aapt version在build-tools/版本目录下、sdkmanager --list_installed。三个都出信息说明这套底座立住了可以往 Unity 里接。3. 版本搭配build-tools、platforms、JDK 与 Unity 版本怎么对上这套工具之所以还有人在用很大原因是它能装到一些新版sdkmanager已经下架的组件。但这个优势只在一件事成立时才有意义版本之间必须搭配正确。Unity 打包 APK 报的错里有一半以上是版本错配而不是功能缺失。3.1 为什么 26.1.1 的 sdkmanager 反而是优势从 25.3.0 开始android命令被sdkmanager取代26.x 是这套新命令行的早期稳定版本。它的优势有两个。第一命令行接口简单sdkmanager 包名;版本这种写法没有后来那些--channel、--include_obsolete的额外概念脚本里好写。第二也是更实用的它还能拉到ndk-bundle——新版 SDK 仓库早已把这个包移除只保留独立分发的 NDK 压缩包。对于还在用老版本 Unity 的工程ndk-bundle目录结构是硬编码期待的装不上就只能在 Unity 里手工指一个 NDK 路径容易出岔子。代价也要说清楚26.1.1 不认识后来新增的仓库元数据格式某些镜像源的清单它解析不了--list可能只显示一部分组件。这不是包坏了是年代差异。遇到这种情况换回官方源或者改用离线 zip 手工解压到对应目录都比硬折腾sdkmanager快。3.2 用 sdkmanager 装一套最小可用组合Unity 打包 APK 对 SDK 的需求其实很小platform-tools提供 adb安装和调试用、一个build-tools提供 aapt、zipalign、apksigner、一个platforms提供android.jar编译期依赖。三个组件版本之间要能对上platforms;android-26配build-tools;26.0.1是同一代platforms;android-28配build-tools;28.0.3是同一代。跨代混用不是绝对不行但编译期常量对不上时会报cannot find symbol这类错误查起来很费时间。我一般按 Unity 版本倒推装哪一代下面这张表是这些年反复验证过的常见搭配不是官方推荐表是按实际能跑通整理出来的Unity 版本区间JDKbuild-toolsplatformsNDK5.6 – 2017.4JDK 826.0.1android-26r13b 附近2018.4 LTSJDK 828.0.3android-28r16b / r192019.4 LTSJDK 828.0.3 或 29.0.2android-28 / 29r19安装命令是幂等的重复执行只会提示 already installed不会把已有组件弄坏# 装第二代组合对应 2018.4 那档 sdkmanager --sdk_rootD:/android-sdk platform-tools build-tools;28.0.3 platforms;android-28 # 装完核对 sdkmanager --sdk_rootD:/android-sdk --list_installed参数上只有一个坑包名里的分号在 Windows 命令行下要加引号build-tools;28.0.3不加引号会被 cmd 当成命令分隔符结果只装了build-tools版本参数被丢掉装出来的东西根本不是你要的。3.3 NDK老源能装、新源装不上的那一块Unity 里勾了 IL2CPP 或者工程里有原生插件时NDK 就是必需品。sdkmanager装 NDK 的写法是sdkmanager --sdk_rootD:/android-sdk ndk-bundle装完之后目录是sdk/ndk-bundle这个固定名字很关键很多老工程和构建脚本默认就是这个路径。如果换用新版独立分发的 NDK 压缩包解压出来的目录名会带版本号比如android-ndk-r19c此时要么在 Unity 的 External Tools 里手工指路径要么把它改名为ndk-bundle放到 SDK 根目录下。还有一个隐蔽问题NDK 解压后如果没有执行权限Linux 和 macOS 上会在链接阶段报Permission denied。执行chmod -R x ndk/就能解决但报错信息完全不会提示这一层容易被误判成工程配置问题。4. 接进 UnityExternal Tools 三路径与 Player Settings 对齐组件装齐只是准备阶段真正决定能不能打出包的是 Unity 这边的三个路径和四项设置。这一步做错前面所有工作都白费。4.1 Preferences 里填哪三个路径Unity 的 Android 相关路径集中在 External Tools 面板三个输入框分别是 SDK、JDK、NDK。填法上有几个细节。SDK 填的是 SDK 根目录也就是包含tools、platform-tools、build-tools的那一层不是tools本身。这是最常见的填错点填成tools之后 Unity 会报找不到platform-tools。JDK 填 JDK 8 的根目录不是bin也不是jre子目录。有些 JDK 发行版自带一个jre子目录样子很像但缺编译工具javac填进去会在编译 Java 源码那一步报找不到编译器。NDK 在不需要 IL2CPP 和原生插件时可以留空。留空不影响 Mono 后端的打包但会在切换脚本后端时提示缺失。Windows 下路径分隔符反斜杠和正斜杠都能填但我习惯统一用正斜杠因为同一个工程在 macOS 上打开时反斜杠路径会直接失效而工程设置是跟着仓库走的。4.2 Player Settings 里跟 SDK 强相关的四项打开 Player Settings 的 Android 分页前四项设置必须和已安装组件对上Minimum API Level和Target API Level决定用哪个android.jar编译。Target 设成 28就必须装了platforms;android-28否则 Unity 会直接报Target SDK version not installed而且这个报错在构建队列里才出现编辑器界面不提示。Scripting Backend选 Mono 还是 IL2CPP直接决定要不要 NDK。Mono 快适合调试IL2CPP 是上架要求编译慢且依赖 NDK。Build System有 Internal 和 Gradle 两个选项。Internal 是老版本 Unity 自带的一套打包流程不依赖 Gradle 和 build-toolsGradle 则要求build-tools版本和 Unity 内置的 Gradle 模板匹配。选 Internal 能绕开很多 SDK 版本问题但无法处理自定义 AndroidManifest 合并、多 ABI 分包这些需求实际项目里迟早要切到 Gradle。Target Architectures勾选 arm64-v8a 之后如果 NDK 缺失会立刻报错这个组合排查起来最快。4.3 Gradle 模板与 build-tools 的搭配验证切到 Gradle 之后Unity 会用工程里的mainTemplate.gradle和内置的 Gradle 版本去构建。build-tools版本不匹配的典型症状是编辑器里一切正常点 Build 之后进度条走到一半控制台丢出一段 Gradle 日志关键行是Failed to find build-tools version 28.0.3或者aapt2相关的com.android.tools.build:gradle版本冲突。我一般会在切 Gradle 之前先手工跑一次构建验证把问题暴露在命令行里而不是 Unity 的黑匣子里# 假设工程已导出为 Android Gradle 工程在工程根目录执行 cd Build/android-project ./gradlew assembleDebug --stacktrace --info 21 | tee gradle-build.log # 只看失败原因 grep -n -i failed\|error\|not found gradle-build.log | head -n 30--stacktrace会打出完整调用链虽然长但版本冲突的信息只在这一层才看得见--info会输出实际使用的 build-tools 路径直接告诉你 Gradle 挑中了哪个版本。tee是为了留档因为 Unity 的控制台窗口会截断长日志很多关键行在编辑器里根本看不到。这一步跑通之后再回 Unity 点 Build成功率会高很多。如果命令行能过、Unity 过不了问题基本就锁定在 Unity 侧的路径配置而不是 SDK 本身。5. 避坑Unity 打包 APK 卡在 SDK 上的五个现场这些都是我在不同机器、不同工程上反复遇到的记录下来省得下次再从头查。5.1 sdkmanager 窗口一闪而过日志里是 NoClassDefFoundError现象双击sdkmanager.bat黑窗口闪一下消失命令行里执行抛出一长串异常关键行是java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema。原因JAVA_HOME指向了 JDK 11 或更高版本。JAXB 在 Java 11 里被移出标准库26.1.1 的代码还在用这个包。注意机器上装多个 JDK 时PATH里的java和JAVA_HOME可能指向不同的 JDK脚本只认后者。解决把JAVA_HOME显式改成 JDK 8 的根目录新开一个终端窗口重试旧窗口的环境变量不会刷新。工程如果同时需要高版本 JDK 做别的就在打包脚本里局部设置JAVA_HOME别改全局。5.2 路径带非 ASCII 字符或空格链接阶段报找不到文件现象编译通过链接阶段报error: unable to open file或者aapt.exe相关的路径错误报错里给出的路径看着就是对的。原因老版本aapt和 Gradle 对路径里的空格、非 ASCII 字符处理不完整尤其中间产物目录会做一次路径拼接拼出来的路径被截断或者转义错误。这类报错信息极具误导性因为它显示的是拼接前的路径。解决SDK 根目录、JDK 目录、Unity 工程目录三者全部放在纯 ASCII、无空格的短路径下比如D:\android-sdk、D:\jdk8、D:\proj\game。工程已经在长路径下的可以先把工程复制到短路径验证一次确认是路径问题再决定是否迁移。5.3 只装了 toolsUnity 报 Android SDK is missing现象External Tools 里已经填了 SDK 路径Unity 仍然提示 SDK 缺失或者提示Unable to locate adb。原因解压出来的包里只有toolsplatform-tools是空的adb根本不存在。Unity 的检测逻辑里adb是判断 SDK 是否可用的标志之一。解决sdkmanager platform-tools装上然后确认sdk/platform-tools/adb.exe存在且能执行adb version。装完不需要重启 Unity但需要在 External Tools 面板里重新点一次路径选择框让它重新探测。5.4 构建到一半卡在 license not accepted现象构建进度卡在Checking Android SDK licenses或者报You have not accepted the license agreements。原因licenses目录不存在或者里面的哈希文件不完整。全新解压的 SDK 一定没有这个目录。解决跑一次sdkmanager --licenses并逐条确认。无交互环境下用管道批量确认见 2.3。确认完检查sdk/licenses/下是否生成文件空目录等于没接受。CI 场景下更稳的做法是把已接受许可的licenses目录随 SDK 一起打进镜像而不是每次构建都跑一遍交互命令。5.5 Target API Level 与已装 platforms 不一致现象点 Build 后立刻失败报Target SDK version not installed或者Failed to find target with hash string android-29。原因Player Settings 里的 Target API Level 指向了没装的 platform。这个设置容易被忽略因为它藏在 Player Settings 的二级面板里而且编辑器不会在设置时校验。解决两者对齐——要么装对应的platforms;android-XX要么把 Target 改到已装版本。工程是多人协作的改设置会同步到仓库所以更稳妥的是补齐组件而不是降版本。改完在 External Tools 里点一下刷新让 Unity 重新扫描已装 platform 列表。6. 进阶用 aapt 与 batchmode 把打包变成可复现流程真正让打包稳定下来的不是记住上面那些坑而是把验证动作固化成命令让每次出包都有可回查的证据。这一节是我自己出包前必走的两步。6.1 aapt dump badging 反查产物APK 打出来之后不要只看文件大小。aapt dump badging能读出包名、版本号、最低与目标 SDK、支持的 ABI这几项任何一项不对装到真机上就是闪退或者装不上。# Windowsaapt 在 build-tools 对应版本目录下 D:\android-sdk\build-tools\28.0.3\aapt.exe dump badging Build\app.apk | findstr /C:package /C:sdkVersion /C:native-code # macOS / Linux $ANDROID_HOME/build-tools/28.0.3/aapt dump badging Build/app.apk \ | grep -E package:|sdkVersion|targetSdkVersion|native-codepackage:行给出包名和versionCode、versionName用来核对发版号是否被 CI 脚本正确注入sdkVersion和targetSdkVersion用来核对是不是你以为的那一档native-code列出打进包里的 ABI缺少arm64-v8a就是 IL2CPP 或 NDK 配置漏了。这一步比在真机上装一遍快得多我现在是出包脚本里强制加的一行不通过就不许上传产物。6.2 Unity batchmode 无头打包图形界面打包的问题是不可复现——同一份代码两个人点出来的包可能不一样。把构建逻辑写成编辑器脚本再用 batchmode 调用能把整个流程钉死。using UnityEditor; using UnityEngine; public class BuildScript { // 场景列表按工程实际情况改顺序即启动顺序 private static readonly string[] Scenes { Assets/Scenes/Main.unity }; public static void BuildAndroid() { string outDir Build; if (!System.IO.Directory.Exists(outDir)) System.IO.Directory.CreateDirectory(outDir); var options new BuildPlayerOptions { scenes Scenes, locationPathName outDir /app.apk, target BuildTarget.Android, options BuildOptions.None }; // 老版本 Unity 返回错误字符串空串表示成功 string err BuildPipeline.BuildPlayer(options); // 用退出码把结果传给外部脚本CI 靠这个判断成败 EditorApplication.Exit(string.IsNullOrEmpty(err) ? 0 : 1); } }参数说明locationPathName是产物路径相对路径以工程根目录为基准scenes必须显式列出batchmode 下不会读取 Build Settings 里保存的场景列表BuildOptions.None表示不打 Development Build需要调试符号就换成BuildOptions.Development。如果是 2018.1 之后的版本返回值可以换成BuildReport用report.summary.result判断信息更全。调用命令是# WindowsUnity 可执行文件路径按实际安装位置改 D:\Unity\Editor\Unity.exe -quit -batchmode -nographics \ -projectPath D:\proj\game \ -executeMethod BuildScript.BuildAndroid \ -logFile D:\proj\game\build.log # 检查退出码0 才算成功 echo %ERRORLEVEL%-quit让 Unity 在方法执行完后退出-batchmode关闭交互界面-nographics在不带显卡的构建机上必需否则会因为初始化图形设备失败。-logFile指定日志落盘因为 batchmode 下控制台不输出任何东西出问题只能靠日志回查。跑完之后接上 6.1 的aapt校验整个链路就闭环了。6.3 把版本清单固定下来最后一步是把当前这套能跑通的版本记录到工程里写成android-env.txt之类的纯文本内容包括 JDK 版本、build-tools版本、platforms版本、NDK 版本以及sdkmanager --list_installed的完整输出。换机器、换人接手、半年后回头查都是靠这份清单而不是靠记忆。我吃过一次亏某次为了试新版本随手把build-tools升上去了当时能打一个月后另一个同事拉代码打包报了一堆aapt2相关错误查了两天才发现是环境不一致。从那以后我每次配完 SDK 环境都强制走一遍--list_installed导出清单并提交到仓库谁改了环境谁更新清单。这套工具本身不复杂难的是让它在一台新机器上稳定复现而清单就是那个后悔药。希望帮到你。本文还有配套的精品资源点击获取