文章目录一、前言二、工具函数方法一览三、截屏检测方法详解3.1 isCaptured() — 当前是否有截屏/投屏/录屏3.2 onCaptureStatusChange() / offCaptureStatusChange() — 监听状态变化四、屏幕旋转监听方法详解4.1 addOnScreenOrientationChange() — 注册旋转监听4.2 removeOnScreenOrientationChange() — 注销旋转监听五、完整演示代码5.1 截屏检测演示5.2 屏幕旋转监听演示5.3 页面生命周期中统一注销5.4 UI 渲染屏幕监听 Tab六、实际应用场景场景 1支付页面防截屏提示场景 2横竖屏实时响应七、注意事项八、小结一、前言近期发现一款很有意思的HarmonyOS 三方库, 地址 pura/harmony-utils(V1.4.0) , 作者是桃花镇童长老, 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦案例demo导航展示↓↓↓↓↓↓接下来言归正传 ↓↓↓↓除了获取屏幕静态信息DisplayUtil还提供了事件监听能力屏幕旋转监听当用户旋转设备时应用能够实时感知方向变化并调整布局。截屏/投屏/录屏检测某些需要保护隐私的场景如支付界面、私信内容需要检测是否正在被截屏。本文结合DisplayUtilDemoPage.ets的完整演示代码详细讲解这两类监听能力。二、工具函数方法一览// 检测当前是否有截屏/投屏/录屏行为staticisCaptured():boolean// 监听截屏/投屏/录屏状态变化staticonCaptureStatusChange(callback:Callbackboolean):void// 取消截屏状态监听staticoffCaptureStatusChange(callback?:Callbackboolean):void// 注册屏幕旋转监听内部去重同一 callback 不会重复注册staticaddOnScreenOrientationChange(callback:ScreenOrientationCallback):void// 移除屏幕旋转监听staticremoveOnScreenOrientationChange(callback:ScreenOrientationCallback):void三、截屏检测方法详解3.1isCaptured()— 当前是否有截屏/投屏/录屏源码staticisCaptured():boolean{returndisplay.isCaptured();}说明返回true当前设备正在截屏、投屏或录屏。返回false当前无上述行为。这是一个时间点快照方法调用时立即返回当前状态。Demo 使用loadCaptureStatus(){constcapturedDisplayUtil.isCaptured();this.isCapturedResultcaptured?⚠️ 正在截屏/投屏/录屏:✅ 正常;this.addLog(Capture,isCaptured() ${captured},captured?warn:info);}3.2onCaptureStatusChange()/offCaptureStatusChange()— 监听状态变化源码staticonCaptureStatusChange(callback:Callbackboolean){display.on(captureStatusChange,callback);}staticoffCaptureStatusChange(callback?:Callbackboolean){display.off(captureStatusChange,callback);}回调参数说明true设备开始截屏/投屏/录屏。false设备结束投屏/录屏截屏操作只会触发一次true不会触发false。注意截屏与投屏/录屏的行为略有不同——截屏是瞬间操作只触发一次true而投屏和录屏是持续行为开始时触发true结束时触发false。四、屏幕旋转监听方法详解4.1addOnScreenOrientationChange()— 注册旋转监听源码DisplayUtil.etsprivatestaticonScreenOrientationChanges:ArrayScreenOrientationCallback[];privatestaticorientation:display.Orientation|undefinedundefined;privatestaticonScreenOrientationChange:Callbacknumber(data){letorientationDisplayUtil.getOrientation();if(DisplayUtil.orientation!orientation){DisplayUtil.orientationorientation;DisplayUtil.onScreenOrientationChanges.forEach(callbackcallback(orientation));}};staticaddOnScreenOrientationChange(callback:ScreenOrientationCallback):void{DisplayUtil.registerScreenOrientationChange();ArrayUtil.addUnique(DisplayUtil.onScreenOrientationChanges,callback);}内部机制分析使用ArrayUtil.addUnique保证同一个 callback 不会被重复添加。首次注册时才调用display.on(change, ...)真正监听系统事件懒初始化。内部比较新旧方向DisplayUtil.orientation ! orientation只有真正发生旋转时才触发回调避免无效触发。4.2removeOnScreenOrientationChange()— 注销旋转监听源码staticremoveOnScreenOrientationChange(callback:ScreenOrientationCallback):void{DisplayUtil.unRegisterScreenOrientationChange();ArrayUtil.remove(DisplayUtil.onScreenOrientationChanges,callback);}privatestaticunRegisterScreenOrientationChange(){if(DisplayUtil.onScreenOrientationChanges.length1){try{display.off(change,DisplayUtil.onScreenOrientationChange);}catch(err){...}}}说明当监听数组中只剩 1 个 callback 时即即将清空才真正取消系统事件订阅这样在多个组件同时监听时不会意外取消其他组件的监听。五、完整演示代码5.1 截屏检测演示registerCaptureStatusChange(){if(this.captureStatusCallback!undefined){this.addLog(Capture,截屏状态监听已注册无需重复,warn);return;}this.captureStatusCallback(captured:boolean){this.lastCaptureStatusChangecaptured?截屏/投屏/录屏开始:截屏/投屏/录屏结束;this.isCapturedResultcaptured?⚠️ 正在截屏/投屏/录屏:✅ 正常;this.addLog(Capture,截屏状态变化:${this.lastCaptureStatusChange},captured?warn:success);};DisplayUtil.onCaptureStatusChange(this.captureStatusCallback);this.captureStatusChangeStatus已注册;this.captureStatusChangeColor#00C853;this.addLog(Capture,onCaptureStatusChange() 已注册,success);}unregisterCaptureStatusChange(){if(this.captureStatusCallback!undefined){DisplayUtil.offCaptureStatusChange(this.captureStatusCallback);this.captureStatusCallbackundefined;this.captureStatusChangeStatus已注销;this.captureStatusChangeColor#888;this.addLog(Capture,offCaptureStatusChange() 已注销,warn);}}5.2 屏幕旋转监听演示registerOrientationChange(){if(this.orientationCallback!undefined){this.addLog(Orientation,已注册无需重复注册,warn);return;}this.orientationCallback(orientation:display.Orientation){constlabelthis.getOrientationLabel(orientation);this.lastOrientationChangelabel;this.addLog(Orientation,屏幕旋转:${label},success);};DisplayUtil.addOnScreenOrientationChange(this.orientationCallback);this.orientationChangeStatus已注册;this.orientationChangeColor#00C853;this.addLog(Orientation,addOnScreenOrientationChange() 已注册,success);}unregisterOrientationChange(){if(this.orientationCallback!undefined){DisplayUtil.removeOnScreenOrientationChange(this.orientationCallback);this.orientationCallbackundefined;this.orientationChangeStatus已注销;this.orientationChangeColor#888;this.addLog(Orientation,removeOnScreenOrientationChange() 已注销,warn);}else{this.addLog(Orientation,尚未注册无需注销,warn);}}5.3 页面生命周期中统一注销aboutToDisappear():void{this.unregisterAllListeners();}unregisterAllListeners(){if(this.orientationCallback!undefined){DisplayUtil.removeOnScreenOrientationChange(this.orientationCallback);this.orientationCallbackundefined;}if(this.captureStatusCallback!undefined){DisplayUtil.offCaptureStatusChange(this.captureStatusCallback);this.captureStatusCallbackundefined;}// 折叠监听同理...}5.4 UI 渲染屏幕监听 Tab// ══ 屏幕监听 ════════════════════════════════════════if(this.activeTab4){// 截屏检测Column(){Text(截屏/投屏/录屏检测).fontSize(13).fontColor(#666).fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:8})Row(){Text(isCaptured():).fontSize(12).fontColor(#888)Text(this.isCapturedResult).fontSize(13).fontWeight(FontWeight.Bold).fontColor(this.isCapturedResult.includes(⚠️)?#FF5252:#00C853).margin({left:6})}.width(100%).margin({bottom:8})Row(){Text(监听状态:).fontSize(12).fontColor(#888)Text(this.captureStatusChangeStatus).fontSize(12).fontWeight(FontWeight.Bold).fontColor(this.captureStatusChangeColor).margin({left:6})Text(| 最后变化:${this.lastCaptureStatusChange}).fontSize(11).fontColor(#AAA).margin({left:8})}.width(100%).margin({bottom:10})Flex({wrap:FlexWrap.Wrap}){Button(注册监听).fontSize(12).height(34).backgroundColor(#00C853).fontColor(#FFF).onClick((){this.registerCaptureStatusChange();}).margin({right:8,bottom:8})Button(注销监听).fontSize(12).height(34).backgroundColor(#FF5252).fontColor(#FFF).onClick((){this.unregisterCaptureStatusChange();}).margin({right:8,bottom:8})Button(刷新状态).fontSize(12).height(34).backgroundColor(#4080FF).fontColor(#FFF).onClick((){this.loadCaptureStatus();}).margin({bottom:8})}.width(100%)}.width(100%).padding(14).backgroundColor(#FFFFFF).borderRadius(12)// 屏幕旋转监听Column(){Text(屏幕旋转监听).fontSize(13).fontColor(#666).fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:8})Text(⚠️ 旋转设备触发日志大量操作可能影响性能).fontSize(11).fontColor(#FF9800).alignSelf(ItemAlign.Start).margin({bottom:8})Row(){Text(监听状态:).fontSize(12).fontColor(#888)Text(this.orientationChangeStatus).fontSize(12).fontWeight(FontWeight.Bold).fontColor(this.orientationChangeColor).margin({left:6})Text(| 最后:${this.lastOrientationChange}).fontSize(11).fontColor(#AAA).margin({left:8})}.width(100%).margin({bottom:10})Flex({wrap:FlexWrap.Wrap}){Button(注册监听).fontSize(12).height(34).backgroundColor(#00C853).fontColor(#FFF).onClick((){this.registerOrientationChange();}).margin({right:8,bottom:8})Button(注销监听).fontSize(12).height(34).backgroundColor(#FF5252).fontColor(#FFF).onClick((){this.unregisterOrientationChange();}).margin({right:8,bottom:8})}.width(100%)}.width(100%).padding(14).backgroundColor(#FFFFFF).borderRadius(12)}六、实际应用场景场景 1支付页面防截屏提示aboutToAppear(){// 检查进入时是否正在截屏if(DisplayUtil.isCaptured()){this.showPrivacyWarning();}// 监听截屏动作this.captureCallback(capturing:boolean){if(capturing){this.showPrivacyWarning();// 可以选择隐藏敏感信息this.maskSensitiveDatatrue;}else{this.maskSensitiveDatafalse;}};DisplayUtil.onCaptureStatusChange(this.captureCallback);}场景 2横竖屏实时响应aboutToAppear(){this.orientationCallback(orientation:display.Orientation){if(orientationdisplay.Orientation.LANDSCAPE){// 切换横屏布局this.columns3;}else{// 切换竖屏布局this.columns1;}};DisplayUtil.addOnScreenOrientationChange(this.orientationCallback);}aboutToDisappear(){if(this.orientationCallback){DisplayUtil.removeOnScreenOrientationChange(this.orientationCallback);}}七、注意事项必须在aboutToDisappear中注销监听否则组件销毁后回调仍然有效会导致访问已销毁组件的State变量引发错误。isCaptured是快照不是实时需要配合onCaptureStatusChange监听才能实时感知截屏。重复注册的防护addOnScreenOrientationChange内部使用ArrayUtil.addUnique防重复但onCaptureStatusChange没有这个保护Demo 中通过if (callback ! undefined)手动防止重复注册。性能提示屏幕旋转监听回调可能频繁触发用户旋转时回调内不要执行耗时操作。八、小结方法类型说明isCaptured()状态查询当前是否截屏/投屏/录屏onCaptureStatusChange(cb)监听截屏状态变化事件offCaptureStatusChange(cb?)注销取消截屏监听addOnScreenOrientationChange(cb)监听屏幕旋转事件内部去重removeOnScreenOrientationChange(cb)注销取消旋转监听掌握这些监听 API配合aboutToAppear/aboutToDisappear生命周期钩子你就能构建出对屏幕状态变化实时响应的健壮 HarmonyOS 应用。