6、应用管理(下):启动、强杀与查底牌
上一节我们把应用的安装、卸载和清除数据聊透了。今天咱们继续往下挖,聊聊怎么用 ADB 命令去操控一个应用的“生死”和“底细”。说白了,就是三个核心动作:启动 Activity、强制停止、查看应用详情。
这三个命令,我几乎每天都会用到。调试的时候,启动一个特定的 Activity 能帮你跳过一堆启动页;遇到应用卡死,强杀比点“强制停止”快得多;而 dumpsys package 简直就是应用的“体检报告”,什么权限、组件、版本号,一目了然。
好,咱们一个一个来。
6.1 启动 Activity:adb shell am start
这个命令,说白了就是“用命令行打开一个界面”。你平时点图标启动应用,本质上也是启动了一个 Activity。但用 ADB 启动,你可以指定启动哪个 Activity,甚至可以带上参数。
基本用法长这样:
adb shell am start -n 包名/Activity全路径
举个例子,我想直接打开微信的聊天列表:
adb shell am start -n com.tencent.mm/.ui.LauncherUI
这里 -n 参数后面跟的就是“包名/Activity名”。注意 Activity 名前面有个点,表示是包名下的相对路径。如果你不知道 Activity 的全名,可以用 dumpsys package 去查,咱们后面会讲。
-n,改用 -p 参数:
adb shell am start -p com.tencent.mm
这样系统会自动找到该包的主 Activity 并启动。我个人习惯用 -p,省得记 Activity 名。
有时候你需要给 Activity 传数据,比如打开一个网页:
adb shell am start -a android.intent.action.VIEW -d "https://www.example.com"
这里 -a 指定 Action,-d 指定数据 URI。这招在调试 Deep Link 时特别有用。我记得有一次测试一个支付页面的跳转,就是用这个命令直接拉起目标页面,省去了在 App 里点来点去的麻烦。
再复杂一点,你还可以加 --es 传字符串,--ei 传整数。比如:
adb shell am start -n com.example.app/.MainActivity --es "key" "value" --ei "count" 10
嗯,这里要注意:参数名和值之间用空格隔开,不要加等号。
6.2 强制停止:adb shell am force-stop
应用卡死了?后台服务抽风了?别慌,用这个命令直接“物理断电”。
adb shell am force-stop 包名
比如:
adb shell am force-stop com.example.app
这个命令的效果,等同于你在系统设置里找到应用,然后点“强制停止”。它会杀掉该应用的所有进程,包括后台服务、广播接收器等等。而且,它不会像 kill 命令那样只杀一个进程,而是把整个应用的所有进程都干掉。
我曾经在调试一个推送服务时,发现推送总是收不到。查了半天,原来是我之前用 force-stop 把应用杀了,而推送服务需要在后台运行。后来我改用 adb shell am kill 只杀前台进程,才解决问题。所以,force-stop 是核武器,别乱用。
另外,这个命令不需要 root 权限,普通用户就能执行。但要注意,它只能停止你调试的应用(即 debuggable 的应用),或者系统应用。对于普通第三方应用,你可能没有权限去强杀。
6.3 查看应用详情:adb shell dumpsys package
这个命令,是我认为 ADB 里最强大的命令之一。它能把一个应用的所有信息都 dump 出来,简直就是应用的“户口本”。
基本用法:
adb shell dumpsys package 包名
比如:
adb shell dumpsys package com.example.app
输出内容会非常长,包含几十个字段。我挑几个最常用的给你说说:
| 字段 | 说明 | 示例 |
|---|---|---|
versionName |
应用的版本号(给用户看的) | 2.3.1 |
versionCode |
应用的版本号(给系统看的,整数) | 231 |
firstInstallTime |
首次安装时间 | 2024-01-15 10:30:00 |
lastUpdateTime |
最近更新时间 | 2024-03-20 14:22:00 |
signatures |
应用的签名信息(用于校验包是否被篡改) | [B@1a2b3c4d |
requestedPermissions |
应用声明的所有权限 | android.permission.CAMERA |
activities |
应用所有的 Activity 列表 | .MainActivity, .SettingsActivity |
你可能会问:这么多信息,我怎么快速找到我想要的?
我的习惯是,用 grep 过滤。比如我只想看版本信息:
adb shell dumpsys package com.example.app | grep -E "versionName|versionCode"
或者只看权限:
adb shell dumpsys package com.example.app | grep "permission"
嗯,这里有个坑:dumpsys package 的输出里,权限列表是分两块的——requestedPermissions(声明的权限)和 grantedPermissions(已授予的权限)。有时候你明明在清单里写了权限,但系统没给,那就要看 grantedPermissions 里有没有。我曾经遇到过一个问题:应用在 Android 12 上闪退,查了半天发现是 BLUETOOTH_SCAN 权限虽然声明了,但没动态申请,导致 grantedPermissions 里没有它。用 dumpsys package 一眼就发现了。
另外,如果你想看应用的所有 Activity 列表(方便前面 am start 用),可以这样:
adb shell dumpsys package com.example.app | grep -A 100 "Activity Resolver Table"
或者更直接:
adb shell dumpsys package com.example.app | grep "ActivityInfo"
这样就能拿到所有 Activity 的全路径了。
好了,这三个命令你掌握了吗?启动 Activity 让你能精准打开某个界面;强制停止是应急用的“大杀器”;而 dumpsys package 则是你排查问题的“照妖镜”。
我个人建议,你可以在自己的测试机上多试试。比如先 dumpsys package 查到一个 Activity 名,然后用 am start 启动它,最后再用 force-stop 关掉。走一遍流程,印象会深很多。
am start 启动它的一个非公开 Activity,结果直接崩溃。后来发现那个 Activity 需要特定的权限,而我的调试机没有。所以,启动前最好先用 dumpsys package 看看它的 exported 属性——只有 exported=true 的 Activity 才能被外部启动。
嗯,今天就到这里。记住,命令是死的,人是活的。多练、多试,你就能找到最适合自己的用法。