uni-app 截屏监听与防截屏 API 实战:onUserCaptureScreen / offUserCaptureScreen / setUserCaptureScreen 全平台实现解析
2026/9/19 19:43:44 网站建设 项目流程

uni-app 截屏监听与防截屏 API 实战:onUserCaptureScreen / offUserCaptureScreen / setUserCaptureScreen 全平台实现解析

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

本篇技术指南围绕 uni-app(uni-app x)的"用户截屏事件监听与防截屏"能力展开,完整讲解uni.onUserCaptureScreenuni.offUserCaptureScreenuni.setUserCaptureScreen三个扩展 API 的兼容性、参数定义、调用示例,并结合当前仓库中uni-usercapturescreen插件的 Android / iOS / HarmonyOS / 微信小程序源码,剖析截屏监听与防截屏在系统底层的实现机制。读完本文,你将能够在金融、隐私类 App 中独立实现"截屏检测提示 + 敏感页面防截屏"的完整方案。

说明:docs/api/capturescreen.md是文档迁移入口,其最新内容位于 capture-screen.md,本文以该文档为骨架,并引用仓库内插件源码 uni-usercapturescreen 与官方示例页 capture-screen.uvue 进行纵深印证。

一、API 能力总览

截屏相关 API 属于 uni-app 的ext api(扩展 API),需要下载并集成uni-usercapturescreen插件后方可使用(插件本体位于 src/uni_modules/uni-usercapturescreen,其 readme 对该插件定位为"用户主动截屏事件监听")。共包含三个接口:

| API | 能力 | 典型场景 | | :- | :- | :- | |uni.onUserCaptureScreen(callback)| 开启截屏监听 | 检测到用户截屏后弹出隐私提示 | |uni.offUserCaptureScreen(callback)| 关闭截屏监听 | 页面退出时释放监听 | |uni.setUserCaptureScreen(options)| 设置防截屏 | 敏感页面禁止截图(如验证码、支付页) |

其中,"截屏"特指用户通过手机系统自带按键(电源键+音量键等)触发的截屏行为,而非代码内对视图的截图。若需要通过代码对某个 view 截图,应使用 takeSnapshot 相关 API。

二、uni.onUserCaptureScreen:开启截屏监听

2.1 函数签名与参数

开启截屏监听,当用户使用系统截屏按键截屏时触发回调。参数定义如下:

| 名称 | 类型 | 必填 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | callback | (res: OnUserCaptureScreenCallbackResult) => void | 否 | Web: x |uni.onUserCaptureScreen/uni.offUserCaptureScreen回调函数定义 |

回调结果对象OnUserCaptureScreenCallbackResult的属性值:

| 名称 | 类型 | 必备 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | path | string | 否 | Web: x | 截屏文件路径(仅 Android 返回) |

在插件类型定义 utssdk/interface.uts 中,回调类型被声明为:

export type OnUserCaptureScreenCallbackResult = { /** * 截屏文件路径(仅Android返回) */ path ?: string } export type UserCaptureScreenCallback = (res : OnUserCaptureScreenCallbackResult) => void export type OnUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void

2.2 兼容性

| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | x | 4.11 | 3.9.0 | 4.11 | 4.61 |

从 interface.uts 的@uniPlatform注释可看到更细粒度的版本要求:

  • Android:系统osVer >= 4.4.4,uni-app xunixVer >= 3.9.0
  • iOS:系统osVer >= 12.0,uni-app xunixVer >= 4.11
  • HarmonyOS:系统osVer >= 3.0,uni-app xunixVer >= 4.61
  • 微信小程序:宿主hostVer >= 1.4.0,uni-app xunixVer >= 4.11
  • Web 端不支持(标记为 x),其他小程序平台(支付宝、百度、抖音、飞书、QQ、快手、京东)当前亦不支持。

2.3 Android 端实现原理:文件系统监听

Android 端实现位于 utssdk/app-android/index.uts,核心是继承android.os.FileObserverScreenFileObserver,对截屏图片目录做文件新增(CREATE)事件监听

class ScreenFileObserver extends FileObserver { private screenFile : File; constructor(screenFileStr : string) { super(screenFileStr); this.screenFile = new File(screenFileStr); } override onEvent(event : Int, path : string | null) : void { // 只监听文件新增事件 if (event == FileObserver.CREATE) { if (path != null) { const currentTime = System.currentTimeMillis(); if ((currentTime - lastObserverTime) < 1000) { // 本地截屏行为比上一次超过1000ms, 才认为是一个有效的时间 return; } lastObserverTime = currentTime; const screenShotPath = new File(this.screenFile, path).getPath(); const res : OnUserCaptureScreenCallbackResult = { path: screenShotPath } listener?.(res); } } } }

实现细节要点:

