VS Code 写 Android,插件生态够用吗

VS Code 写 Android,插件生态够用吗

VS Code 写 Android,插件生态够用吗


VS Code 写 Android,插件生态够用吗


从一次 Gradle 同步崩溃说起


去年把主力开发机从 Intel Mac 换成 M3 MacBook Pro 之后,我做过一个实验:把 IntelliJ IDEA 卸载,只用 VS Code 写 Android 项目,看能撑多久。动机很简单,IDEA 在 Apple Silicon 上虽然能跑,但那个 JetBrains Runtime 的内存占用始终让我不舒服,开两个中大型项目就开始 swap,风扇起飞。VS Code 的内存 footprint 小得多,启动速度也快,如果插件生态能补上关键缺口,日常开发未必不能迁移。


实验持续了大概三个月,最后我装回了 IDEA,但不是全盘否定。这个过程让我对 VS Code 的 Android 插件生态有了很具体的认知:哪些真的能用,哪些只是 demo 级别,哪些坑会浪费你整个下午。这篇文章想把这段经历摊开,给同样想尝试的人一个真实的参考坐标。


崩溃发生在第三天。一个用了 Kotlin 2.0.0 的新项目,VS Code 里的 Gradle 插件死活同步失败,报错信息是 Could not open init generic class cache。同样的项目在 IDEA 里秒开。查了一下午,发现问题出在 Gradle for Java 这个微软官方插件的默认配置上——它调用的 Gradle wrapper 路径和 Android 项目特有的 gradle/wrapper/gradle-wrapper.properties 解析逻辑有冲突,导致 init script 被错误注入。解决方法是手动在 .vscode/settings.json 里指定 gradle.java.homegradle.nestedProjects,但文档里根本没提 Android 项目的特殊处理。这个插曲很典型:VS Code 的 Android 支持不是不能用,而是你需要比 IDEA 多知道很多东西,多踩很多文档没写的坑。


语言支持:Kotlin 插件的甜蜜与苦涩


写 Android 离不开 Kotlin,而 VS Code 的 Kotlin 支持核心只有一个选择:fwcd 的 Kotlin Language Server(GitHub: fwcd/kotlin-language-server)。这个插件在 Marketplace 上的安装量超过两百万,看起来是社区标准方案,但实际体验要拆开看。


语法高亮和基础补全做得不错。它能解析标准库的 API,对 Kotlin 的语法特性覆盖比较全,协程关键字、内联函数、reified 类型参数这些都能正确着色。对于纯 Kotlin 项目或者 Kotlin/JS 项目,这个插件基本够用。但一到 Android 项目,问题就开始冒头。


最痛的是 Android SDK 类的索引。Language Server 默认不会自动拉取 Android SDK 的源码和 API 文档,所以 android.widget.TextView 这种类名能补全出来,但跳转到定义时经常落到反编译的 stub 类,没有注释,没有参数说明。你需要手动配置 kotlin.languageServer.jvm.targetkotlin.sourceSets,让它知道 android.jar 在哪里。我当时的配置大概长这样:


{
  "kotlin.languageServer.jvm.target": "17",
  "kotlin.compiler.jvm.target": "17",
  "kotlin.sourceSets": {
    "main": {
      "kotlin": ["src/main/java", "src/main/kotlin"],
      "resources": ["src/main/res"]
    }
  }
}

即使这样,R.id.xxx 这种资源引用也经常解析失败,因为 Language Server 不理解 AAPT 生成的 R.java 结构。你写 findViewById(R.id.button) 时,类型推断会断掉,变成 View! 而不是具体的 Button,后续的链式调用补全也就废了。


另一个深坑是 Kotlin 版本兼容性。JetBrains 的 Kotlin 语言特性更新很快,2.0.0 引入的上下文参数(context parameters)预览、明确的后端模式选择这些新东西,Language Server 的跟进有显著延迟。我实验期间正好赶上 Kotlin 2.0.0 发布,IDEA 当天就支持了新语法高亮,VS Code 的插件等了三个星期才更新。这种延迟对于需要尝鲜新版本的开发者是致命的。


