ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

adb shell appops 详解:Android 权限与后台管控命令实战

adb shell appops 详解:Android 权限与后台管控命令实战 1. 先搞清楚 appops 到底管什么adb shell appops这套东西我最早是在给测试机造权限异常场景时撞上的。当时产品提了个需求验证 App 在用户明明点了同意、系统层面却拿不到数据的情况下会怎么表现比如定位一直转圈、通讯录返回空列表。改代码当然能测但每验证一条分支就发一次包效率低得让人抓狂。后来发现adb shell appops能直接在设备侧动手脚一行命令就能把应用打成权限已授予但实际被掐断的状态从那以后它就成了我调试箱里常驻的家伙。这篇文章把 appops 的命令语法、op 名称、模式语义、踩坑点全部摊开讲一遍。适合三类人看做 Android 测试的同学、负责一批设备日常管控的人、以及喜欢折腾自己手机的玩家。不需要你会写 Android 代码只要能在电脑上敲命令、能连上 adb就能把下面的内容直接用起来。1.1 权限是门禁卡appops 是保安很多人第一次看到appops会懵权限管理不是有pm grant、pm revoke吗为什么还要多一层这里得把概念掰开。Android 的运行时权限CAMERA、ACCESS_FINE_LOCATION这些本质上是一张门禁卡——它记录的是用户有没有把这个权限发给这个应用。应用启动时调用checkSelfPermission系统查的就是这张卡。而 appopsApplication Operations是站在门口的那个保安它管的是这次具体调用到底放不放行。门禁卡和保安是两套独立的账本可以出现卡是真的、保安拦着你不让进的情况。我在设备上做过最直观的验证用pm grant给某个应用授予定位权限checkSelfPermission返回GRANTED应用界面上权限开关也是打开状态然后执行appops set 包名 COARSE_LOCATION ignore应用再去请求定位返回的是空结果而权限状态依旧是已授予。应用根本不知道发生了什么它只知道用户同意了但系统没给我数据。这个错位关系是理解 appops 的全部钥匙。往下所有命令、所有模式都要围绕权限账本和放行账本这两条线来想。底层实现上系统里维护着一份 appops 状态表记录每个 UID或包名在每个 op 上的模式以及最近一次的允许时间、拒绝时间、持续时长。这套数据由系统的 AppOpsService 统一管理adb shell appops就是给它发的遥控指令。老一点的系统里这份状态落在/data/system/appops.xml现在一般在/data/system/下的运行时权限相关配置文件里。这一点很重要它解释了两件事一是重启之后你改的状态通常还在二是系统自己也会往这份文件里写东西你手动改的值有可能被覆盖。1.2 除了权限appops 还管一堆不是权限的事如果你以为 appops 只是权限的另一个开关那就低估它了。它管的操作比运行时权限多得多很多根本不走用户授权弹窗属于系统自己就能定的规矩。举几类比较典型的一是后台行为。RUN_ANY_IN_BACKGROUND控制应用能不能在后台跑WAKE_LOCK控制能不能持有唤醒锁START_FOREGROUND控制能不能启动前台服务BOOT_COMPLETED控制开机自启动。这些东西在系统设置里你很难找到一个对应的开关但对续航的影响比权限大得多。国产 ROM 里那个禁止后台运行底层操作的就是这套 op。二是交互与展示。POST_NOTIFICATION管通知SYSTEM_ALERT_WINDOW管悬浮窗VIBRATE管震动TOAST_WINDOW管 Toast 显示。你在设置里关掉某个应用的通知系统做的其实也是改 appops 状态。三是数据读取。READ_CLIPBOARD、WRITE_CLIPBOARD、READ_CONTACTS、READ_CALL_LOG、GET_USAGE_STATS、PROJECT_MEDIA这些各有各的用途。其中READ_CLIPBOARD特别值得注意它能在后台限制应用偷读剪贴板内容且不需要改任何权限。四是特殊授权。GET_USAGE_STATS使用情况访问、MANAGE_EXTERNAL_STORAGE所有文件访问、MOCK_LOCATION模拟位置这些正常路径都要跳转到系统设置页面让用户手动点用 appops 可以一步到位。覆盖面广意味着它的破坏力也大。我见过有人手抖把某个社交应用的POST_NOTIFICATION设成 deny然后花了半小时找为什么消息不提醒。改之前先想清楚影响面这是最基本的要求。1.3 和 pm grant / revoke 的关键差异既然都是改权限状态那appops set ... deny和pm revoke到底差在哪这个区别决定了你在什么场景该用哪个值得单独讲清楚。pm revoke改的是权限账本。执行之后checkSelfPermission会返回DENIED应用下次启动时通常会走检测到权限缺失 → 弹窗请求的逻辑。也就是说应用知道自己被撤销了权限。appops set ... deny/ignore改的是放行账本。权限账本不动checkSelfPermission依旧返回GRANTED应用以为自己有权限一路走到实际调用系统服务时被拦下来。这两种状态对应的是完全不同的用户故事。pm revoke模拟的是用户从来没授权应用应该走引导授权流程appops 模拟的是用户授权了但系统不给你数据应用应该走降级、兜底、超时处理流程。后一种情况在真实世界里大量存在——国产 ROM 的隐私保护、企业设备管控、家长管控都属于这一类但很多 App 的开发者从没测过。所以我的建议很明确测缺权限用 pm revoke测系统拦截用 appops。两者的报错表现也不一样deny一般会抛安全异常或者直接返回失败ignore则是安安静静给你返回空数据应用如果没做空值判断很容易崩在NullPointerException上。我在测试里最喜欢用ignore因为它能把应用最脆弱的那一面逼出来。2. 命令速通从查询到改写的完整语法2.1 先把设备连上环境检查清单命令再好连不上设备都是白搭。开工前的检查顺序我固定这么走第一步确认电脑上 adb 能用。adb version能打印出平台工具版本就行不需要装完整的开发环境。老系统Android 5 以下建议用 1.0.39 以前的版本新设备用最新的平台工具这个坑踩过好几次——新 adb 连老机器偶尔会握手失败。第二步adb devices看设备列表。正常应该是这样$ adb devices List of devices attached 2A3F5E8C1B00 device如果显示unauthorized说明手机上还没确认这台电脑的授权。处理办法按顺序试手机上重新插拔 USB、在开发者选项里点撤销 USB 调试授权再重新连接、检查电脑上~/.android/adbkey是否存在删掉后重启 adb 服务会重新生成密钥。如果是offline先adb kill-server再adb start-server。第三步确认目标设备只有一台或者用-s 序列号指定。多设备环境下最容易被忽略的就是命令悄悄打到了另一台机器上改完发现没效果其实改到隔壁去了。第四步判断目标应用所在用户。绝大多数场景是--user 0也就是机主。如果手机开了多用户、或者有工作资料分身包名会在不同用户下各有一份运行状态改错用户等于没改。注意部分厂商 ROM 默认关闭了 USB 调试的写入能力尤其是开发者选项里的 USB 调试安全设置这一项不开的话 appops 修改会被拒绝。碰到莫名的失败先去确认这个开关。2.2 四板斧get、query-op、set、resetappops 子命令常用的就四个记住它们就能覆盖九成场景。查一个应用的全部 op 状态adb shell appops get com.example.app输出是一长串格式类似COARSE_LOCATION: modeignore; time1h12m3s456ms ago FINE_LOCATION: modeignore CAMERA: modeallow RECORD_AUDIO: modeallow WAKE_LOCK: modeallow; time18m2s11ms ago RUN_ANY_IN_BACKGROUND: modedenymode后面的就是当前模式。带time的是最近一次被使用的相对时间rejectTime表示最近一次被拒绝。没有列出来的 op 就是默认模式这一点要记住别以为没显示就是出问题了。查单个 opadb shell appops get com.example.app CAMERA反查某个 op 下哪些应用被设成了某个模式。adb shell appops query-op CAMERA ignore这条命令在排查到底是谁把相机搞坏了的时候特别有用——直接列出所有被设成忽略的应用一个个试就能定位。写模式adb shell appops set com.example.app CAMERA ignore恢复默认adb shell appops set com.example.app CAMERA defaultdefault会把这条记录删掉让系统按它自己的逻辑决定。比手动设回allow更干净因为你并不知道系统原本给它的是allow还是foreground。整体重置adb shell appops reset com.example.app # 重置单个应用 adb shell appops reset --all # 重置所有应用慎用Android 8 之后也可以写成adb shell cmd appops ...两者等价我个人习惯用前者短一点。2.3 模式词表要背下来尤其是 ignore 和 deny 的区别模式是这个工具里最容易用错的部分我把它整理成一张表模式含义应用看到的现象适用场景allow放行正常拿到数据恢复被误改的状态deny拒绝通常抛异常或明确失败模拟用户拒绝ignore静默忽略返回空数据、不报错模拟系统层拦截default回到系统默认由系统逻辑决定清理手动改动foreground仅前台放行后台拿不到前台正常模拟新版本系统的后台限制ask每次询问弹系统确认框部分敏感 op 支持deny和ignore的区别是这张表的核心。我打个比方deny相当于保安直接告诉你你不能进ignore相当于保安让你进门但里面什么东西都搬不出来。前者会触发应用的异常处理逻辑后者会触发应用的数据为空逻辑。实测下来很多应用对异常做了处理对空数据反而没做。用ignore测出来的崩溃往往比用deny测出来的更真实、更有价值——因为线上用户真的会遇到这种情况。foreground这个模式是 Android 10 之后才出现的语义是应用在前台时可以访问退到后台就掐断。用它可以精准复现新版系统对后台定位、后台相机的限制比粗暴地设成ignore更贴近真实。2.4 --uid 和 --user 的适用场景两个参数长得很像作用完全不同我见过不少人混着用。--user指的是用户空间。--user 0是机主--user 10可能是工作资料或者分身应用。多用户设备上不加这个参数命令默认作用在 0 号用户。--uid指的是用 UID 而不是包名来定位目标。写法是adb shell appops set --uid 10123 WAKE_LOCK deny什么时候用 UID答案是当一个 UID 下挂了多个包名的时候。共享 UID 的应用android:sharedUserId老应用常见、以及被系统合并计算的多个进程用包名改只能改其中一个用 UID 改能覆盖全部。反过来如果只想针对单个应用下手用包名更安全不会误伤同 UID 的兄弟应用。查 UID 的办法adb shell dumpsys package com.example.app | grep userId另外还有--attribution参数Android 11 之后用于区分同一个应用内不同归因标签的访问。这个属于细粒度场景一般用不到知道有这回事就行。提示appops get默认输出的是包名维度。想看 UID 维度的完整状态用adb shell dumpsys appops加管道过滤能看到系统内部更原始的数据。3. 常用 op 清单与实战场景矩阵3.1 隐私类定位、相机、麦克风、剪贴板隐私类 op 是使用频率最高的一类因为它们直接对应到用户能感知到的功能。定位相关的有两个COARSE_LOCATION粗略定位和FINE_LOCATION精确定位。两个都要改只改一个经常不生效因为应用会根据实际拿到的精度去判断。我一般这么写adb shell appops set com.example.app COARSE_LOCATION ignore adb shell appops set com.example.app FINE_LOCATION ignore相机是CAMERA麦克风是RECORD_AUDIO。这两个设成ignore之后应用拿到的通常是一段空数据或者打开失败而且不会有权限弹窗——这就是它和 revoke 最大的区别。剪贴板是两个比较特殊的 opREAD_CLIPBOARD和WRITE_CLIPBOARD。Android 10 之后系统本身就限制了后台读剪贴板但 appops 可以做到更彻底。我测试过把某个常驻应用设成READ_CLIPBOARD deny它再也没法在后台悄悄读取我复制的验证码了。这个用法比装第三方管控软件干净得多。联系方式类的是READ_CONTACTS、WRITE_CONTACTS、READ_CALL_LOG、WRITE_CALL_LOG。这几个设成ignore之后应用拿到的是空游标不会抛异常非常容易让没做判空的应用直接崩掉。身体活动识别是ACTIVITY_RECOGNITION管的是计步、运动检测。传感器相关的还有BODY_SENSORS。这些在测试健康类应用时很有用。3.2 省电类后台、唤醒锁、前台服务、开机自启这一类是我个人用得最多的因为它对续航的影响立竿见影而且不需要 root也不需要装任何额外工具。RUN_ANY_IN_BACKGROUND是后台运行的总闸。设成deny之后应用退到后台基本就被冻住了。注意不同版本上这个 op 的名字可能有差异老版本叫RUN_IN_BACKGROUND如果一条命令报未知 op换另一个名字试。保险做法是先appops get 包名看看设备实际认识哪个名字。WAKE_LOCK管的是能不能持有唤醒锁。有些应用在后台一直申请唤醒锁导致手机进了口袋还在耗电。设成ignore之后它申请唤醒锁的请求会被静默忽略应用不会崩但也没法把 CPU 从休眠里叫醒。START_FOREGROUND管前台服务启动。设成deny之后应用没法把自己变成前台服务也就没法长期驻留。这一条对那些常驻通知栏的应用特别有效。缺点是有些应用在startForeground失败后会有兜底逻辑可能会反复重试反而更耗电所以改完要观察一段时间。BOOT_COMPLETED管开机自启。设成deny之后应用收不到开机完成广播自然也就起不来了。这是最省电的一刀代价是应用可能在你手动打开它之前完全没有推送。一组我常用的省电组合PKGcom.example.heavy adb shell appops set $PKG RUN_ANY_IN_BACKGROUND deny adb shell appops set $PKG WAKE_LOCK deny adb shell appops set $PKG BOOT_COMPLETED deny3.3 体验类通知、悬浮窗、震动、Toast这一类改动的是看得见摸得着的部分效果最直接。POST_NOTIFICATION控制通知。Android 13 把通知做成了运行时权限但在这个版本之前appops 里的这个 op 一样可以控制。设成deny之后应用发不出任何通知栏消息。SYSTEM_ALERT_WINDOW控制悬浮窗。这类权限正常需要在系统设置里单独授权用 appops 可以直接关掉。测试悬浮窗类应用的时候非常方便不用来回跳设置页。VIBRATE控制震动。TOAST_WINDOW控制 Toast 显示。VIBRATE设成deny之后应用调震动接口会静默失败不会影响其他逻辑适合用来做安静模式的强制体验测试。PROJECT_MEDIA和TAKE_AUDIO_FOCUS属于媒体类。前者管屏幕投射后者管音频焦点。给视频类应用做互斥测试时会用到。3.4 一张表看清组合配置把上面几类整理成场景化的组合方便直接抄目标需要设置的 op建议模式彻底静音不打扰POST_NOTIFICATION、VIBRATE、TOAST_WINDOWdeny后台零耗电RUN_ANY_IN_BACKGROUND、WAKE_LOCK、START_FOREGROUND、BOOT_COMPLETEDdeny 或 ignore隐私保护COARSE_LOCATION、FINE_LOCATION、CAMERA、RECORD_AUDIO、READ_CONTACTSignore屏幕整洁SYSTEM_ALERT_WINDOW、TOAST_WINDOWdeny测试后台受限COARSE_LOCATION、FINE_LOCATION、CAMERAforeground恢复全部默认对该应用执行 reset-设置完记得用appops get 包名复查一遍尤其是批量脚本跑完之后。我踩过一次坑脚本里有一行包名拼错了前面几条改成功、后面几条静默失败因为报错信息被吞掉了直到发现耗电没降才查出来。4. 动手实操三条可以照抄的完整流程4.1 场景一把某个 App 关进静音笼子背景是我家里那台备用机装了一个购物应用每天推送七八条消息还会在后台跑定位。我不想卸载也不想开系统那一堆设置项就用 appops 一次性处理掉。第一步确认包名和 UIDadb shell pm list packages | grep -i shop拿到包名假设是com.example.shop。第二步先备份当前状态这个习惯一定要养成adb shell appops get com.example.shop shop-appops-backup.txt第三步批量设置PKGcom.example.shop adb shell appops set $PKG POST_NOTIFICATION deny adb shell appops set $PKG RUN_ANY_IN_BACKGROUND deny adb shell appops set $PKG WAKE_LOCK ignore adb shell appops set $PKG COARSE_LOCATION ignore adb shell appops set $PKG FINE_LOCATION ignore adb shell appops set $PKG SYSTEM_ALERT_WINDOW deny第四步复查adb shell appops get com.example.shop | grep -E m(odedeny|odeignore)实测下来改完之后应用还能正常打开、能浏览商品、能下单只是收不到推送、拿不到位置、后台不耗电了。这正是我想要的效果——功能可用打扰为零。出问题想恢复的时候对着备份文件一条条设回default就行或者直接adb shell appops reset com.example.shop。所以备份这一步别省我吃过不备份的亏。4.2 场景二造一个权限已授予但拿不到数据的测试环境这是我认为 appops 最有价值的用法前面提过它的原理这里讲具体操作。目标是验证 App 在定位权限已授予、但系统返回空结果时的表现。操作只有一条adb shell appops set com.example.app FINE_LOCATION ignore adb shell appops set com.example.app COARSE_LOCATION ignore然后打开应用进入依赖定位的功能页面。前提是不要先撤销权限一定是用pm grant或者正常弹窗把权限给到位否则测的就是另一条分支了。验证权限状态adb shell dumpsys package com.example.app | grep -A2 ACCESS_FINE_LOCATION看到grantedtrue就说明权限账本是对的。接下来打开应用的相应界面观察三件事它有没有做超时处理、有没有做空数据判断、会不会直接崩。我测过的应用里大约三成会一直转圈直到超时两成会白屏没有提示剩下五成里还有一部分能正确给出定位失败请重试的提示。这个比例就是这条命令的价值所在。同样的思路可以套到通讯录、相机、剪贴板。尤其是相机把CAMERA设成ignore之后很多应用打开相机预览时会拿到黑屏然后又没有异常分支直接卡在那里。还有一种进阶玩法用foreground模式复现新版系统的后台限制。adb shell appops set com.example.app FINE_LOCATION foreground应用在前台时定位正常退到后台就断。这个状态在真机上是系统自动施加的用命令可以随时切换非常适合做对比测试。4.3 场景三用 shell 脚本批量管理设备多了之后一条条敲命令不现实。我写了两个脚本一个用来批量关闭一个用来批量恢复放在电脑上跑注意是在电脑的 bash 里跑不是在adb shell里面。批量关闭脚本#!/bin/bash PKG$1 USER_ID0 OPSPOST_NOTIFICATION RUN_ANY_IN_BACKGROUND WAKE_LOCK \ START_FOREGROUND BOOT_COMPLETED SYSTEM_ALERT_WINDOW if [ -z $PKG ]; then echo 用法: $0 包名 exit 1 fi for op in $OPS; do if adb shell appops set --user $USER_ID $PKG $op deny 2/dev/null; then echo [OK] $op - deny else echo [SKIP] $op 不支持或权限不足 fi done这里有几个细节值得说。2/dev/null是为了把设备返回的报错吞掉用退出码判断成败比解析输出文本稳定。用if而不是是因为要让失败的那一条继续往下走——不同设备支持的 op 集合不完全一样遇到不认识的 op 直接跳过就好不要中断整个流程。批量恢复脚本更简单#!/bin/bash PKG$1 adb shell appops reset --user 0 $PKG adb shell appops get $PKG | head -5如果你要处理的是/data/adb/modules这类模块目录下的应用脚本里的包名需要单独确认模块应用有可能不在标准包名列表里用pm list packages -f才能看到完整路径。注意脚本里不要用adb shell里面的for循环语法去套这套命令。在电脑上执行和在设备上执行命令前缀完全不同混着写会得到一堆not found。这是我最早踩的坑之一分享出来省你半小时。5. 踩坑与排查记录5.1 改了不生效八成是被系统写回去了最让人头大的一种情况是命令执行成功、appops get也显示modeignore但应用一跑起来数据还是照样能拿到。原因通常是这条 op 跟运行时权限绑定了。当应用重新走一次权限请求流程、用户点了同意之后系统会自动把对应的 op 写回allow你的手动修改就被覆盖了。这是系统的正常行为不是 bug。判断方法很简单改完之后先查一次打开应用操作一轮再查一次。如果模式变了就说明被写回去了。这时候有两个选择一是改用pm revoke走权限缺失那条路二是换一批不受权限流程影响的 op比如WAKE_LOCK、RUN_ANY_IN_BACKGROUND、BOOT_COMPLETED这些不和权限账本联动改完就是改完了。还有一种被写回的情况来自厂商的权限管理模块。国产 ROM 一般会有一层自己的管控逻辑它会定期扫描并覆盖 appops 状态。表现是改完之后过几十分钟自己变回去了。碰到这种要么关掉厂商自带的那个管理开关要么就别在这台设备上做长期修改。5.2 SecurityException 与 root 的边界不是所有 op 都能用普通 adb shell 改。系统对MANAGE_APP_OPS_MODES这个能力有权限检查shell用户uid 2000能改的只是一部分。改到受保护的那批 op 时你会看到类似这样的报错$ adb shell appops set com.example.app WRITE_SETTINGS allow java.lang.SecurityException: uid 2000 does not have android.permission.MANAGE_APP_OPS_MODES解决办法有两条路。第一条是换用等价的、权限要求更低的 op 组合很多时候效果类似比如不给GET_USAGE_STATS而是绕开。第二条就是走 rootadb shell su -c appops set com.example.app WRITE_SETTINGS allow具体哪些 op 属于受保护范围不同版本、不同厂商的做法不一致没有一份通用清单。我的做法是先试报 SecurityException 就换路不在这上面纠结太久。测稳定性问题和续航问题基本用不到 root涉及特殊授权才需要。5.3 adb 连不上时的排查顺序appops 用不了九成不是 appops 的问题是 adb 没连上。我固定按这个顺序排查adb devices看状态unauthorized就按 2.1 节的办法处理。换一根数据线。这听起来很蠢但换线解决问题的比例高得惊人尤其是那种只能充电不能传数据的线。换 USB 口优先插主板直出的口不要用前面板或者扩展坞。adb kill-server adb start-server重启服务。检查开发者选项里的USB 调试是否真的开着有些系统更新之后会自己关掉。无线调试路径下确认配对码和端口没填错。如果目标是模拟器环境需要确认模拟器自身的 adb 端口和系统 adb 版本是否冲突。常见的做法是统一使用同一份平台工具或者让模拟器暴露到标准端口 5555 再连接。5.4 常见问题速查表现象可能原因处理方向报未知 op名称在系统上不一致先appops get看设备支持的名字改了不生效被权限授予流程覆盖改完再查一次或换不联动的 op改完一段时间自己变回厂商管控模块覆盖关闭厂商权限管理或改用 revokeSecurityExceptionop 受保护shell 权限不足换等价 op 或走 root应用崩溃没做空数据判断这说明问题找对了可复现给开发多设备改错机器未指定序列号加-s 序列号重启后状态丢失部分 op 不持久化写进开机脚本重新应用应用完全打不开改到了启动必需的 op用备份文件逐条恢复提示改之前先跑一遍adb shell appops get 包名 backup.txt这个动作花不了十秒钟但能省掉后面半小时的手忙脚乱。6. 我很在意的几条使用边界6.1 厂商 ROM 与版本差异这一块必须提前打预防针appops 的行为在不同系统上差异明显我总结出三条规律。第一条op 名称会变。同一个功能老版本可能叫RUN_IN_BACKGROUND新版本叫RUN_ANY_IN_BACKGROUND有些 op 在某个版本里干脆被合并掉了。所以看到未知 op别慌先appops get 包名把设备实际认识的名称捞出来照着改。第二条默认模式会变。同一个 op在 A 系统上默认是allow在 B 系统上默认是foreground。这就是为什么恢复的时候要用default而不是手动设回allow——你手动设的值未必是系统原本的值。第三条厂商会加戏。国产 ROM 普遍有一层自己的权限和后台管控逻辑有时和 appops 叠加有时直接覆盖。遇到怎么改都不生效的情况先去系统的应用管理里看看有没有后台管理自启动管理这类选项把厂商的那层关掉再试。版本方面Android 10 之后foreground模式才普遍可用Android 11 引入了归因标签Android 12 对前台服务启动做了额外约束Android 13 把通知变成了运行时权限。跨版本做同一套操作的时候把这些差异记在脚本注释里下次就不用重新踩一遍。6.2 自己的几条使用习惯折腾这么久我形成了几个固定习惯分享出来供参考。第一永远先备份。一条appops get重定向到文件成本几乎为零。有一次我把一个输入法应用的某个 op 改掉导致它无法正常调起而我又忘了改之前是什么状态最后只能卸载重装白白丢了一堆自造词。第二一次只改一条观察五分钟。批量脚本用起来爽但出问题时排查成本高。调试阶段我都是单条改、单条验确认没问题了再写进批量脚本。第三把测试环境写进代码注释。我会在测试用例里标注本用例需要在 FINE_LOCATION 为 ignore 的环境下执行这样别人接手的时候不会一脸茫然地以为是自己代码写错了。第四不拿主力机练手。appops 的某些设置会影响到系统组件的正常行为尤其是改到系统应用的时候。备用机或者模拟器上折腾出问题直接重置成本最低。第五改完记得收尾。做测试留下的ignore状态如果忘了恢复下次遇到问题时你会怀疑人生。我现在固定流程是测完立刻执行 reset并用appops get确认列表干净。这个习惯帮我省掉了不止一次明明代码没问题为什么跑不通的困惑。这类底层命令的价值不在于它能做多炫的事而在于它让你能精确地控制变量。把一个权限、一个后台开关拆成可单独调节的参数很多原本要靠猜的问题就变成了可复现、可定位、可验证的工程问题。这大概就是我愿意在它上面花时间的原因。
返回列表