  • 监听目录按厂商区分:小米机型监听DCIM/Screenshots,其他机型监听PICTURES/Screenshots(见Build.MANUFACTURER.toLowerCase() == "xiaomi"的分支判断);
  • 防抖处理:两次截屏事件间隔小于 1000ms 时直接丢弃,避免同一次截屏触发重复回调;
  • 权限申请:首次调用时检查READ_EXTERNAL_STORAGE权限,未授予则通过ActivityCompat.requestPermissions主动申请;
  • 生命周期释放:通过UTSAndroid.onAppActivityDestroy在 Activity 销毁时自动stopWatching,防止监听泄漏;
  • 回调结果:Android 端回调中会携带path字段(截屏文件完整路径),这也是path属性"仅 Android 返回"的原因。

2.4 iOS 端实现原理:系统截屏通知

iOS 端实现位于 utssdk/app-ios/index.uts,通过注册系统通知UIApplication.userDidTakeScreenshotNotification监听截屏:

static listenCaptureScreen(callback : UserCaptureScreenCallback | null) { this.listener = callback // target-action 回调方法需要通过 Selector("方法名") 构建 const method = Selector("userDidTakeScreenshot") NotificationCenter.default.addObserver(this, selector = method, name = UIApplication.userDidTakeScreenshotNotification, object = null) } @objc static userDidTakeScreenshot() { const res: OnUserCaptureScreenCallbackResult = {} this.listener?.(res) }

iOS 系统在用户截屏后会广播userDidTakeScreenshotNotification,插件以 target-action 方式订阅,截屏发生时回调userDidTakeScreenshot()并触发开发者注册的 listener。注意 iOS 回调结果中不含 path

2.5 HarmonyOS 端实现原理:captureStatusChange 事件

HarmonyOS 端实现位于 utssdk/app-harmony/index.uts,通过display.on('captureStatusChange')订阅系统截屏状态变更:

const onUserCaptureScreenCallbacks: Function[] = [] const harmonyCaptureStatusChange: Callback<boolean> = (captureStatus: boolean) => { if (captureStatus) { onUserCaptureScreenCallbacks.forEach(cb => { typeof cb === 'function' && cb() }) } } display.on('captureStatusChange', harmonyCaptureStatusChange)

插件内部维护回调数组onUserCaptureScreenCallbacksonUserCaptureScreen负责 push、offUserCaptureScreen负责按引用移除(indexOf+splice),多个监听者互不覆盖。

三、uni.offUserCaptureScreen:关闭截屏监听

3.1 函数签名与参数

取消截屏事件监听,参数与onUserCaptureScreen一致:

| 名称 | 类型 | 必填 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | callback | (res: OnUserCaptureScreenCallbackResult) => void | 否 | Web: x |uni.onUserCaptureScreen/uni.offUserCaptureScreen回调函数定义 |

最佳实践:传入的 callback 必须与onUserCaptureScreen注册时是同一个函数引用,否则无法正确移除(尤其是 HarmonyOS 端依赖indexOf精确查找引用)。

3.2 各平台关闭逻辑

  • Android:直接停止 FileObserver 监听并置空引用(见 app-android/index.uts 的offUserCaptureScreen,同时会重置lastObserverTime防抖时间戳);
  • iOS:移除 NotificationCenter 观察者并清空 listener(NotificationCenter.default.removeObserver(this));
  • HarmonyOS:从回调数组中按引用移除指定回调。

四、uni.setUserCaptureScreen:设置防截屏

4.1 函数签名与参数

设置防截屏,控制用户能否截取当前应用页面内容:

| 名称 | 类型 | 必填 | 兼容性 | | :- | :- | :- | :-: | | options |SetUserCaptureScreenOptions| 是 | Web: x |

options属性描述:

| 名称 | 类型 | 必备 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | enable | boolean | 是 | Web: x | true: 允许用户截屏;false: 不允许用户截屏,防止用户截屏到应用页面内容 | | success | (res: SetUserCaptureScreenSuccess) => void | 否 | Web: x | 设置成功回调 | | fail | (res: IUniError) => void | 否 | Web: x | 设置失败回调 | | complete | (res: any) => void | 否 | Web: x | 完成回调(成功、失败均执行) |

其中IUniError的属性值(错误对象,详细规范见 err-spec.md):

| 名称 | 类型 | 必备 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | errCode | number | 是 | Web: x | 统一错误码 | | errSubject | string | 是 | Web: x | 统一错误主题(模块)名称 | | data | any | 否 | Web: x | 错误信息中包含的数据 | | cause | Error | 否 | | 源错误信息,可以包含多个错误,详见 SourceError | | errMsg | string | 是 | Web: x | 错误描述 |

4.2 兼容性

| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | x | 4.11 | 3.9.0 | 4.11 | 4.61 |

注意 iOS 端setUserCaptureScreen对系统版本要求更高(osVer >= 13.0,见 interface.uts 的注释),而on/offUserCaptureScreen在 iOS 12.0 起即可用。

4.3 各平台防截屏实现原理

Android:FLAG_SECURE 窗口标志位

在 app-android/index.uts 中,通过切换窗口的FLAG_SECURE标志实现,且必须运行在 UI 线程:

export const setUserCaptureScreen : SetUserCaptureScreen = function (option : SetUserCaptureScreenOptions) { // 切换到UI线程 UTSAndroid.getUniActivity()?.runOnUiThread(new SetUserCaptureScreenRunnable(option.enable)); const res : SetUserCaptureScreenSuccess = {} option.success?.(res); option.complete?.(res); } class SetUserCaptureScreenRunnable extends Runnable { override run() : void { if (this.enable) { UTSAndroid.getUniActivity()?.getWindow()?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE); } else { UTSAndroid.getUniActivity()?.getWindow()?.addFlags(WindowManager.LayoutParams.FLAG_SECURE); } } }

FLAG_SECURE是系统级防截屏机制:设置后截屏画面为空白/黑屏,同时禁止最近任务预览图显示应用内容。

iOS:安全输入视图(UITextField secure 技巧)

iOS 端没有公开的防截屏 API,插件采用了业界通用的"借壳"方案——利用UITextField.isSecureTextEntry = true时系统自动创建的私有安全视图,将其插入到窗口层级中包裹根视图,从而让截屏画面变黑(见 app-ios/index.uts 的createSecureView/onAntiScreenshot/offAntiScreenshot)。同时注意,iOS 的 uts 方法默认在子线程执行,涉及 UI 操作统一通过DispatchQueue.main.async切回主线程。

HarmonyOS:PRIVACY_WINDOW 受限权限 + 窗口隐私模式

HarmonyOS 端通过ohos.permission.PRIVACY_WINDOW受限开放权限(使用前需在应用配置中申请受限权限)配合window.setWindowPrivacyMode(!options.enable)设置窗口隐私模式(见 app-harmony/index.uts):

UTSHarmony.requestSystemPermission(['ohos.permission.PRIVACY_WINDOW'], (allRight: boolean, _grantedList: string[]) => { if (allRight) { window.setWindowPrivacyMode(!options.enable, (err: BusinessError) => { // 成功/失败分别回调 success / fail / complete }); } // ... });

权限被拒绝(permission denied)时会走fail回调,错误主题(errSubject)统一为uni-usercapturescreen

4.4 错误码定义

防截屏相关错误码在 utssdk/unierror.uts 中统一定义,错误主题为uni-usercapturescreen

| 错误码 | 错误信息 | 触发条件 | | :- | :- | :- | | 12001 |setUserCaptureScreen:system not support| iOS 系统版本低于 13.0 | | 12010 |setUserCaptureScreen:system internal error| iOS 15.1 系统 bug 导致 |

export const UniErrors : Map<SetUserCaptureScreenErrorCode, string> = new Map([ [12001, 'setUserCaptureScreen:system not support'], [12010, 'setUserCaptureScreen:system internal error'], ]); export class SetUserCaptureScreenFailImpl extends UniError implements SetUserCaptureScreenFail { constructor(errCode : SetUserCaptureScreenErrorCode) { super(); this.errSubject = UniErrorSubject; this.errCode = errCode; this.errMsg = UniErrors[errCode] ?? ""; } }

五、完整实战示例:截屏监听 + 防截屏组合页面

以下是仓库官方示例 src/pages/API/capture-screen/capture-screen.uvue 的完整代码(与 hello uni-app x 同步维护),实现了"允许截屏开关 + 开启/关闭截屏监听"的完整交互,可在真机上直接体验(该 API 不支持 Web,请运行到 App 平台):

<template> <view class="uni-container"> <page-head :title="title"></page-head> <view class="uni-common-mt"> <text class="uni-title">截屏状态:{{ captureStatus }}</text> <boolean-data :defaultValue="allowCapture" title="是否允许截屏" @change="toggleCaptureScreen"></boolean-data> <view class="uni-btn"> <button @click="startCaptureListener" type="primary" class="uni-common-mt">开启截屏监听</button> <button @click="stopCaptureListener" class="uni-common-mt">关闭截屏监听</button> </view> </view> </view> </template> <script setup lang="uts"> import { state, setAllowCapture } from '@/store/index.uts' const title = '截屏监听' const allowCapture = ref(state.allowCapture) const captureStatus = ref('未监听') let captureCallback: ((res: OnUserCaptureScreenCallbackResult) => void) | null = null; const toggleCaptureScreen = (checked: boolean) => { uni.setUserCaptureScreen({ enable: checked, success: (res: SetUserCaptureScreenSuccess) => { allowCapture.value = checked setAllowCapture(checked) console.log('设置截屏状态成功:', res) }, fail: (err:IUniError) => { console.log('设置截屏状态失败:', err) } }) } const startCaptureListener = () => { captureCallback = (res: OnUserCaptureScreenCallbackResult) => { captureStatus.value = '检测到截屏' console.log('检测到用户截屏',res) } uni.onUserCaptureScreen(captureCallback) captureStatus.value = '正在监听' console.log('开始监听截屏') } const stopCaptureListener = () => { if (captureCallback != null) { uni.offUserCaptureScreen(captureCallback) captureStatus.value = '未监听' console.log('停止监听截屏') } } // 页面卸载时清理监听 onUnmounted(() => { stopCaptureListener() }) </script>

示例中的关键编码规范:

  1. 回调引用复用captureCallback保存为模块级变量,供 on / off 成对使用,保证能精确解绑;
  2. 生命周期清理:在onUnmounted中调用stopCaptureListener(),避免页面销毁后监听器泄漏(对应 Android 端 Activity 销毁自动释放的兜底逻辑);
  3. 状态驱动 UI:通过ref维护captureStatusallowCapture,截屏检测到后立即更新界面提示。

六、使用注意事项(tips)

以下限制与坑位来自官方文档,务必在方案设计阶段确认:

  • 本文的"截屏"指手机自带截屏事件的监听和取消监听,由用户操作手机按键触发。App 平台如需通过代码对 view 截屏,另见 API takeSnapshot;
  • iOS 13.0 以下系统不支持该系列 API,调用setUserCaptureScreen会返回错误12001: system not support
  • iOS 15.1 系统存在系统 bug,在该系统上调用setUserCaptureScreen会返回错误12010: system internal error
  • Android 平台在某些页面暂不支持,如:图片选择等页面以及 App 原生插件内部的原生页面;
  • HarmonyOS 平台使用setUserCaptureScreen时需要添加受限开放权限ohos.permission.PRIVACY_WINDOW(对应 app-harmony/index.uts 中的requestSystemPermission动态申请逻辑)。

七、延伸阅读:仓库内相关资源

| 资源 | 路径 | 说明 | | :- | :- | :- | | 官方 API 文档 | capture-screen.md | 本文内容的一手来源 | | 插件 README | uni-usercapturescreen/readme.md | 插件能力简介 | | 类型与兼容性定义 | uni-usercapturescreen/utssdk/interface.uts | 回调、选项类型及各平台版本要求 | | Android 实现 | uni-usercapturescreen/utssdk/app-android/index.uts | FileObserver 监听 + FLAG_SECURE 防截屏 | | iOS 实现 | uni-usercapturescreen/utssdk/app-ios/index.uts | 系统截屏通知 + 安全视图防截屏 | | HarmonyOS 实现 | uni-usercapturescreen/utssdk/app-harmony/index.uts | captureStatusChange 监听 + 窗口隐私模式 | | 错误码定义 | uni-usercapturescreen/utssdk/unierror.uts | 12001 / 12010 错误映射 | | 官方示例页面 | src/pages/API/capture-screen/capture-screen.uvue | 可直接运行的完整示例 |

综上,uni.onUserCaptureScreen/uni.offUserCaptureScreen/uni.setUserCaptureScreen三个 API 覆盖了"截屏检测"与"防截屏"两大诉求:监听侧在 Android 基于文件系统监听、在 iOS 基于系统截屏通知、在 HarmonyOS 基于captureStatusChange事件;防截屏侧在 Android 依赖FLAG_SECURE、在 iOS 采用安全视图技巧、在 HarmonyOS 依赖PRIVACY_WINDOW受限权限与窗口隐私模式。理解这些平台差异后,开发者即可在 uni-app 项目中按需集成,为金融、隐私、版权类业务提供可靠的截屏防护能力。

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询