不过 fwcd 的插件有一个 IDEA 没有的优势:它对 Gradle Kotlin DSL 的支持更原生。IDEA 的 build.gradle.kts 编辑体验一直有点别扭,而 Language Server 因为直接解析 Kotlin AST,在脚本插件(plugins {} 块、版本目录引用)的补全上反而更流畅。如果你是个 build script 写得很多的人,这点会意外顺手。


Android 构建:Gradle 插件的权限与调试


Android 开发的核心循环是改代码、编译、装包、看日志。VS Code 里这个链条能跑通,但每一步都有摩擦。


微软官方的 Gradle for Java 插件(v3.13 之后版本)是构建任务的基础。它能识别 build.gradlebuild.gradle.kts,在侧边栏生成任务树,支持点击运行 assembleDebug 这类任务。但 Android Gradle Plugin 的 task 命名和依赖关系比纯 Java/Kotlin 项目复杂得多,这个插件的任务解析经常漏掉变体(variant)级别的 task。比如你有 debugrelease 两个 build type,又开了 productFlavors,任务树里可能只显示 assembleDebug,找不到 assembleDemoDebugassembleFullRelease,得手动写 tasks.json 配置。


更麻烦的是增量编译感知。Android Gradle Plugin 的增量编译逻辑很精细,哪些 task 需要重新跑、哪些可以跳过,依赖文件系统快照和 transform 缓存。Gradle for Java 插件的任务输出面板不会显示 AGP 的详细日志级别,你调 org.gradle.logging.level=debug 之后,输出淹没在几千行 Gradle 内部日志里,很难定位编译错误。IDEA 的 Build 工具窗口把 AGP 的编译错误做了结构化解析,点击直接跳转到源文件;VS Code 的错误面板只能显示 Gradle 原始输出,行号解析经常错位,尤其是涉及 Kotlin 编译器报错时。


我后来找到一个折中方案:用 Gradle 插件启动编译,但把详细输出重定向到文件,再用 Error Lens 插件(usernamehw.errorlens)把问题标在行内。Error Lens 本身是个通用插件,但它能解析 Kotlin 编译器的输出格式,把 e: file.kt:42:13 这种错误定位到具体位置。这个组合能用,但配置起来很烦,需要写正则匹配模式,而且和 Kotlin Language Server 的诊断信息会重复显示,满屏幕红色波浪线。


ADB 和日志查看是另一个断层。VS Code 没有内置的 Logcat 工具窗口,社区方案主要是两个:Appulate 的 Android 插件(appulate.file-and-folder-gallery,名字很奇怪但功能相关)和独立运行的 pidcat 之类的命令行工具。我试的是另一个更活跃的项目:Android iOS Emulator(DiemasMichiels.emulator,虽然名字带 iOS 但 Android 支持更好),它能列出连接的设备、启动模拟器,但 Logcat 集成很弱,只能开一个终端面板跑 adb logcat,没有过滤、没有着色、没有进程筛选。


实际工作中我退回了终端方案:用 `adb logcat -c && adb logcat grep "MyAppTag"` 这种原始命令,配合终端的搜索功能。对于需要频繁看日志的场景,这比在 VS Code 里折腾插件稳定得多。但这也意味着你失去了 IDEA 里点击堆栈跳转源码的能力,线上崩溃日志里的行号,得手动 `cmd+click` 或者搜文件名定位。

布局与资源:XML 编辑的荒野


Android 的 XML 资源文件是 VS Code 插件生态最薄弱的一环。IDEA 的布局编辑器、资源引用跳转、预览功能,在 VS Code 里完全没有等效替代。


