更新记录
0.2.0(2026-09-06)
- 新增录屏/投屏自动遮挡,可与后台遮罩独立配置;Android 15+ 与 iOS 捕获状态变化时自动覆盖敏感内容。
- 新增前台动态水印,支持文本、颜色、透明度、字号、旋转角度和横纵间距配置。
- 新增多监听器 API,监听器使用独立 ID 注册和移除;保留
startPrivacyEventMonitor()/stopPrivacyEventMonitor()兼容旧项目。 - 新增运行诊断 API,返回系统版本、前后台状态、监听器数量、遮罩与水印可见状态、原生回调注册状态和最近错误。
- Android 补充
DETECT_SCREEN_RECORDING普通权限,完善多 Activity 生命周期、回调切换和 Android 10 兼容处理。 - iOS 17+ 改用 Scene 捕获状态 Trait,低版本继续使用系统捕获状态通知;完善多 Scene/多窗口恢复逻辑。
- 示例页新增主动保护和运行诊断区域,继续采用白色系界面,并同步完善 API、FAQ、隐私说明和测试清单。
- Android、iOS UTS 插件模块编译通过;完整真机保护效果仍需按测试清单验证。
0.1.0(2026-08-21)
- 修复 Android 10 上
ActivityLifecycleCallbacks$-CC缺失导致的启动崩溃,并在 SEUIC CRUISE Ge2 真机验证前后台切换不再报错。 - 完成 Android 后台遮罩、
FLAG_SECURE截屏保护、Android 14 截图事件和 Android 15 录屏状态检测。 - 完成 iOS 后台遮罩、截图完成事件及录屏/投屏状态监听。
- 新增平台能力状态 API、交互式示例页、API 文档和发布前测试清单。
- 通过 Android、iOS UTS 插件模块与双端整项目编译,并在 iOS 模拟器完成首屏运行检查。
平台兼容性
uni-app x(4.0)
| Chrome | Safari | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|---|---|
| × | × | 5.0 | 0.2.0 | 12 | 0.2.0 | × | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | × | √ |
APP 隐私屏幕保护
xs-privacy-screen 是面向 uni-app x App 的本地隐私屏幕保护 UTS 插件。它用一套接口封装 Android、iOS 后台任务快照遮罩、录屏自动遮挡、前台动态水印、Android FLAG_SECURE 截屏保护,以及系统支持范围内的截图、录屏/投屏和前后台事件。
当前版本:0.2.0
0.2.0已通过 Android、iOS UTS 插件模块与整项目编译,并在 iOS 26.3 模拟器完成示例页启动、状态/诊断读取和白色系首屏检查。Android 10 真机兼容记录来自0.1.0;新增保护效果和多窗口逻辑仍应按测试清单完成真机验收。本文不会用编译结果代替真机保护结论。
核心特性
| 能力 | 说明 |
|---|---|
| 双端统一接口 | Android 5.0 及以上、iOS 12.0 及以上使用相同的 UTS 配置、状态和事件类型 |
| 后台隐私遮罩 | App 离开前台时用原生视图覆盖任务界面快照,可配置颜色、图片和文案 |
| Android 截屏保护 | 使用系统 FLAG_SECURE 保护当前及后续 Activity 的常规截图和非安全显示输出 |
| 截图事件 | Android 14+ 监听系统支持的截图动作;iOS 12+ 在截图完成后收到通知 |
| 录屏状态 | Android 15+ 检测本 App 是否对录屏可见;iOS 12+ 检测录屏、镜像或 AirPlay 克隆 |
| 录屏自动遮挡 | 可独立配置捕获遮罩;检测到录屏/投屏时覆盖前台,捕获结束后恢复 |
| 前台动态水印 | 原生重复绘制文字水印,可配置颜色、透明度、字号、角度和间距 |
| 能力矩阵 | 运行时返回真实系统能力,避免业务层根据平台名称猜测 |
| 多监听器与诊断 | 支持按 ID 管理多个订阅者,并查询回调、遮罩、水印与最近错误 |
| 独立控制 | 后台遮罩、捕获遮罩、水印、截屏保护和事件监听可分别启停 |
| 本地与离线 | 不读取截图内容或屏幕像素,不联网、不存储、不上传数据 |
适用场景
- 金融、医疗、政务、企业内部等敏感信息页面的后台任务快照遮挡。
- Android 登录页、身份信息页、密钥页等页面的系统截图保护。
- 在系统允许范围内提示用户当前页面正在被录屏或投屏。
- 记录截图、录屏状态和前后台变化,用于页面提示或业务风控联动。
插件提供的是系统公开能力的统一封装,不是 DRM 或防泄密终局方案。Root、越狱、外部相机、定制系统、调试器和其他进程内采集不在保护承诺内。
平台支持
开发环境
| 项目 | 要求 |
|---|---|
| 开发框架 | uni-app x App |
| HBuilderX | 5.0 及以上 |
| uni-app x | 4.0 及以上 |
| Android | Android 5.0 / API 21 及以上 |
| iOS | iOS 12.0 及以上 |
能力差异
| 能力 | Android 5.0~13 | Android 14 | Android 15+ | iOS 12+ |
|---|---|---|---|---|
| 后台任务快照遮罩 | 支持 | 支持 | 支持 | 支持 |
| 阻止常规系统截屏 | FLAG_SECURE |
FLAG_SECURE |
FLAG_SECURE |
不支持 |
| 截图事件 | 不支持 | 支持 | 支持 | 支持,截图完成后通知 |
| 录屏/投屏状态 | 不支持 | 不支持 | 支持 | 支持 |
| 录屏自动遮挡 | 不支持 | 不支持 | 支持 | 支持 |
| 前台动态水印 | 支持 | 支持 | 支持 | 支持 |
| 前后台事件 | Activity 级 | Activity 级 | Activity 级 | 应用级 |
| 用户运行时授权 | 无 | 无 | 无 | 无 |
Web、小程序和 HarmonyOS 暂不支持。
安装与运行
将插件目录放入业务项目的 uni_modules/xs-privacy-screen,统一从插件根目录导入公开接口:
import {
configureCaptureShield,
configurePrivacyScreen,
configurePrivacyWatermark,
setScreenshotBlocked,
isScreenCaptured,
getPrivacyScreenDiagnostics,
getPrivacyScreenStatus,
addPrivacyEventListener,
removePrivacyEventListener,
startPrivacyEventMonitor,
stopPrivacyEventMonitor
} from '@/uni_modules/xs-privacy-screen'
不要从 utssdk、平台子目录或原生类名导入内部实现,否则后续升级可能失去兼容性。
原生配置
| 平台 | 插件内配置 | 用途 |
|---|---|---|
| Android | android.permission.DETECT_SCREEN_CAPTURE |
Android 14+ 标准截图检测;普通安装时权限,不弹运行时授权框 |
| Android | android.permission.DETECT_SCREEN_RECORDING |
Android 15+ 录屏可见状态检测;普通安装时权限,不弹运行时授权框 |
| Android | minSdkVersion = 21 |
声明最低系统版本为 Android 5.0 |
| iOS | deploymentTarget = 12.0 |
声明最低系统版本为 iOS 12.0 |
iOS 不需要用户授权权限。插件也不申请存储、相机、麦克风或网络权限。
标准基座不包含当前插件的完整原生实现和 Android 权限。真机调试前应制作包含本插件的自定义基座,并在最终打包后核对配置合并结果。
快速开始
下面示例在页面进入时配置保护、启动事件监听,在页面销毁时释放当前页面持有的监听。业务项目如果需要全局监听,应把监听所有权放到应用级模块,不要让普通页面卸载时误停止全局监听。
import {
addPrivacyEventListener,
configureCaptureShield,
configurePrivacyScreen,
configurePrivacyWatermark,
getPrivacyScreenDiagnostics,
getPrivacyScreenStatus,
removePrivacyEventListener,
setScreenshotBlocked,
CaptureShieldOptions,
PrivacyScreenEvent,
PrivacyScreenOptions,
PrivacyWatermarkOptions
} from '@/uni_modules/xs-privacy-screen'
let privacyListenerId = ''
function enablePrivacyProtection() {
configurePrivacyScreen({
enabled: true,
backgroundColor: '#101820',
imagePath: null,
message: '敏感内容已隐藏'
} as PrivacyScreenOptions)
configureCaptureShield({
enabled: true,
backgroundColor: '#183126',
imagePath: null,
message: '录屏期间内容已隐藏'
} as CaptureShieldOptions)
configurePrivacyWatermark({
enabled: true,
text: 'CONFIDENTIAL',
color: '#315D48',
opacity: 0.12,
fontSize: 13,
rotation: -24,
horizontalGap: 150,
verticalGap: 100
} as PrivacyWatermarkOptions)
const blockSupported = setScreenshotBlocked(true)
if (!blockSupported) {
console.log('当前平台不能阻止系统截图,继续使用遮罩和事件提示')
}
privacyListenerId = addPrivacyEventListener((event : PrivacyScreenEvent) => {
if (event.type == 'screenshot') {
console.log('系统截图事件', event.timestamp)
} else if (event.type == 'recording-start') {
console.log('检测到录屏或投屏开始')
} else if (event.type == 'recording-stop') {
console.log('录屏或投屏结束')
}
})
const status = getPrivacyScreenStatus()
console.log('截图保护能力', status.screenshotBlockingSupported)
console.log('截图事件能力', status.screenshotDetectionSupported)
console.log('录屏检测能力', status.recordingDetectionSupported)
console.log('运行诊断', getPrivacyScreenDiagnostics())
}
function releasePageMonitor() {
if (privacyListenerId.length > 0) {
removePrivacyEventListener(privacyListenerId)
privacyListenerId = ''
}
}
关闭保护时需要分别关闭三个独立部分:
configurePrivacyScreen({
enabled: false,
backgroundColor: '#101820',
imagePath: null,
message: null
} as PrivacyScreenOptions)
setScreenshotBlocked(false)
configureCaptureShield({
enabled: false,
backgroundColor: '#183126',
imagePath: null,
message: null
} as CaptureShieldOptions)
configurePrivacyWatermark({
enabled: false,
text: 'CONFIDENTIAL',
color: '#315D48',
opacity: 0.12,
fontSize: 13,
rotation: -24,
horizontalGap: 150,
verticalGap: 100
} as PrivacyWatermarkOptions)
releasePageMonitor()
推荐接入顺序
- 页面或应用初始化时调用
getPrivacyScreenStatus(),按真实能力决定按钮和提示。 - 尽早调用
configurePrivacyScreen(),避免第一次进入后台前尚未注册生命周期。 - 需要录屏自动隐藏时配置
configureCaptureShield();需要水印时配置configurePrivacyWatermark()。 - 仅在 Android 且业务确实需要时启用
setScreenshotBlocked(true)。 - 新项目用
addPrivacyEventListener()获取监听 ID,页面销毁时只移除自己持有的监听。 - 退出敏感业务或账号登出时,按业务要求分别关闭各项保护。
接口总览
| 接口 | 返回值 | 说明 |
|---|---|---|
configurePrivacyScreen(options) |
void |
配置后台遮罩、颜色、图片和文案 |
configureCaptureShield(options) |
void |
配置录屏/投屏期间自动显示的前台遮罩 |
configurePrivacyWatermark(options) |
void |
配置前台重复文字水印 |
setScreenshotBlocked(blocked) |
boolean |
Android 设置安全窗口;iOS 返回 false |
isScreenCaptured() |
boolean |
同步读取当前录屏、投屏或屏幕镜像状态 |
getPrivacyScreenStatus() |
PrivacyScreenStatus |
同步读取当前配置和设备能力矩阵 |
getPrivacyScreenDiagnostics() |
PrivacyScreenDiagnostics |
读取监听、原生回调、遮罩、水印和最近错误 |
addPrivacyEventListener(callback) |
string |
新增独立监听并返回监听 ID |
removePrivacyEventListener(id) |
boolean |
只移除指定监听器 |
startPrivacyEventMonitor(callback) |
void |
兼容 0.1.0 的单监听槽位 |
stopPrivacyEventMonitor() |
void |
只停止兼容单监听槽位 |
后台遮罩
configurePrivacyScreen(options)
configurePrivacyScreen({
enabled: true,
backgroundColor: '#101820',
imagePath: null,
message: '内容已保护'
})
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled |
boolean |
是 | 是否在 App/Activity 进入后台时显示原生遮罩 |
backgroundColor |
string |
是 | 推荐 #RRGGBB 或 #AARRGGBB;空值或非法颜色回退到 #101820 |
imagePath |
string \| null |
是 | 可选本地图片;空值或解析失败时显示内置 PRIVATE 标识 |
message |
string \| null |
是 | 遮罩主文案;空值或空白字符串显示“内容已保护” |
图片路径规则:
| 写法 | Android | iOS |
|---|---|---|
绝对路径 /... |
本地文件 | 本地文件 |
file://... |
本地文件 URI | 本地文件 URL |
content://... |
支持;调用方需确保读取权限仍有效 | 不支持 |
| 相对路径或名称 | Android assets 相对路径 | App Bundle 图片名 |
插件只做本地解码,不下载网络图片。建议使用体积受控的静态图片,避免把超大原图作为遮罩素材;图片解析失败不会阻止遮罩显示。
Android 在 Activity onPause 时添加遮罩,在 onResume 时移除;iOS 在应用进入后台时为当前可见窗口添加遮罩,应用重新激活时移除。复杂导航、多 Activity、多 Scene、分屏和多窗口场景需要在目标项目中单独验证。
录屏自动遮挡
configureCaptureShield(options)
options 的字段结构与后台遮罩一致,但作用时机不同:后台遮罩保护任务快照,捕获遮罩在应用仍处于前台且系统报告录屏/投屏时覆盖内容。
configureCaptureShield({
enabled: true,
backgroundColor: '#183126',
imagePath: null,
message: '录屏期间内容已隐藏'
} as CaptureShieldOptions)
Android 需要 API 35+ 和插件自动合并的 DETECT_SCREEN_RECORDING 普通权限;iOS 17+ 使用 Scene 捕获状态 Trait,iOS 12~16 使用系统屏幕捕获状态通知。系统不支持检测时配置仍可安全保存,但不会出现自动遮挡,业务应结合 recordingDetectionSupported 提示用户。
前台动态水印
configurePrivacyWatermark(options)
| 字段 | 类型 | 约束与说明 |
|---|---|---|
enabled |
boolean |
是否在应用窗口上方绘制水印 |
text |
string |
空白时回退为 CONFIDENTIAL |
color |
string |
推荐 #RRGGBB 或 #AARRGGBB |
opacity |
number |
自动限制到 0~1 |
fontSize |
number |
自动限制到 10~48 |
rotation |
number |
自动限制到 -60~60 度 |
horizontalGap |
number |
自动限制到 80~360 |
verticalGap |
number |
自动限制到 60~300 |
水印为不拦截触摸的本地原生视图,不读取底层页面、截图或屏幕像素。它只能增加外传识别成本,不等于数字取证、不可移除水印或内容溯源。
Android 截屏保护
setScreenshotBlocked(blocked)
const supported = setScreenshotBlocked(true)
| 平台 | 返回值 | 行为 |
|---|---|---|
| Android | true |
对当前及后续 Activity 设置或清除 WindowManager.LayoutParams.FLAG_SECURE |
| iOS | false |
不修改系统截图行为 |
返回值表示平台是否接受这项配置,不表示用户已经截图,也不证明所有外部采集方式都被阻止。
开启 FLAG_SECURE 后,常规系统截图通常会被阻止或显示空白,因此验证 Android 截图事件时应先关闭截屏保护,避免“截图本身未发生”被误判为监听失效。
捕获状态
isScreenCaptured()
const captured = isScreenCaptured()
| 平台 | 行为 |
|---|---|
| Android 15+ | 返回本 App 当前是否对系统录屏可见 |
| Android 14 及以下 | 系统没有当前实现使用的等价公开能力,返回 false |
| iOS 12+ | 返回主屏幕是否处于录屏、屏幕镜像或 AirPlay 克隆状态 |
false 可能表示“当前没有捕获”,也可能表示“当前系统版本不支持检测”。业务判断必须同时查看 recordingDetectionSupported。
状态查询
getPrivacyScreenStatus()
同步返回当前配置与运行设备能力,不申请权限,也不启动监听。
| 字段 | 类型 | 说明 |
|---|---|---|
platform |
string |
android 或 ios |
privacyScreenEnabled |
boolean |
当前后台遮罩配置是否开启 |
screenshotBlocked |
boolean |
当前是否已请求 Android 截屏保护;iOS 固定为 false |
screenshotBlockingSupported |
boolean |
是否支持系统级截屏保护 |
screenshotDetectionSupported |
boolean |
当前系统版本是否支持截图事件 |
recordingDetectionSupported |
boolean |
当前系统版本是否支持录屏/投屏状态检测 |
screenCaptured |
boolean |
当前是否检测到录屏、投屏或屏幕镜像 |
能力字段表示源码在当前系统版本上存在对应路径,不等同于该设备已经完成真机验收。
getPrivacyScreenDiagnostics()
诊断接口用于接入排错,不启动监听,也不读取屏幕内容。它返回平台与系统版本、应用前后台状态、监听器数量、两类遮罩与水印的配置/可见状态、截图/录屏原生回调是否已注册,以及最近一次原生注册错误。lastError 为 null 表示当前没有已知错误,不代表设备行为已经通过真机验收。
事件监听
startPrivacyEventMonitor(callback)
这是为 0.1.0 保留的兼容 API。重复调用只替换 legacy-listener 兼容槽位,不会移除通过新 API 注册的其他监听器。
startPrivacyEventMonitor((event : PrivacyScreenEvent) => {
console.log(event.type, event.timestamp)
})
| 事件 | Android | iOS | 说明 |
|---|---|---|---|
screenshot |
Android 14+ | iOS 12+ | Android 为系统支持的截图动作;iOS 为截图完成通知 |
recording-start |
Android 15+ | iOS 12+ | App 内容开始被系统录屏、投屏或镜像捕获 |
recording-stop |
Android 15+ | iOS 12+ | 捕获状态结束 |
background |
Android 5.0+ | iOS 12+ | Android Activity 暂停;iOS 应用进入后台 |
foreground |
Android 5.0+ | iOS 12+ | Android Activity 恢复;iOS 应用重新激活 |
事件结构:
| 字段 | 类型 | 说明 |
|---|---|---|
type |
PrivacyEventType |
五种事件之一 |
timestamp |
number |
事件产生时的 Unix 毫秒时间戳 |
Android 14 标准截图检测主要覆盖系统支持的截图入口,不承诺 ADB、测试框架或定制厂商路径。启用标准截图检测后,系统可能向用户显示隐私提示,业务页面应提前说明用途。
iOS 在开始监听时,如果屏幕已经处于被捕获状态,当前实现会立即发送一次 recording-start,用于同步初始状态。
addPrivacyEventListener(callback) / removePrivacyEventListener(id)
新项目推荐使用多监听器 API:每次添加返回一个不透明字符串 ID,移除时只影响对应订阅者。
const listenerId = addPrivacyEventListener((event : PrivacyScreenEvent) => {
console.log(event.type, event.timestamp)
})
const removed = removePrivacyEventListener(listenerId)
多个监听器共享底层系统回调。Android 在最后一个事件监听器移除后注销截图回调;若录屏自动遮挡仍开启,录屏回调会继续保留,这是保护功能的正常行为。
stopPrivacyEventMonitor()
只停止 startPrivacyEventMonitor() 创建的兼容监听槽位,不影响 addPrivacyEventListener() 创建的订阅。没有其他监听器且录屏自动遮挡关闭时,Android 会释放对应平台捕获回调;iOS 系统通知观察者保留供后续复用,但不会继续向已移除的业务回调发送事件。
该调用不会:
- 关闭后台隐私遮罩。
- 清除 Android
FLAG_SECURE。 - 修改之前调用
configurePrivacyScreen()保存的配置。 - 关闭录屏自动遮挡或动态水印。
典型调用流程
仅保护后台任务快照
页面初始化 -> configurePrivacyScreen(enabled = true)
离开前台 -> 原生遮罩覆盖窗口 -> 系统生成任务快照
返回前台 -> 原生遮罩移除
Android 截屏保护
进入敏感业务 -> setScreenshotBlocked(true)
离开敏感业务 -> setScreenshotBlocked(false)
事件驱动提示
读取能力 -> 支持时启动监听 -> 收到事件 -> 更新页面提示
|
页面/业务结束 --------------------> 停止监听
页面与生命周期建议
- 尽早配置后台遮罩,不要等到 App 已进入后台才首次调用。
- 页面级监听应在页面卸载时停止;全局监听应由唯一的应用级模块持有。
- Android 会聚合已启动 Activity 后再发出应用级
background/foreground;多窗口和厂商系统仍需真机验证。 - 事件回调中只更新轻量状态;需要网络上报时由业务层做节流、隐私告知和失败重试。
screenCaptured为true时可隐藏敏感区域、暂停展示或提醒用户;开启捕获遮罩后插件会自动覆盖整个应用窗口。- 账号退出、敏感流程结束或插件不再使用时,显式恢复业务期望的遮罩和安全窗口状态。
常见问题
为什么 iOS 开启阻止截屏后返回 false?
iOS 没有面向第三方 App 的公开系统截图禁用 API。插件不会通过私有 API 或伪造成功结果,iOS 可用的是后台遮罩、截图完成通知和录屏/镜像状态检测。
为什么 Android 设备没有截图事件?
先查看 screenshotDetectionSupported。该事件要求 Android 14 / API 34 及以上;Android 13 及以下返回不支持。测试时还应先关闭 FLAG_SECURE,并使用设备的标准系统截图入口。
为什么 isScreenCaptured() 一直返回 false?
Android 只有 15 / API 35 及以上支持当前实现使用的录屏可见状态 API。较低版本的 false 表示无法检测,不应解释为安全证明;同时检查 recordingDetectionSupported。
为什么停止监听后后台遮罩仍然存在?
五组能力相互独立。停止监听只释放对应事件回调;后台遮罩、捕获遮罩和水印需分别重新配置为 enabled: false,关闭 Android 截屏保护要调用 setScreenshotBlocked(false)。
插件能拿到用户的截图或录屏文件吗?
不能。事件只包含类型和时间戳,插件不读取截图、录屏、屏幕像素或业务内容。
当前限制
- 只面向 uni-app x App-Android、App-iOS。
- iOS 不支持系统截图阻止,截图事件发生在截图完成后。
- Android 14 以下没有截图事件,Android 15 以下没有录屏状态检测。
- Android 前后台事件会聚合已启动 Activity;复杂导航、多窗口和厂商行为仍需真机验证。
- 动态水印是视觉提示层,不提供不可删除、身份绑定或服务端溯源保证。
- 不提供事件持久化、网络上报、截图内容、录屏文件或审计后台。
- 不承诺防 Root、越狱、外部相机、定制 ROM 或其他非标准采集方式。
- 最低版本、多厂商、多窗口和完整系统事件仍需在业务目标设备上验证。
验证建议
正式使用前至少完成:
- Android API 21、34、35 与 iOS 12、当前 iOS 的版本边界验证。
- 开启和关闭后台遮罩后检查系统任务界面快照。
- Android 开启、关闭
FLAG_SECURE后分别测试截图与投屏。 - Android 14 关闭
FLAG_SECURE后测试标准系统截图事件。 - Android 15、iOS 真机测试录屏开始/结束和投屏、镜像状态。
- 连续前后台切换、连续启停监听、页面跳转和多窗口稳定性。
- 自定义图片、非法路径、透明颜色和长文案的显示边界。
隐私与合规
插件本身不联网只代表插件实现不发送数据,不代表集成它的业务应用不会记录或上传事件。业务方如需把截图或录屏事件用于风控、审计或账号处置,应在隐私政策和产品界面中说明用途、保存期限、访问范围与申诉机制,并遵守适用法律和平台规则。
更多文档
docs/API.md:完整类型、接口、平台差异、事件顺序和生命周期说明。docs/PLATFORM_AND_PRIVACY.md:保护模型、权限、数据流、产品提示和发布检查清单。docs/FAQ.md:接入、测试和常见故障排查。docs/TESTING.md:双端真机测试矩阵和设备记录模板。docs/VERIFICATION.md:当前已经完成与尚未完成的验证证据。

收藏人数:
购买源码授权版(
试用
使用 HBuilder 导入示例项目
赞赏(0)
下载 5
赞赏 0
下载 12653109
赞赏 1954
赞赏
京公网安备:11010802035340号