OpenHarmony 录屏免弹窗踩坑记:从 CUSTOM_SCREEN_RECORDING 到 EXEMPT_CAPTURE_SCREEN_AUTHORIZE
环境:OpenHarmony 6.1.0.31(API 23)定制系统 · root 开发板 · ArkTS AVScreenCapture 录屏写文件
结论先行:只需要在 module.json5 里声明ohos.permission.EXEMPT_CAPTURE_SCREEN_AUTHORIZE,重装即可免弹窗。设备侧任何文件都不用改。
一、背景
基于 AVScreenCapture 做录屏到文件的功能,调用 start() 时系统必弹一个隐私确认框:
录屏投屏管理
“将录制/投射您屏幕上显示的内容和系统声音。请注意保护个人敏感信息,如密码、付款信息、照片、录像、聊天记录等。”
[不允许] [允许]
每次录屏都要点一次,产品上希望去掉。这个弹窗由系统服务弹出,应用侧没有任何 API 可以隐藏或拦截它,唯一的路是让系统认为你"有资格跳过"。
二、弹窗的判定逻辑(源码)
弹窗逻辑在 multimedia_player_framework 的 services/services/screen_capture/server/screen_capture_server.cpp,启动录屏时的判定链:
// StartScreenCaptureInner()
isScreenCaptureAuthority_ = CheckPrivacyWindowSkipPermission();
// ↑ 检查 ohos.permission.EXEMPT_CAPTURE_SCREEN_AUTHORIZE
if (!isScreenCaptureAuthority_ && IsUserPrivacyAuthorityNeeded()) { // root 进程免
RequestUserPrivacyAuthority();
// └─ IsSkipPrivacyWindow() = 是系统录屏器(sysparam配置的包名)
// || CheckCustScrRecPermission()
// ↑ 检查 ohos.permission.CUSTOM_SCREEN_RECORDING
// 都不满足 → StartPrivacyWindow() → 弹窗,等用户点"允许"
}
也就是说有三条正规跳过通道:
- 持有
ohos.permission.EXEMPT_CAPTURE_SCREEN_AUTHORIZE(挡在最外层) - 持有
ohos.permission.CUSTOM_SCREEN_RECORDING(挡在弹窗流程里) - 应用包名恰好等于系统参数
const.multimedia.screencapture.screenrecorderbundlename(伪装成系统录屏器,副作用多,不推荐)
另外 IsUserPrivacyAuthorityNeeded() 里 root 进程直接放行,但应用进程不是 root,用不上。
三、两个权限的对比
| EXEMPT_CAPTURE_SCREEN_AUTHORIZE | CUSTOM_SCREEN_RECORDING | |
|---|---|---|
| 设计对象 | 系统内部应用的"豁免"通道 | 三方应用的官方免弹窗通道(受限开放权限) |
| 权限级别 | system_core | system_basic |
| 授权方式 | system_grant(安装即授) | manual_settings(设置里手动授权/可撤销) |
| 起始版本 | API 18 | API 22 |
| 设备范围 | 无限制 | 官方文档限定 PC/2in1 |
| 审计 | 不留使用记录 | 授予后系统仍记 AddPermissionUsedRecord |
| 商用获取 | 基本拿不到 | 华为 AGC 审批(仅 PC/2in1 场景) |
文档里 CUSTOM_SCREEN_RECORDING 写得很明确:“申请该权限后录屏不再弹出隐私告警弹窗”,看起来是正解。但在我的设备上它是个不存在的东西——这就引出本次最大的坑。
四、坑 1(最大坑):API 版本 ≠ 权限定义存在
定制系统会裁剪权限定义表。查权限是否真的存在,不是看文档、不是看 API 版本,而是查设备的 access_token 权限定义表:
hdc shell "atm dump -d" | grep -A6 "CUSTOM_SCREEN_RECORDING"
# 输出为空 = 这个系统里该权限根本不存在,声明了也白搭
hdc shell "atm dump -d" | grep -A6 "EXEMPT_CAPTURE_SCREEN_AUTHORIZE"
# 有定义,且关键字段:SYSTEM_GRANT / provisionEnable: true
我这台 API 23 的系统,全量定义表(200+ KB)里 CUSTOM_SCREEN_RECORDING 出现 0 次。之前无论怎么配预授权都不弹消失,根因在此——授一个系统里不存在的权限,是不可能成功的。
注意区分两个"权限表":
- ATM 权限定义表(
atm dump -d):权限的存在性、级别、授权方式、provisionEnable,决定"能不能授"/system/etc/app/install_list_permissions.json:按应用(bundleName + 签名)的预授权列表,决定"给谁授"
我一开始把它们混为一谈,绕了远路。
五、为什么 EXEMPT 能被普通签名拿到
按规则,system_core 级权限要求应用 APL ≥ system_core,而 DevEco 自动签名的应用 APL 是 normal。能授予是因为定义表里:
grantMode: SYSTEM_GRANT ← 安装时自动授,不需要用户点
availableLevel: SYSTEM_CORE ← 门槛很高……
provisionEnable: true ← ……但跨级授予免 profile 声明,installer 直接放行
判定是二选一:APL 够 → 直接授;APL 不够 → 走 ACL,而 ACL 的授权来源可以是 profile 里的 acls.allowed-acls(要改签名材料),或者 provisionEnable: true 时免声明直接放行。所以不需要系统签名,不需要改 profile,普通调试证书 + 一行声明即可。
六、最终方案
// entry/src/main/module.json5
"requestPermissions": [
{
"name": "ohos.permission.EXEMPT_CAPTURE_SCREEN_AUTHORIZE",
"reason": "$string:xxx_desc",
"usedScene": { "abilities": ["EntryAbility"], "when": "always" }
}
]
重新编译安装,完事。验证:
hdc shell "hilog -r" # 清日志后点录屏
hdc shell "hilog -x" | grep -i privacywindow
# ScreenCaptureServer::CheckPrivacyWindowSkipPermission() START.
# CheckPrivacyWindowSkipPermission: user have the right to skip privacywindow ← 放行
界面直接进入"录制中",无弹窗。
七、踩坑记录清单
坑 1:给不存在的权限做配置
如上。任何 install_list_permissions.json / 签名 profile 手段都救不了"定义表里没有的权限"。配权限前先 atm dump -d | grep 确认存在。
坑 2:install_list_permissions.json 的三种"签名"写法
这个文件是按应用预授权格式(bundleName + app_signature 数组 + permissions 数组)。app_signature 我见过/试过的写法:
- 证书 hex 指纹(如
A4F58FD6...,某些工具从 .cer 算出的 SHA256)——本次实验里居然也能生效 - appId 格式(
bm dump -n <包名>里的bundleName_base64串)——和系统应用条目格式一致 - 空字符串
""——文档说调试签名可匹配任意
最后的结论是:对"免弹窗"这个需求,整个文件根本不用动(见坑 4),所以格式之争没有意义。但如果哪天真需要预授权(比如给 user_grant 权限做免确认),建议按系统应用条目的 appId 格式写,最稳。
坑 3:改了文件不重启 = 白改
bundle 服务只在开机时读 /system/etc/app/install_list_permissions.json。改完必须 hdc shell reboot,再重装应用(token 是安装时创建的)。跳过重启去验证,会得到完全错误的结论。
坑 4:一次只改一个变量,否则归因错误
我中间版本同时换了"权限"和"签名格式"两个变量,导致误判"必须 appId 格式才生效"。后来做对照实验(每组都完整走 改配置 → 重启 → 重装 → 实测):
- hex 签名 → 依然免弹窗 ✅
- 删掉整个条目 → 依然免弹窗 ✅
真相:起作用的只有 module.json5 里的权限声明。"我测过了,都可以"有时候是对的,要用控制变量法去解释为什么。
坑 5:grantStatus: 0 不代表没授予
atm dump -t -i <tokenId> 里 system_grant 权限显示 grantStatus: 0,但实际已授予且工作正常(KEEP_BACKGROUND_RUNNING 也是 0)。别被这个字段骗去反复重装。
坑 6:查源码要用 GitHub master,Gitee 镜像是旧的
Gitee 上的 multimedia_player_framework master 同步滞后,没有 CUSTOM_SCREEN_RECORDING 相关代码,会误导判断。GitHub master 才有完整逻辑。
坑 7:hdc 传文件的两个坑
hdc file send 本地文件 /data/local/tmp/xxx.json(目标不存在时)会镜像本地 Windows 路径建目录,文件实际落在/data/local/tmp/Local/Temp/xxx.json之类的子目录里。用grep -rl "特征串" /data/local/tmp按内容定位。hdc shell "cat 不存在的源 > /system/xxx"时重定向会先把目标截断成 0 字节再报错。改 /system 文件前必须先备份:cp 原文件 /data/local/tmp/xxx.bak。- 写入姿势:
cat /data/local/tmp/新文件 > /system/etc/app/install_list_permissions.json && sync(前提mount -o remount,rw /)。
坑 8:文档描述与设备实况的差距
官方文档说 CUSTOM_SCREEN_RECORDING 仅 PC/2in1、API 22 起。实际还有第三重门槛——厂商镜像有没有把这个权限编进去。三道门(文档 → API 版本 → 定义表)都过了才算数。
八、遗留事项
- 换系统镜像后若弹窗复现,先
atm dump -d确认 EXEMPT 定义(尤其provisionEnable)还在不在。 - module.json5 里我把
CUSTOM_SCREEN_RECORDING也留着:当前系统上空转、无害,等以后换带完整定义表的镜像会自动生效,算个双保险。 - 这是自控设备的调试方案。要上华为商用市场的话,EXEMPT(system_core)拿不到,只能走 CUSTOM_SCREEN_RECORDING 的 AGC 受限权限审批,且官方仅支持 PC/2in1——手机上这个弹窗是去不掉的。
九、一图总结
弹窗原因: 三方应用默认无任何豁免权限 → 系统服务弹出隐私确认框
失败原因: 试图授予 CUSTOM_SCREEN_RECORDING,但定制系统定义表里没有此权限
最终方案: module.json5 声明 ohos.permission.EXEMPT_CAPTURE_SCREEN_AUTHORIZE
(SYSTEM_GRANT + provisionEnable:true → 安装时免 profile 直接授予)
验证方法: hilog grep "have the right to skip privacywindow" + 界面无弹窗
维护成本: 零(不改设备文件,换签名证书也不受影响)
更多推荐

所有评论(0)