macOS上基于命令行工具包搭建Android构建与模拟器环境 简介Android命令行工具commandlinetools-mac-11076708-latest.zip是官方发布的macOS版SDK管理套件专为不安装完整Android Studio、需要通过命令行完成Android SDK下载与构建的开发者设计。整个压缩包共104个文件以93个jar依赖库为主并集成sdkmanager、avdmanager、apkanalyzer、lint、retrace、screenshot2等可执行工具还包含properties配置文件和readme说明文档压缩后体积约146.49MB。目前已有201人学习/下载。借助sdkmanager可以灵活下载和管理多版本SDK组件avdmanager负责创建与管理Android虚拟设备apkanalyzer用于解析APK文件lint则能检查代码中的潜在问题。这套工具链覆盖了从环境准备、依赖管理到应用分析的常见流程适合已有命令行使用习惯的Android开发者也是理解Android SDK运行原理的实用资料。1. 在 macOS 上只靠一个命令行工具包拉起 Android 构建环境先认识 commandlinetools-mac-11076708-latest.zip如果你接到的任务是把一台全新的 Mac 变成 Android 构建机而不是写界面那么任何带图形界面的 IDE 都会显得笨拙又占地方。我第一次在测试机配 CI 镜像时就吃过这样的亏装完 IDE、再让它自动补全 SDK 组件磁盘少了十几个 GB而且没人敢动它的配置。后来换成下载 commandlinetools-mac-11076708-latest.zip 这个命令行工具包才开始觉得 Android 的构建链是可控的。这个压缩包本身不大解压后是一个 cmdline-tools 目录里面只提供 sdkmanager、avdmanager、apkanalyzer 这类命令行入口真正干活的 platform-tools、build-tools、platform、system-image都要靠这些命令去拉。适合三类人要脚本化打包的开发者、要同时管理多台苹果电脑构建机的人以及想搞懂 Android SDK 目录结构的人。2. 把 commandlinetools-mac 装成 SDK 根目录解压、目录布局与三个环境变量这个 zip 最大的特点是“解压就能用”但“放错地方就用不了”。很多人拿到压缩包直接双击解压到下载目录然后发现 sdkmanager 报错或者把包装到了奇怪的位置。问题不在命令本身而在命令行工具在 SDK 根目录里的相对位置。macOS 上要从零把 SDK 配好需要做三件事确认前置环境、按约定摆放 cmdline-tools、配置好 shell 变量。2.1 下载前先看架构和 Javamac 上装命令行工具最容易忽略的两个前置检查命令行工具本身是 Java 程序大部分逻辑跟 CPU 架构无关但你后续用 avdmanager 下载模拟器镜像时必须知道这台机器是 arm64 还是 x86_64。mac 上 Apple Silicon 与 Intel 的镜像 ABI 不通用选错镜像轻则创建失败重则模拟器启动后黑屏。先执行两条命令把环境底细记录下来。uname -m java -version第一条命令输出 arm64 表示这是 Apple Silicon 机器后续模拟器镜像要选 arm64-v8a输出 x86_64 就选 x86_64。第二条命令检查 JDK 版本高版本的命令行工具通常要求 Java 17 或更高。如果 java -version 报找不到命令或者版本停留在 8、11后面跑 sdkmanager 会直接在启动阶段崩掉。系统没装 Java 时常见做法是用包管理器装 openjdk17或者复用 IDE 自带的 Java 运行时目录。装完之后重新打开一个终端窗口再跑一遍 java -version直到看到 17 以上的版本号再做下一步。这个检查只花一分钟却能省掉后面最莫名其妙的一次排错。还有一个容易被忽略的点文件名里的 11076708 是这个工具包的构建编号官方会随发布周期换新编号。不要把这个数字写死在长期脚本里脚本只该关心它拿到的是哪一个压缩包否则这次用的编号在下个季度很可能就装不到新发布的平台组件。2.2 解压后必须把 cmdline-tools 放到 latest 子目录否则 sdkmanager 找不到自己zip 解压后得到的顶层目录叫 cmdline-tools里面是 bin 和 lib。sdkmanager 的默认行为是从自身执行路径反推 SDK 根目录它约定根目录下必须存在 cmdline-tools/latest/bin。也就是说正确结构是 $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager。如果只把解压目录丢到 SDK 根目录下路径会变成 $ANDROID_HOME/cmdline-tools/bin/sdkmanager运行时它找不到合法的根目录会把当前目录当成根后面安装的所有组件都落到错误位置。这是整个 mac 命令行工具安装里最常见的坑。我一般会先把压缩包解压到临时目录再整体移动成 latest这样无论 zip 内部结构是否变化最终目标唯一。ANDROID_SDK_ROOT$HOME/Android/sdk TOOLS_ZIP$HOME/Downloads/commandlinetools-mac-11076708-latest.zip TMP_DIR$(mktemp -d) unzip -q $TOOLS_ZIP -d $TMP_DIR mkdir -p $ANDROID_SDK_ROOT/cmdline-tools mv $TMP_DIR/cmdline-tools $ANDROID_SDK_ROOT/cmdline-tools/latest rm -rf $TMP_DIR这段命令先用 mktemp 创建临时目录避免解压文件散落在当前目录unzip 加上 -q 参数只输出错误信息干净一些。mkdir -p 确保 SDK 根下的 cmdline-tools 存在然后把临时目录里的 cmdline-tools 整体改名成 latest。如果你重复执行这段脚本需要对原来的 latest 做备份或删除否则 mv 会把旧目录嵌套成 latest/cmdline-tools目录叠套的坑就是这么来的。rm -rf 清理临时目录是为了不让副本留在磁盘上。完成后最好检查一下最终路径ls $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager能看到这个文件再继续。2.3 PATH、ANDROID_HOME、ANDROID_SDK_ROOT 一次配齐目录放好之后还需要让终端能找到 sdkmanager、avdmanager、adb 和 emulator。macOS 的 zsh 默认读 ~/.zshrc如果你的构建机登录 shell 是 bash就得写进 ~/.bash_profile。我倾向于只改当前用户的 rc 文件不改 /etc/paths避免影响机器上其他账号。export ANDROID_HOME$HOME/Android/sdk export ANDROID_SDK_ROOT$ANDROID_HOME export PATH$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$PATHANDROID_HOME 是早期工具链就在用的变量ANDROID_SDK_ROOT 是新版构建系统更认的名字两个都设能兼容更多场景。PATH 的顺序有讲究cmdline-tools/latest/bin 必须放在最前面避免 /usr/local/bin 或其他目录里存在同名命令时抢掉版本。platform-tools 和 emulator 目录此刻可能还不存在这不影响 shellPATH 里的无效目录会被忽略等后续组件装完就能直接使用。配置完成后执行 source ~/.zshrc再运行 sdkmanager --version能打印出版本号就说明这一层已经通了。如果提示 command not found优先看变量的拼写和当前 shell 环境如果打印 Java 报错回到 2.1 检查 JDK。注意不要用 sudo 去跑 sdkmanager尤其是 SDK 目录建在自己用户目录下时sudo 会把 licenses、临时文件变成 root 所有之后普通用户再写就会遇到权限拒绝。3. 用 sdkmanager 把真正干活的东西装进来platform-tools、platforms、build-tools 的最小命令cmdline-tools 本身不包含 adb、aapt2、android.jar它更像一个管家。你要做的下一步是告诉它需要哪些组件。这里最容易踩的误区是以为装了命令行工具就等于装了 SDK实际上跑构建时缺少 platform-toolsGradle 会一直报找不到 SDK缺少 build-toolsaapt2 无法处理资源。所以这一章把包名规则、最小安装命令、许可证处理都讲清楚。3.1 sdkmanager 的包名规则分号后面是什么cat 输出怎么看运行 sdkmanager --list 会输出很长的组件列表第一次看容易晕。列表里每个包名都带分号比如 platforms;android-34、build-tools;34.0.0、system-images;android-34;google_apis;arm64-v8a。这里的分号表示分类层次不是文件路径分隔符。在 shell 里必须用双引号把包名包起来否则某些环境下分号会被当成命令分隔符命令执行逻辑完全变样。常用组件可以大致分成五类表格里列的是最常遇到的包名。包名实际包含什么什么时候需要platform-toolsadb、fastboot、mke2fs 等任何设备交互、调试、安装 APKplatforms;android-34android.jar 和平台元数据Gradle 编译时必须匹配 compileSdkbuild-tools;34.0.0aapt2、aidl、zipalign 等手动做资源编译、签名对齐时使用emulator模拟器可执行文件需要跑虚拟设备时system-images;android-34;google_apis;arm64-v8a模拟器系统镜像创建 AVD 的前置条件还有 cmdline-tools;latest 这个包它是命令行工具自更新用的。原则上你不需要刻意安装但如果看到 sdkmanager 提示自身版本较老用这个包名可以拉取更新。这些组件占用从几百 MB 到几个 GB 不等所以在装之前要明确目标。如果只是命令行出包emulator 和 system-images 可以先不装要做 UI 自动化再补。这也是命令行方式比图形 IDE 更省磁盘的原因之一按需取用。3.2 最小安装命令--sdk_root、--channel 与版本配套装一组最常用的组件命令可以写成下面这样。推荐把 --sdk_root 显式写出来这样即使当前 shell 环境变量被其他脚本覆盖也仍然装到预期位置。sdkmanager --sdk_root$ANDROID_HOME \ platform-tools \ platforms;android-34 \ build-tools;34.0.0 \ emulatorplatform-tools 提供 adbplatforms;android-34 提供 android.jarGradle 的 compileSdk 为 34 时必须存在build-tools;34.0.0 里包含 aapt2 等资源处理工具虽然 Gradle 也能自动下载构建工具但手动装到一个固定版本更可控emulator 是模拟器本体不在 commandlinetools 范围内需要单独安装。包名里的版本号是有配套关系的platforms;android-34 通常对应 build-tools;34.0.0你用 33 的 platform 配 34 的 build-tools 也能跑但没必要。--channel 参数控制预览版渠道0 是正式版1 是 beta2 是 alpha3 是 canary。日常构建用 0 就够了尝鲜新 API 才需要调到 2 或 3。预览版可能伴随不兼容行为不建议把它写进正式构建脚本。安装过程中需要从网络拉取文件中途不要随意按 Ctrl-C否则会出现半安装状态licenses 目录写入了但组件文件不完整重新安装时又可能因为目录已存在而跳过覆盖一部分内容。3.3 许可证不通过怎么办yes 管道与 --licenses 的适用场景第一次安装带许可的组件时命令行工具会打印一长段协议然后停在那里等输入 y 或 n。人工操作没问题自动化流水线必须提前处理。最简单的方案是接一个 yes 管道。yes | sdkmanager --sdk_root$ANDROID_HOME platforms;android-34yes 会不断输出 y当命令读完需要的输入后管道关闭进程自然继续。适合只装一两个包的情况。如果需要同时装很多包每个包都去接受一遍很烦更值得统一处理。yes | sdkmanager --licenses --sdk_root$ANDROID_HOME这个命令会扫描 SDK 根目录下所有已安装但还未接受许可的组件统一补齐。许可接受状态记录在 SDK 目录下的 licenses 文件夹里同一类许可只要接受过一次后续再装不会重复询问。注意安装时不要用 sudo如果已经用了检查 licenses 目录是否属于当前用户必要时 chown 修正否则后续安装会一直提示权限不足。3.4 把 SDK 装进项目目录还是固定目录我如何选默认情况下我会把 SDK 放在 $HOME/Android/sdk 下所有项目共享一份省空间环境变量也好统一。但有些场景需要做到“项目私有”比如离线构建、多个客户要求不同 API 版本或者你想验证某一次构建在全新 SDK 下也能复现。这时可以把 SDK 放到项目里的隐藏目录。sdkmanager --sdk_root$PWD/.android-sdk \ platform-tools platforms;android-34 build-tools;34.0.0然后在项目 local.properties 里写上 sdk.dir 指向这个目录。要注意 sdk.dir 必须是绝对路径相对路径在 Gradle 解析时会出问题。项目私有 SDK 最大的缺点是体积一个最小的工具链至少三四个 GB多几个项目就会把磁盘吃光。所以我的选择标准是共享机器用固定目录临时实验或合规要求严格的构建环境才放项目目录。如果你把 local.properties 提交到版本库不同开发者路径不一致会立刻翻车正确的做法是把它加入忽略列表只在本地生成。4. avdmanager 建模拟器选镜像、写 device 配置、等待 sys.boot_completed有了平台和构建工具命令行出包已经能跑通。但做 UI 测试、截图回归、动态授权测试时还需要一台命令行能创建和启动的模拟器。avdmanager 是命令行工具里专门负责 AVD 的部分它可以做到和图形界面一样的效果而且每一步都可脚本化、可回放。这章从装镜像开始把创建到启动完整走一遍。4.1 先用 sdkmanager 装对 ABI 的系统镜像AVD 的核心是系统镜像所以在执行 avdmanager 之前必须先安装对应的 system-images。镜像包名结构是 system-images;android-API;variant;abi比如 system-images;android-34;google_apis;arm64-v8a。API 决定系统版本variant 通常是 google_apis 或 defaultabi 必须和宿主机架构一致。Apple Silicon 机器选 arm64-v8aIntel 机器选 x86_64。选错 ABI 不会在安装时报错但会在启动模拟器时出现各种诡异问题比如黑屏、CPU 不支持、进程反复崩溃。sdkmanager --sdk_root$ANDROID_HOME \ system-images;android-34;google_apis;arm64-v8a执行完后镜像会被放到 SDK 根目录下对应的 system-images/android-34/google_apis/arm64-v8a 目录。avdmanager 创建 AVD 时会读取这个路径所以如果镜像安装到了 A 目录而 ANDROID_SDK_ROOT 指向 B 目录结果就是找不到镜像。每次在脚本里创建 AVD 之前确认环境变量和 sdkmanager 使用同一个根目录这个检查只需要一条命令echo $ANDROID_SDK_ROOT。4.2 create avd 的参数和 echo no 的坑镜像就绪后创建 AVD 的最小命令如下。printf no\n | avdmanager create avd \ -n ci_avd \ -k system-images;android-34;google_apis;arm64-v8a \ --device pixel_6 \ --force-n 指定 AVD 名称后续启动用这个名称找到设备-k 要填完整的镜像包名必须与已安装镜像完全一致--device 指定硬件模板pixel_6 提供一组默认分辨率、density 和外形参数--force 表示同名 AVD 存在时直接覆盖这在反复跑脚本时很有用。printf no\n 回答的是创建过程中那个交互式问题“Do you wish to customize the hardware profile? [no]”。很多人直接不加结果脚本卡在交互等待上。不使用 yes 管道的原因很简单create avd 只期望一行输入yes 会不断输出反而可能干扰后续流程。创建完成后可以用下面命令检查。avdmanager list avd -c这个命令只输出有效 AVD 的配置路径。看到类似 ~/.android/avd/ci_avd.avd 的结果说明创建成功。如果列表为空多半是系统镜像没有安装或者环境变量没有指到同一个 SDK 根目录。4.3 启动模拟器与等待开机完成的轮询写法创建好 AVD 只是生成配置文件真正的模拟器进程由 emulator 命令启动。在无显示器或 SSH 场景下需要加无头参数。$ANDROID_HOME/emulator/emulator -avd ci_avd \ -no-window -no-audio -no-boot-anim -no-snapshot -no-window 关闭窗口适合 CI-no-audio 去掉音频设备-no-boot-anim 跳过开机动画缩短冷启动时间-no-snapshot 不使用快照恢复保证每次从干净状态启动避免历史状态污染测试。模拟器进程在后台运行调试时可以把这些参数去掉留下 -avd ci_avd 就能看到图形窗口。设备在线和系统启动完成是两回事adb wait-for-device 只代表设备被 adb 识别不代表可以开始操作。要等系统真正起来需要轮询 getprop。export PATH$ANDROID_HOME/platform-tools:$PATH adb wait-for-device until [ $(adb shell getprop sys.boot_completed 2/dev/null | tr -d \r) 1 ]; do sleep 2 doneadb shell getprop sys.boot_completed 在系统未完成启动时返回空字符串完成后返回 1。tr -d \r 是为了去掉 Windows 风格的回车符macOS 下一般没有但脚本复制到 Windows 环境时这行能避免奇怪的字符串比较问题。轮询间隔设 2 秒比较合理太快会频繁拉起 adb 进程太慢则会拖慢整个构建流程。如果 3 分钟内还没完成说明模拟器可能陷入重启循环需要回头检查配置。4.4 基于 config.ini 调分辨率、内存和 CPU 核数创建 AVD 时使用的硬件模板决定了初始的屏幕尺寸和内存但实际测试时往往要按需调整。AVD 的配置文件在 ~/.android/avd/名称.avd/config.ini模拟器关闭状态下可以手动修改。常见改动是下面几项。hw.ramSize 2048 hw.cpu.ncore 4 hw.lcd.width 1080 hw.lcd.height 2340hw.ramSize 单位是 MB2048 表示给模拟器 2GB 内存这个值不是越大越好macOS 本身也要内存设置过大会拖慢宿主机。hw.cpu.ncore 控制模拟器可用 CPU 核数设成 4 基本够用除非宿主机核数很多且确有余量。分辨率修改后渲染压力会明显变化无头模式下影响不大有窗口的本地调试会变卡。特别注意修改 config.ini 前一定要确认模拟器进程已退出否则退出时模拟器会把内存中的旧配置写回来覆盖你的修改。5. mac 命令行工具包使用排查五个经典翻车点的现象、原因、解决即便前面章节全部照做实际运行一周后仍可能遇到问题。有些问题只出现在特定机器上有些则出现在重装或升级之后。下面五条是高频率翻车现场按现象到原因再到解决的顺序写可以直接对照处理。5.1 现象sdkmanager 报 java.lang.NoClassDefFoundError新装的命令行工具一执行就在启动阶段失败错误提示里有 java.lang.NoClassDefFoundError有时还提到 javax/xml/bind/JAXBException。原因是机器默认的 Java 版本太老高版本命令行工具需要的模块在 Java 8 或 11 里不存在。macOS 上如果同时存在系统自带 Java 和后来安装的 JDK很容易出现默认版本不对。解决方法是先检查当前 shell 的 JVM 版本java -version。如果版本低于 17安装新版 JDK 后把 JAVA_HOME 指到新 JDK 的目录。如果不想额外装 Java可以复用某个 IDE 运行时把 JAVA_HOME 指向 IDE 安装包内的 jbr 目录。改完环境变量后要重新打开终端因为当前 shell 的变量不会自动刷新。这个问题最气人的地方在于它不影响 IDE 内的构建只在纯命令行环境下爆炸所以排查时第一反应往往不对。5.2 现象platform-tools 装完adb 仍然 command not foundsdkmanager 明确显示 platform-tools 安装成功但新终端里运行 adb 却提示找不到。原因通常是 PATH 里没有加入 $ANDROID_HOME/platform-tools或者环境变量里 SDK 路径与组件实际安装路径不一致。先执行 ls $ANDROID_HOME/platform-tools/adb 确认文件是否存在如果文件在就检查 shell 配置里 PATH 是否包含这个目录如果文件不在看是否因为安装时使用了 --sdk_root 指向了别的位置。还有一种少见的情况是用户把 SDK 放在云同步目录或网络盘里adb 这种需要可执行权限和局部 socket 文件的工具在这种文件系统上会失效把 SDK 移到本地普通目录再试。5.3 现象avdmanager create avd 在交互提示卡住脚本执行到 create avd 时一直停着没有报错也没有输出CI 任务直到超时。原因是 create avd 会从标准输入读取“是否自定义硬件配置文件”的答复脚本没有给它任何输入它就一直等待。解决方法是显式给一行输入。推荐使用 printf no\n 而不是 echo no两者行为接近但 printf 不依赖 shell 别名在严格模式下更可控。如果这条命令已经被包装到其他函数里确认标准输入没有被重定向到 /dev/null否则 printf 的信息也不会被命令读到。在 CI 的 YAML 配置里我会把整条命令写成一个脚本步骤而不是拆成多条 shell 字符串避免管道的解析差异。5.4 现象模拟器黑屏、boot_completed 一直不返回模拟器进程在运行adb devices 也能看到设备但 sys.boot_completed 一直不是 1或者屏幕长时间黑着。最常见的原因是镜像 ABI 与宿主机不匹配Intel 机器上装了 arm64-v8a 镜像运行时靠二进制转换性能极差且容易卡死。其次是配置的内存过低系统反复重启。解决方法是先确认 uname -m 的输出与 system-images 包名中的 ABI 是否一致再检查 config.ini 的 hw.ramSize 是否低于 1536。把内存调到 2048核数至少 2加上 -gpu swiftshader_indirect 参数很多渲染相关的问题能缓解。另外要检查后台是否残留了多个模拟器进程多个实例同时启动会抢占资源先全部杀掉再重启。5.5 现象旧版 zip 的编号过期后装不了新 API某个时间点之后sdkmanager --list 里看不到新发布的 API 组件或者安装某个新 platform 时报 404。原因是命令行工具包本身是一个固定的构建版本随着时间推移新组件的索引不会主动进入旧版工具。解决方法是更新命令行工具本身。可以用 sdkmanager cmdline-tools;latest 自更新也可以直接重新下载新的 mac 版压缩包按第 2 章的流程覆盖 latest 目录。我更倾向于重新下载压缩包因为能顺势确认压缩包的目录结构和权限。覆盖前先备份旧的 latest新工具验证无误后再删除备份这个习惯能避免更新后工具不能用的尴尬。6. 把整套流程固化成一条命令从 unzip 到模拟器 boot 完成的初始化脚本前面所有的步骤最终都应该变成一条能重复执行的命令。下面这段脚本把下载好的压缩包路径作为唯一入参完成解压、摆放、安装组件、创建 AVD、启动并等待开机完成。适合放在新机器的初始化任务里。6.1 一个可重复执行的 bash 脚本#!/bin/bash set -euo pipefail TOOLS_ZIP${1:?请提供 commandlinetools zip 路径} SDK_DIR${ANDROID_HOME:-$HOME/Android/sdk} TMP$(mktemp -d) unzip -q $TOOLS_ZIP -d $TMP mkdir -p $SDK_DIR/cmdline-tools rm -rf $SDK_DIR/cmdline-tools/latest mv $TMP/cmdline-tools $SDK_DIR/cmdline-tools/latest rm -rf $TMP export ANDROID_HOME$SDK_DIR export ANDROID_SDK_ROOT$SDK_DIR export PATH$SDK_DIR/cmdline-tools/latest/bin:$SDK_DIR/platform-tools:$SDK_DIR/emulator:$PATH yes | sdkmanager --sdk_root$SDK_DIR \ platform-tools \ platforms;android-34 \ build-tools;34.0.0 \ emulator sdkmanager --sdk_root$SDK_DIR \ system-images;android-34;google_apis;arm64-v8a printf no\n | avdmanager create avd \ -n ci_avd \ -k system-images;android-34;google_apis;arm64-v8a \ --force $SDK_DIR/emulator/emulator -avd ci_avd -no-window -no-audio -no-boot-anim -no-snapshot adb wait-for-device for i in $(seq 1 60); do if [ $(adb shell getprop sys.boot_completed 2/dev/null | tr -d \r) 1 ]; then echo boot completed exit 0 fi sleep 2 done echo boot timeout 2 exit 1set -euo pipefail 的作用是遇到未定义变量、命令失败或管道中任一环节出错时立即退出避免 CI 误判。rm -rf 旧的 latest 让脚本可重复执行这是我在第一次目录叠套翻车后加进去的。yes 管道负责统一接收所有许可printf 只回答 create avd 的一个问题for 循环给开机等待加了 120 秒上限超时直接退出并返回错误码不会让任务无限挂起。如果你用的是 Intel Mac把 system-images 包名里的 arm64-v8a 改成 x86_64 再执行。6.2 跑完以后的验证与软收尾模拟器启动完成后先确认设备状态再执行分辨率检查。adb devices adb shell wm size adb emu killwm size 输出的结果应该与 config.ini 里设置的分辨率一致如果不一致说明模拟器进程启动时可能读取了旧配置需要关闭后检查配置。adb emu kill 是优雅关闭模拟器的命令比直接 kill 进程更可靠直接杀进程有时会留下锁文件导致下次启动报“another emulator instance is running”。整套脚本第一次执行大约需要下载几个 GB 组件磁盘不够时最容易卡在 system-images 那一步。中断后不要直接重跑先看 SDK 目录里有没有半包有就删掉对应目录再跑。我在一次现场演示前没清理旧 latest解压后目录叠套导致 avdmanager 用旧版本工具报了一堆不可名状的问题。后来把“先删再 mv”固定进脚本再也没翻过车。把这个顺序当成默认习惯能帮你省下不少排错时间。希望帮到你。本文还有配套的精品资源点击获取