Red Hat 的 XML 插件(redhat.vscode-xml)能给 AndroidManifest.xmlres/layout/*.xml 提供 schema 验证,但你需要手动配置 XML catalog,指向 Android SDK 里的 platforms/android-34/data/res/ 下的 XSD 文件。即使配好了,它也只能做基础的结构验证,不知道 android:id="@+id/button" 里的 ID 有没有在 Java/Kotlin 代码里定义,也不能像 IDEA 那样 Ctrl+BR.id.button 跳转到 XML 声明。


布局预览是完全缺失的。Compose 时代这个痛点稍微缓解,因为 Compose 预览可以用 Compose Compiler 的 @Preview 注解在设备或模拟器上运行,但传统 View 体系的 XML 布局,你在 VS Code 里只能盲写,然后编译安装看效果。我实验期间维护的一个老项目还在用 ConstraintLayout 写复杂界面,这个环节的效率损失非常明显,改一个 layout_constraintBottom_toBottomOf 的引用,可能要编译两次才能确认没写错。


资源引用的重构也是灾难。IDEA 里重命名一个 drawable 文件,所有引用它的 Java/Kotlin/XML 代码都会联动更新。VS Code 里没有任何插件能做到这个程度的跨语言重构。Kotlin Language Server 能重命名 Kotlin 符号,但 R.drawable.old_nameR.drawable.new_name 的变更,它感知不到。你只能全局搜索替换,风险自担。


我找到一个半吊子方案:用 Android Asset Studio 的命令行版本(romannurik/AndroidAssetStudio 的社区 fork)生成资源,然后用 VS Code 的多文件搜索做批量替换。但这和 IDE 的语义重构完全不是一回事,Rename 操作在 VS Code 里对 Android 资源基本不可用。


调试:能跑,但别期待太多


调试功能是我实验期间最大的惊喜,也是最大的失望来源。惊喜在于,VS Code 的 Java Debug 扩展(vscjava.vscode-java-debug)配合 Android 项目的配置,确实能打断点、单步、看变量。失望在于,这个"能跑"的状态很脆弱,配置对了能工作,配置错了调试器直接沉默崩溃。


核心问题是 Android 应用的进程模型。你的 APK 运行在设备或模拟器上的独立进程中,VS Code 的调试器需要通过 JDWP 协议 attach 到目标进程。但 Android 应用启动时不是立即开启 JDWP 端口的,你需要在 AndroidManifest.xml 里设 android:debuggable="true",并且在应用启动后执行 adb shell am set-debug-app -w --persistent com.example.app 这种命令等待调试器 attach。


VS Code 的 launch.json 配置需要手动指定 adb -s <device> shell run-as com.example.app ... 这种复杂命令,或者更常见的方案:用 Android 插件生成一个包装过的启动配置。我最终跑通的配置参考了 GitHub 上 kotlin-community-tools/vscode-android 这个非官方项目(已经归档,但配置还能用),大概结构是:


{
  "type": "android",
  "request": "launch",
  "name": "Launch Android App",
  "appSrcRoot": "${workspaceFolder}/app/src/main",
  "apkFile": "${workspaceFolder}/app/build/outputs/apk/debug/app-debug.apk",
  "adbPort": 5037
}

这个 android 类型不是 VS Code 内置的,需要额外安装插件。我试的是已经停更的 android-dev 插件,以及另一个更实验性的 vscode-android-dev 扩展。它们的问题在于,对 Android Gradle Plugin 8.x 的变体输出路径支持不好,经常找不到最新编译的 APK,或者 attach 到错误的进程 ID。


断点命中后的体验倒是还行。VS Code 的调试 UI 比 IDEA 更简洁,变量查看、调用栈、条件断点这些基础功能都有。但 Kotlin 的协程调试是盲区,IDEA 的 Coroutine Debugger 能展示挂起函数的调用图和协程状态,VS Code 里完全没有。你在 suspend fun 里打断点,只能看到当前的 continuation 对象,看不到协程在哪个 dispatcher 上运行、有没有被调度器挂起。对于重度使用协程的项目,这个缺失很致命。


还有一个隐蔽的坑:Kotlin 的 inline 函数和 reified 类型参数在调试时会"消失"。因为编译后内联展开,源代码行号和字节码的对应关系被打乱,VS Code 的调试器经常走进反编译的 stub 代码里,变量名变成 var1var2 这种编译器生成的名字。IDEA 的 Kotlin 调试器有特殊处理来还原这些名字,VS Code 没有。


代码质量:Detekt 和 Ktlint 的 CLI 化


静态分析工具在 VS Code 里的集成度普遍不如 IDEA,但能用命令行跑通的工具,配合 VS Code 的任务系统和问题面板,可以凑出接近的体验。


我项目里用的是 Detekt(GitHub: detekt/detekt),配置是 detekt.yml 放在根目录。VS Code 没有官方的 Detekt 插件,社区方案是 nomike 的 detekt-vscode(Marketplace 上叫 Detekt,安装量很小)。这个插件的功能很薄:读取 detekt.yml 配置,在保存时运行 detekt cli,把输出解析成 VS Code 的 diagnostic 格式。实际用下来,配置路径解析经常出问题,多模块项目的 config 块合并逻辑和命令行行为不一致,我最后弃用了插件,改在 tasks.json 里写了一个保存时触发的任务:


{
  "label": "detekt",
  "type": "shell",
  "command": "./gradlew detekt",
  "problemMatcher": {
    "pattern": {
      "regexp": "^(.*\\.kt):(\\d+):(\\d+):\\s+(.*)$",
      "file": 1,
      "line": 2,
      "column": 3,
      "message": 4
    }
  },
  "group": "build"
}

Ktlint 的情况类似。IDEA 的 ktlint 插件能在编辑时实时提示格式问题,并且有自动格式化快捷键。VS Code 的 ktlint 插件(pinterest-ktlint.vscode-ktlint,由 ktlint 官方维护)支持保存时自动格式化,但规则集的配置解析和 Gradle 插件版本有差异。我项目里用 ktlint-gradle 插件(JLLeitschuh/ktlint-gradle)做 CI 检查,本地 VS Code 的格式化结果和 CI 偶尔不一致,排查发现是 .editorconfig 里的 max_line_length 被两个工具链解析成了不同的值(一个含注释,一个不含)。最后统一改成显式配置才解决。


这些工具链的碎片化是 VS Code 生态的通病。IDEA 的插件体系是 JetBrains 统一维护的,版本兼容性有保证;VS Code 的插件来自不同作者,对同一个工具的配置解析可能各写各的,你需要自己当胶水。


版本控制与协作:Git 的优势区间


这是 VS Code 真正碾压 IDEA 的地方。内置的 Git 集成、GitLens 插件(eamodio.gitlens,免费基础版够用)、GitHub Pull Requests 插件(GitHub.vscode-pull-request-github)组成的体验,比 IDEA 的 VCS 工具窗口流畅得多。


GitLens 的 blame 行内标注、历史追溯、分支对比这些功能,在审查代码时效率很高。IDEA 的 Annotate 也能做 blame,但界面更重,默认不开启行内显示。GitHub PR 插件可以直接在 VS Code 里查看、评论、checkout PR 分支,对于开源项目贡献或者团队 Code Review,这个流程比 IDEA 里跳转到浏览器再跳回来顺畅。


但 Android 项目有个特殊场景:IDEA 的 .idea/ 目录和 VS Code 的 .vscode/ 目录都需要版本控制策略。团队里如果混合使用两种 IDE,.idea/ 里的 run configuration、code style 配置和 .vscode/ 里的 settings.jsonlaunch.json 会打架。我实验期间推了一个 .vscode/ 配置到仓库,后来团队里用 IDEA 的同事抱怨说 VS Code 的格式化配置覆盖了 .editorconfig 的预期行为。最后我们决定:.vscode/.idea/ 都不进版本控制,只保留 .editorconfigdetekt.yml 这种中性配置。


那些我试过但放弃的插件


实验期间安装又卸载的插件有一长串,值得提几个有代表性的。


Kotlin Explorer(mathiasfrohlich.kotlin-explorer):承诺提供 Kotlin 的 AST 查看和字节码预览,类似 IDEA 的 Tools > Kotlin > Show Kotlin Bytecode。但实际字节码输出是调用 kotlinc 命令行生成的,没有和项目依赖联动,Android 项目的类路径导不进去,显示的字节码缺少 Android SDK 类的引用解析,基本不可用。


Android XML 预览(joshuapaling.android-xml-preview):一个试图用 WebView 渲染 XML 布局的实验性插件,2019 年后停更。安装后会在命令面板加一个 "Android: Preview XML Layout",但只支持最基础的 LinearLayoutTextViewConstraintLayout 的约束属性完全忽略,渲染结果和实际设备差异巨大。


ADB Interface(vintharas.adb-interface):提供了一组 ADB 命令的快捷方式,比如截图、录屏、安装 APK。但每个命令都是简单包装 adb shell,没有错误处理,设备未连接时直接抛 uncaught exception,插件崩溃。后来我用回了自定义的 shell alias。


这些插件的共同问题是:作者往往是个人开发者,出于兴趣做 demo,没有持续维护的资源和动力。Android 开发工具链的变化速度很快,AGP 每年一个大版本,Android SDK 的 API 行为也在变,停更的插件迅速变成技术负债。


什么场景下 VS Code 真的能用


三个月实验结束,我总结了几条 VS Code 写 Android 的适用边界。


第一是纯 Kotlin 逻辑层开发。如果你的工作集中在业务逻辑的纯 Kotlin 模块(比如 domain 层、usecase 层、Repository 实现),不碰 XML 布局,不频繁调试多线程协程,VS Code 的 Kotlin 支持足够流畅。我后来把一些工具库的开发和单元测试工作流留在了 VS Code 里,因为启动快、内存轻,跑 ./gradlew test 的反馈循环很舒服。


第二是脚本和构建工具开发。Gradle Kotlin DSL 的编辑、版本目录(libs.versions.toml)的维护,VS Code 的体验不比 IDEA 差,甚至某些方面更顺手。我写过几个自定义 Gradle 插件,VS Code 里写 buildSrc 的代码感觉更轻量。


第三是跨平台项目的辅助编辑。Compose Multiplatform 项目同时有 Android、Desktop、iOS 目标,IDEA 的 Android Studio 和 Fleet 对 iOS 的支持还在追赶,VS Code 配合 Kotlin Multiplatform Mobile 插件(kotlinlang.vscode-kotlin,JetBrains 官方实验性插件)可以做一个"够用"的跨平台编辑环境。但这个插件本身也很早期,iOS 模拟器启动、Xcode 集成这些环节坑很多,另开一篇文章都讲不完。


绝对不适合的场景:需要频繁操作 XML 布局的 UI 开发、需要深度协程调试的异步逻辑、需要同时维护多个 build variant 的大型项目。这些场景 IDEA 的工具链深度是几年积累的结果,VS Code 的插件生态短期内追不上。


装回 IDEA 之后


最后说个具体的对比。我装回 IDEA 后打开的第一个项目是一个用了 Jetpack Compose 的模块化项目,十几个 feature 模块加 core 模块。IDEA 的 Project Structure 对话框让我瞬间找回了对依赖图的掌控感——VS Code 里没有等效工具,看模块依赖只能手动翻 settings.gradle.kts 和各个 build.gradle.kts。Compose Preview 的交互式刷新、Layout Inspector 的实时属性查看、Database Inspector 的 Room 数据库浏览,这些工具在 VS Code 里完全没有对应物。


但 VS Code 的实验不是浪费时间。它让我更清楚自己依赖了哪些 IDEA 的"魔法",也让我在 VS Code 里搭建了一套能跑通的轻量工作流,现在处理一些简单的 PR review、紧急修个纯逻辑 bug,我还是会开 VS Code,因为启动速度的差距是真实的。两个 IDE 同时装在机器里,根据任务切换,成了我现在的常态。


如果你也想尝试,建议不要一上来就卸载 IDEA。从一个小模块、一个纯 Kotlin 库开始,把 VS Code 当成辅助工具而不是主力环境,慢慢摸清插件的边界。这样当某个插件突然崩溃或者遇到无解的 bug 时,你有退路,也不会对整个生态产生不切实际的期待。


VS Code 的 Android 插件生态,用是可以用的,但"够用"的标准因人而异。对工具链有深度定制需求的人,这个生态还太薄;对愿意自己动手配置、能接受命令行补全缺失环节的人,它能提供一个更轻量的替代选项。关键是知道自己的场景落在哪个区间,不做一厢情愿的迁移。

Charles 和 Proxyman 的 HTTPS 解密配置教程 2026-07-17

评论区