1. 项目概述:为什么真有必要在命令行里跑 Android 应用?
你有没有过这种体验:打开 Android Studio,等它加载完 Gradle、索引完项目、启动模拟器——整个过程像在煮一锅慢炖汤,CPU 风扇呼呼作响,内存占用直逼 8GB,而你只是想快速验证一行Toast是否弹出来了?或者,你正在一台只有 4GB 内存的旧笔记本上调试一个轻量级工具类 App,IDE 一开就卡死,连adb devices都要等三秒才响应。又或者,你在写 CI/CD 流水线,需要让 Jenkins 或 GitHub Actions 自动构建、安装、启动、截图、抓日志——这时候,图形界面不仅多余,更是障碍。
这正是本文要解决的真实问题:绕过 IDE,用纯命令行完成 Android 应用的全生命周期操作——从环境准备、项目编译、APK 安装、应用启动,到实时日志监控与行为验证。它不是炫技,而是回归开发本质:Android 本身是一套基于 Linux 的操作系统,它的构建、部署、调试机制天然就是命令行友好的。IDE 只是封装层,而命令行才是它的“原生语言”。
关键词“Android”在这里不是泛指系统,而是特指其开发工具链的底层能力:adb是与设备通信的神经中枢,gradlew是构建系统的执行引擎,emulator是虚拟硬件的控制台。掌握它们,你就拿到了 Android 开发的“机械钥匙”——不依赖图形界面,不被 IDE 版本绑架,不因内存不足而停摆。我带过的实习生里,有三位在入职第一周就靠这套流程独立完成了自动化测试脚本的搭建;我自己在给一个嵌入式设备做定制化 Android 系统适配时,全程没开过一次 Android Studio,所有调试都靠终端里的adb shell和logcat完成。这不是极客癖好,而是工程效率的刚需。
2. 核心工具链解析与环境搭建实操
2.1 工具链选型逻辑:为什么只选这三样?
很多初学者会疑惑:“为什么不用maven或ant?fastlane不是更高级吗?”答案很实在:稳定性、最小依赖、官方支持度。我们的目标是“能跑就行”,不是“功能最全”。gradlew(Gradle Wrapper)是 Android 官方强制推荐的构建方式,它自带指定版本的 Gradle,避免了本地 Gradle 版本与项目不兼容的“玄学错误”;adb是 Android SDK Platform-Tools 的核心组件,十年来接口稳定,文档完备,所有设备厂商都必须兼容;emulator是官方模拟器二进制,虽然后来有了Android Emulator Hypervisor Driver(Windows)或Hypervisor.Framework(macOS)加速,但命令行调用方式十年未变。
相比之下,fastlane是上层自动化框架,依赖 Ruby 环境,配置复杂,出错时堆栈信息冗长;maven构建 Android 项目早已被官方弃用,文档稀少且极易报错。我试过用maven-android-plugin编译一个简单的 Hello World,光是解决android-maven-plugin版本与sdk版本的兼容性就花了两天——而用gradlew build,30 秒搞定。所以,本文只聚焦这三个基石工具,因为它们构成了 Android 命令行开发的“黄金三角”:构建(gradlew)、通信(adb)、运行(emulator)。
2.2 JDK 安装:版本选择与路径陷阱
JDK 是所有 Java 生态的起点,但版本选错,后面全是坑。截至 2024 年,Android 官方明确支持的 JDK 版本是 JDK 17(LTS)和 JDK 21(LTS)。JDK 21 是最新 LTS,但部分老项目(尤其是使用androidx.appcompat:appcompat:1.4.x以下版本的)在 JDK 21 下会触发--illegal-access=warn警告,进而导致gradlew启动失败。因此,我的实操建议是:新项目一律用 JDK 21,老项目降级到 JDK 17。
安装时,切记不要用系统包管理器(如apt install openjdk-17-jdk)直接装,因为 Ubuntu/Debian 的包管理器常会把JAVA_HOME指向/usr/lib/jvm/java-17-openjdk-amd64这种路径,而gradlew在某些情况下会读取错误的java二进制文件。正确做法是:
- 去 Adoptium 下载
Eclipse Temurin JDK 17或JDK 21的.tar.gz包; - 解压到固定目录,例如
~/jdk-17.0.1; - 在
~/.bashrc或~/.zshrc中添加:export JAVA_HOME="$HOME/jdk-17.0.1" export PATH="$JAVA_HOME/bin:$PATH" - 执行
source ~/.bashrc,然后验证:java -version # 输出应为 "17.0.1" 或 "21.0.1" echo $JAVA_HOME # 输出应为 "/home/yourname/jdk-17.0.1"
提示:
echo $JAVA_HOME必须输出绝对路径,且不能包含符号链接(如/usr/lib/jvm/default-java)。我曾在一个客户现场遇到gradlew build报错Could not determine java version from '17.0.1',排查两小时才发现JAVA_HOME指向的是一个软链接,gradlew内部脚本无法解析。直接指向真实路径,一劳永逸。
2.3 Android SDK 安装:精简主义与路径规范
Android SDK 动辄几个 GB,但命令行开发根本不需要全部。我的经验是:只装三个核心组件,总大小可压缩到 1.2GB 以内。它们是:
- Platform-Tools:包含
adb、fastboot,必备; - Build-Tools:选一个稳定版本,如
34.0.0(2024 年主流),不必装多个; - Platforms:只装目标 API Level,例如你的
build.gradle里compileSdk 34,那就只装android-34。
安装方式有两种:GUI 安装器(Android Studio 附带)或命令行sdkmanager。后者更可控。首先,下载 Command line tools only (注意:不是完整版 Android Studio!),解压后得到cmdline-tools/latest/目录。将其加入PATH:
export ANDROID_HOME="$HOME/android-sdk" export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$PATH"然后执行:
# 初始化 sdkmanager sdkmanager --sdk_root=$ANDROID_HOME --list_installed # 查看当前已装组件 # 安装核心三件套(以 API 34 为例) sdkmanager --sdk_root=$ANDROID_HOME "platform-tools" "build-tools;34.0.0" "platforms;android-34"注意:
sdkmanager默认会把组件装到$ANDROID_HOME下,但cmdline-tools本身必须放在$ANDROID_HOME/cmdline-tools/latest/这个固定路径,否则sdkmanager会报错Failed to find SDK root path。这是 Google 设计的一个硬编码路径,踩过坑才知道。
2.4 环境变量终极校验:五步法确认万无一失
环境变量是命令行开发的“地基”,地基不牢,后面全崩。我总结了一套五步校验法,每次换新机器或重装系统必做:
java -version:确认 JDK 版本与JAVA_HOME一致;echo $ANDROID_HOME:确认非空,且路径存在;ls $ANDROID_HOME/platform-tools/adb:确认adb二进制文件存在;ls $ANDROID_HOME/emulator/emulator:确认模拟器二进制存在(如果要用模拟器);which adb:确认PATH中的adb指向$ANDROID_HOME/platform-tools/adb,而非/usr/bin/adb(系统自带的旧版)。
执行完这五步,如果全部通过,恭喜,你的命令行 Android 开发环境已经“出厂合格”。我曾帮一位同事远程调试,他卡在第四步,ls $ANDROID_HOME/emulator/emulator报错No such file or directory,最后发现他下载的是“Android Studio for Linux”,而不是“Command line tools only”,导致emulator根本没装进去。工具链的每个环节,都必须亲手验证,不能假设。
3. 全流程实操:从空目录到应用启动的每一步
3.1 创建最小可行项目:android create project已成历史
Android 官方早在 2015 年就废弃了android create project命令,现在创建项目必须用gradle init或androidx模板。但为了纯粹的命令行体验,我们采用最轻量的方式:手动创建一个极简的build.gradle和AndroidManifest.xml。这比用Android Studio新建项目再删掉一堆东西更干净。
在任意空目录下,执行:
mkdir my-cli-app && cd my-cli-app mkdir -p app/src/main/{java/com/example/mycli, res/layout, res/values}然后创建app/src/main/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.mycli"> <application android:allowBackup="true" android:label="My CLI App" android:supportsRtl="true"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>再创建app/src/main/java/com/example/mycli/MainActivity.java:
package com.example.mycli; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }最后,创建app/src/main/res/layout/activity_main.xml(内容为空布局即可)和app/src/main/res/values/strings.xml(定义app_name)。这个项目没有 UI,但足以验证整个构建-安装-启动流程。
3.2 构建 APK:gradlew build的隐藏参数与提速技巧
进入项目根目录,执行./gradlew build是标准操作,但它默认会执行所有任务:compileDebugJavaWithJavac、mergeDebugResources、packageDebug……对于只想快速得到一个可安装 APK 的场景,这太慢了。真正的命令行高手,只执行最必要的任务:assembleDebug。它跳过测试、lint、javadoc 等所有非构建环节,速度提升 3-5 倍。
执行:
./gradlew assembleDebug成功后,APK 位于app/build/outputs/apk/debug/app-debug.apk。但这里有个关键细节:gradlew脚本第一次运行时,会自动下载对应版本的 Gradle(如gradle-8.4-bin.zip),这个过程需要联网,且下载源是https://services.gradle.org/distributions/。在国内,这个域名常被 DNS 污染,导致超时。解决方案是:在项目根目录创建gradle/wrapper/gradle-wrapper.properties文件,修改distributionUrl:
distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists腾讯云镜像站稳定快速,亲测下载时间从 10 分钟缩短到 20 秒。这个小改动,能让你在任何网络环境下都流畅构建。
3.3 设备连接与状态诊断:adb devices的深层含义
adb devices是命令行开发的第一道门,但它的输出远不止“设备列表”那么简单。执行后,你可能看到:
List of devices attached emulator-5554 device 0123456789ABCDEF offline这里的device表示设备已连接且 ADB 守护进程(adbd)正常运行;offline表示设备已连接,但adbd未启动或通信异常;unauthorized表示设备已连接,但 USB 调试授权未通过(常见于新手机首次连接)。
诊断offline的标准流程是:
- 在设备上重启
adbd:adb kill-server && adb start-server; - 检查设备 USB 调试是否开启(设置 > 开发者选项 > USB 调试);
- 拔插 USB 线,或更换 USB 端口(尤其避免 USB 3.0 的蓝色接口,有时兼容性差);
- 如果是模拟器,检查
emulator进程是否存活:ps aux | grep emulator。
实操心得:我曾在一个客户现场,
adb devices一直显示offline,折腾半小时无果。最后发现是客户公司的安全策略软件拦截了adb的网络端口(5037),卸载该软件后立即恢复。所以,当adb devices异常时,先查杀毒软件和企业安全代理,比查线缆更有效。
3.4 安装与覆盖安装:adb install的-r、-t、-d参数详解
adb install -r app-debug.apk是最常用的命令,但-r(replace)只是冰山一角。实际开发中,你会频繁用到另外两个参数:
-t(test):用于安装带有android:testOnly="true"属性的 APK。很多 CI 流水线生成的测试 APK 默认加了这个 flag,不加-t会报错Failure [INSTALL_FAILED_TEST_ONLY];-d(downgrade):当设备上已安装更高版本号(android:versionCode)的 APK 时,adb install会拒绝覆盖。加-d可强制降级安装,对回滚测试非常有用。
一个完整的安装命令组合可能是:
adb install -r -t -d app-debug.apk它表示:覆盖安装(-r)、允许测试 APK(-t)、允许降级(-d)。这个组合拳,能应对 95% 的安装场景。
但要注意:adb install有大小限制,APK 超过 100MB 时,部分旧设备会报错INSTALL_FAILED_INSUFFICIENT_STORAGE,即使存储空间充足。此时必须用adb push+pm install组合:
adb push app-debug.apk /data/local/tmp/ adb shell pm install -r /data/local/tmp/app-debug.apk/data/local/tmp/是设备上的临时目录,权限宽松,不受 APK 大小限制。这是我处理大体积 TensorFlow Lite 模型 App 的标准操作。
3.5 启动应用:am start的 Intent 构造艺术
adb shell am start -n "com.example.mycli/.MainActivity"是启动应用的命令,但-n(component name)只是最基础的用法。真正强大的是-a(action)、-c(category)、-e(extra)的组合,它能模拟用户点击、传入参数、甚至触发特定广播。
例如,启动一个带参数的 Activity:
adb shell am start -n "com.example.mycli/.MainActivity" -e "key1" "value1" -e "key2" "123"在MainActivity的onCreate()中,你可以这样获取:
Intent intent = getIntent(); String value1 = intent.getStringExtra("key1"); // "value1" int value2 = intent.getIntExtra("key2", 0); // 123更实用的场景是:启动应用并直接进入某个 Fragment 或页面。很多 App 的主 Activity 是一个容器,真正的业务页由 Fragment 承载。这时,你可以定义一个自定义 Action:
<intent-filter> <action android:name="com.example.mycli.ACTION_SHOW_SETTINGS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>然后用命令启动:
adb shell am start -a "com.example.mycli.ACTION_SHOW_SETTINGS"App 内部的MainActivity就可以根据intent.getAction()判断并跳转。这比写一堆if-else判断Intent的 extra 更优雅,也更符合 Android 设计规范。
3.6 日志监控:logcat的过滤与实时分析
adb logcat是调试的灵魂,但原始输出是信息洪流。必须学会过滤,否则等于在噪音中找针。核心过滤语法是:
adb logcat [tag]:[level] [tag]:[level] ...其中tag是日志标签(如ActivityManager、dalvikvm),level是日志级别(VVerbose,DDebug,IInfo,WWarning,EError,FFatal,SSilent)。
实战中最常用的三个命令:
只看当前应用的日志(按包名过滤):
adb logcat --pid=$(adb shell pidof -s com.example.mycli)pidof命令获取进程 ID,--pid只显示该 PID 的日志,精准高效。过滤特定标签和级别(如只看 ERROR):
adb logcat ActivityManager:E MyAppTag:D *:S*:S表示屏蔽所有其他日志,ActivityManager:E只显示ActivityManager的 ERROR 级别,MyAppTag:D显示你自定义标签的 DEBUG 级别。保存日志到文件并实时追加:
adb logcat -v threadtime > app.log & tail -f app.log-v threadtime添加线程时间和进程 ID,便于分析并发问题;&让logcat在后台运行;tail -f实时查看。
注意:
logcat默认缓冲区是 64KB,日志过多会被覆盖。用adb logcat -g查看当前缓冲区大小,用adb logcat -G 2M扩大到 2MB,避免关键日志丢失。我在调试一个内存泄漏问题时,就是因为缓冲区太小,OutOfMemoryError的堆栈信息被刷掉了,浪费了整整一天。
4. 常见问题与排查技巧实录
4.1 构建失败:Could not resolve all files for configuration ':app:debugRuntimeClasspath'
这是 Gradle 依赖解析失败的典型报错,表面看是网络问题,但根源往往在build.gradle的仓库配置。Android 项目默认使用google()和mavenCentral(),但mavenCentral()在国内访问极不稳定。解决方案是:在项目根目录的build.gradle(或settings.gradle)中,将mavenCentral()替换为阿里云镜像:
repositories { google() maven { url 'https://maven.aliyun.com/repository/public' } maven { url 'https://maven.aliyun.com/repository/google' } }同时,在gradle/wrapper/gradle-wrapper.properties中,确保distributionUrl指向国内镜像(如前文所述)。这两步做完,90% 的依赖解析失败都能解决。如果仍有问题,执行./gradlew --refresh-dependencies强制刷新缓存。
4.2 安装失败:Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE]
这个错误意味着你试图安装的 APK,其package name与设备上已安装的某个 App 相同,但签名不一致。Android 系统强制要求:同一package name的 App,必须用同一套密钥签名,否则拒绝安装。常见于:
- 用 Android Studio 直接 Run(使用 debug keystore);
- 然后用命令行
gradlew assembleDebug构建并安装(同样用 debug keystore)——这通常没问题; - 但如果之前用
signingConfigs配置了自定义 release keystore,而这次没配,就会冲突。
排查方法:adb shell pm list packages -f | grep "com.example.mycli",查看已安装 APK 的完整路径,然后adb pull下来,用jarsigner -verify -verbose -certs xxx.apk检查签名证书指纹。如果指纹不同,就必须先adb uninstall com.example.mycli,再重新安装。
4.3 启动失败:Error type 3 Error: Activity class {com.example.mycli/.MainActivity} does not exist.
这个错误说明adb am start指定的 Activity 类在 APK 中不存在。原因有三:
- 类名拼写错误:检查
AndroidManifest.xml中<activity android:name=".MainActivity">的name属性,.开头表示相对包名,必须与package属性一致; - Activity 未在 Manifest 中声明:这是新手最高频错误,以为写了 Java 类就能启动,忘了注册;
- 构建产物未更新:执行
./gradlew clean assembleDebug,确保app-debug.apk是最新构建的。
一个快速验证方法是:aapt dump badging app-debug.apk | grep "launchable-activity",它会直接输出 APK 中声明为LAUNCHER的 Activity 全限定名,复制粘贴到adb am start -n命令中,100% 准确。
4.4 模拟器启动黑屏:emulator: ERROR: x86_64 emulation currently requires hardware acceleration!
这是 Windows/macOS 上最常见的模拟器报错。根本原因是:CPU 虚拟化技术(Intel VT-x / AMD-V)未在 BIOS 中开启,或 Windows Hyper-V / macOS Hypervisor.Framework 未启用。
- Windows:进入 BIOS,找到
Intel Virtualization Technology或AMD SVM Mode,设为Enabled;然后在 Windows 功能中,关闭 Hyper-V 和 Windows Hypervisor Platform(注意:不是开启!因为 Android Emulator 使用的是自己的 HAXM 或 Windows Hypervisor Driver,与 Hyper-V 冲突); - macOS:无需 BIOS 设置,但需确保
Hypervisor.Framework已启用(macOS 10.10+ 默认开启); - Linux:检查
kvm模块是否加载:lsmod | grep kvm,若无输出,则sudo modprobe kvm-intel(Intel CPU)或sudo modprobe kvm-amd(AMD CPU)。
实操心得:我在一台戴尔 XPS 笔记本上遇到此问题,BIOS 里明明开启了 VT-x,但模拟器还是报错。最后发现是戴尔预装的
Dell SupportAssist软件在后台启用了Virtualization Based Security (VBS),它独占了 VT-x,导致模拟器无法使用。卸载该软件后,问题立刻解决。所以,当硬件加速报错时,除了查 BIOS,还要查系统级安全软件。
4.5 日志无输出:adb logcat一片空白
这通常不是logcat坏了,而是日志缓冲区被清空或过滤太严。首先,执行adb logcat -c清空缓冲区,然后立即adb logcat,看是否有基础系统日志(如I/ActivityManager);如果没有,说明adbd进程异常,执行adb kill-server && adb start-server;如果只有系统日志,没有你的 App 日志,检查是否在AndroidManifest.xml的<application>标签中设置了android:debuggable="false"(Release 模式下默认为 false),这会导致Log.d()等低级别日志被编译器移除。解决方案:在build.gradle的buildTypes中,为debug类型显式设置:
debug { debuggable true jniDebuggable true }5. 进阶技巧与工程化实践
5.1 一键脚本:将全流程封装为run.sh
重复输入一长串命令是反生产力的。我习惯为每个项目创建一个run.sh脚本,实现“一键构建-安装-启动-日志”:
#!/bin/bash # run.sh set -e # 任何命令失败,脚本立即退出 echo "✅ 步骤1:构建 APK..." ./gradlew assembleDebug echo "✅ 步骤2:安装 APK..." adb install -r -t -d app/build/outputs/apk/debug/app-debug.apk echo "✅ 步骤3:启动 MainActivity..." adb shell am start -n "com.example.mycli/.MainActivity" echo "✅ 步骤4:开始日志监控(按 Ctrl+C 退出)..." adb logcat --pid=$(adb shell pidof -s com.example.mycli) -v threadtime赋予执行权限:chmod +x run.sh,然后./run.sh。set -e是关键,它保证任何一个步骤失败,脚本就停止,不会出现“APK 没构建成功却去安装”的尴尬。这个脚本,是我每天早上启动开发环境的第一条命令。
5.2 CI/CD 集成:GitHub Actions 中的 Android 命令行流水线
命令行能力的终极体现,是在无人值守的 CI/CD 环境中稳定运行。以下是一个精简的.github/workflows/android.yml示例:
name: Android CI on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - name: Setup Android SDK uses: android-actions/setup-android@v2 with: sdk-path: ${{ github.workspace }}/android-sdk - name: Build APK run: ./gradlew assembleDebug env: ANDROID_HOME: ${{ github.workspace }}/android-sdk - name: Upload APK Artifact uses: actions/upload-artifact@v3 with: name: app-debug path: app/build/outputs/apk/debug/app-debug.apk核心要点是:actions/setup-java和actions/setup-android这两个官方 Action,能自动配置好JAVA_HOME和ANDROID_HOME,省去了手动下载 SDK 的麻烦。env环境变量确保gradlew能找到正确的 SDK 路径。这个流水线,能在 3 分钟内完成从代码提交到 APK 生成的全过程,且完全可审计、可复现。
5.3 性能监控:adb shell top与dumpsys meminfo的组合拳
命令行不仅是构建和调试工具,更是性能分析利器。当 App 卡顿时,adb shell top -m 10可以实时查看 CPU 占用最高的前 10 个进程,确认是否是你的 App 主线程在死循环;而adb shell dumpsys meminfo com.example.mycli则能精确到每个对象的内存分配,输出类似:
Applications Memory Usage (in Kilobytes): Pss Private Public Swapped Dirty Heap Heap Heap Total Total Total Total Total Size Alloc Free ...其中Private Dirty是该 App 独占的物理内存,是判断内存泄漏的关键指标。我曾用这个命令发现一个图片加载库在Activity销毁后仍持有Context引用,导致Private Dirty持续增长,最终定位并修复了内存泄漏。
5.4 安全加固:adb的权限控制与生产环境规避
adb是一把双刃剑。在开发环境,它提供了无与伦比的便利;但在生产环境,它是一个巨大的安全风险。因此,所有面向用户的 Release APK,必须确保android:debuggable="false",且设备的 USB 调试开关必须关闭。更进一步,可以在Application类的onCreate()中加入检测:
if (BuildConfig.DEBUG || (Settings.Global.getInt(getContentResolver(), Settings.Global.ADB_ENABLED, 0) == 1)) { Toast.makeText(this, "警告:ADB 已启用!", Toast.LENGTH_LONG).show(); }这段代码在 Debug 模式或 ADB 开启时弹出警告,提醒开发者不要将调试版 APK 发布出去。这是我在多个金融类 App 项目中强制推行的安全红线。
6. 个人经验总结:从命令行到工程思维的跃迁
写完这篇长文,我想分享一个贯穿始终的体会:命令行不是目的,而是培养工程思维的训练场。当你不再依赖 IDE 的“Run”按钮,而是亲手敲出./gradlew assembleDebug、adb install、adb shell am start这一连串命令时,你实际上是在拆解 Android 开发的“黑盒子”。你知道了构建的本质是 Gradle 的任务图执行,安装的本质是pm install命令调用 PackageManagerService,启动的本质是 ActivityManagerService 解析 Intent 并调度 ActivityStack。
这种“知其所以然”的能力,会让你在面对复杂问题时游刃有余。比如,当团队里有人问“为什么这个 Bug 在 Android Studio 里复现不了,但在命令行构建的 APK 里必现?”,你马上会想到:IDE 可能用了不同的 Gradle Daemon、不同的 JVM 参数、甚至不同的build.gradle缓存。而命令行环境是纯净、可复现的,它强迫你去思考每一个变量。
我坚持用命令行开发已有七年,从最初为了省内存,到现在已成为一种本能。它让我写的每一行代码,都带着对底层机制的敬畏;让我做的每一次调试,都建立在坚实的事实之上。如果你今天开始尝试,不必一步到位,就从./gradlew assembleDebug和adb install这两个命令开始。当你第一次在终端里看到Success的输出,那种掌控感,是任何图形界面都无法给予的。