环境: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() → 弹窗,等用户点"允许"
}

也就是说有三条正规跳过通道:

  1. 持有 ohos.permission.EXEMPT_CAPTURE_SCREEN_AUTHORIZE(挡在最外层)
  2. 持有 ohos.permission.CUSTOM_SCREEN_RECORDING(挡在弹窗流程里)
  3. 应用包名恰好等于系统参数 const.multimedia.screencapture.screenrecorderbundlename(伪装成系统录屏器,副作用多,不推荐)

另外 IsUserPrivacyAuthorityNeeded() 里 root 进程直接放行,但应用进程不是 root,用不上。

三、两个权限的对比

EXEMPT_CAPTURE_SCREEN_AUTHORIZECUSTOM_SCREEN_RECORDING
设计对象系统内部应用的"豁免"通道三方应用的官方免弹窗通道(受限开放权限)
权限级别system_coresystem_basic
授权方式system_grant(安装即授)manual_settings(设置里手动授权/可撤销)
起始版本API 18API 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" + 界面无弹窗
维护成本:  零(不改设备文件,换签名证书也不受影响)
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