Android 14 新 API:直接监听截屏操作,不用再观察媒体文件了~

这篇具有很好参考价值的文章主要介绍了Android 14 新 API:直接监听截屏操作,不用再观察媒体文件了~。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android 14 新 API:直接监听截屏操作,不用再观察媒体文件了~
截屏可以说是手机设备最常用的功能了,Android 系统非常重视截屏方面的体验,近几年的更新都不忘去优化这方面的体验。

从一开始仅在通知栏提醒已截屏,到 Android 11 支持在左下角生成截屏缩略图供编辑或分享,再到 Android 12 支持滚动截屏,以及这次的 Android 14 允许 App 直接监听用户的截屏操作。

为打造更加标准的监听截屏体验,Android 14 正式推出了受隐私保护的相关 API。简单来说,该 API 允许 App 以 Activity 为单位注册监听 Callback,当这些 Activity 可见并且被用户截屏的话,系统将回调这些 Callback 并告知用户当前的 App 监听到了截屏操作。

如下是官方提供的效果示例:

需要留意的是:监听截屏 API 并不提供图像数据,意在告诉 App 截屏的时机,你可以选择在这个时机做相应的操作。比如:客服类 App 可以询问用户是否要上传截屏以反馈问题抑或引导用户从相册选择截屏;隐私程度高的 App 则可以提醒用户不要泄露、做好隐私保护等等。

实战

首先要给 App 声明监听截屏的权限: DETECT_SCREEN_CAPTURE

<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />

这个权限是 normal 级别的,无需动态申请,APK 被安装的时候将自动授予。

Allows an application to get notified when a screen capture of its windows is attempted.

Protection level: normal

之后的写法比较简单,即在需要监听截屏的 Activity 里注册回调:

  1. 创建 ScreenCaptureCallback 的实例,并在 onScreenCapture() 实现里添加所需逻辑,比如此处为弹出警告 Dialog:
    class ScreenShotActivity : AppCompatActivity() {
        private val screenCaptureCallback = ScreenCaptureCallback {
            Log.d("ScreenShot", "onScreenCaptured()", Throwable())
    
            AlertDialog.Builder(this)
                .setMessage("You have taken a screenshot...")
                .setTitle("Warning")
                .show()
        }
        ...
    }
  1. 接着,在该 Activity 的 onStart() 方法里注册上述的 ScreenCaptureCallback 实例,需要指定该回调的执行线程 Executor
class ScreenShotActivity : AppCompatActivity() {
    ...
    override fun onStart() {
        super.onStart()

        Log.d("ScreenShot", "onStart() registerScreenCaptureCallback")
        registerScreenCaptureCallback(mainExecutor, screenCaptureCallback)
    }
    ...
}
  1. 记得在 Activity 的 onStop() 里注销该 ScreenCaptureCallback 实例,避免内存 leak:
class ScreenShotActivity : AppCompatActivity() {
    ...
    override fun onStop() {
        super.onStop()

        Log.d("ScreenShot", "onStop() unregisterScreenCaptureCallback")
        unregisterScreenCaptureCallback(screenCaptureCallback)
    }
    ...
}

而后将目标 Activity 启动,通过 log 可以看到已经注册了监听回调,后面就是操作截屏进行验证。

04-05 21:57:53.904  5230  5230 D ScreenShot: onStart() registerScreenCaptureCallback

可是问题来了:笔者手动没有能够运行 Android 14 的真机,运行 14 的是 Pixel 6 模拟器。

要知道模拟器上你是无法直接同时按下 POWER 键+ VOLUME DOWN 按键来完成截屏的,同时 Pixel ROM 的通知面板也没有提供截屏的 UI 入口。

笔者突然想到了用 adb 模拟按键事件,可苦苦搜寻之后发现 input keyevent 仅支持单个 keyevent 的模拟。就在要放弃的时候,我忽然想到另一种 event 模拟办法,就是 sendevent

首先通过搜索和尝试获悉 POWER 键的长按输入办法:

adb shell sendevent /dev/input/event0 1 116 1 && adb shell sendevent /dev/input/event0 0 0 0 && sleep 3 && adb shell sendevent /dev/input/event0 1 116 0 && adb shell sendevent /dev/input/event0 0 0 0

再找到 VOLUME DOWN 键的长按输入办法:

adb shell sendevent /dev/input/event12 1 114 1 && adb shell sendevent /dev/input/event12 0 0 0 && sleep 3 && adb shell sendevent /dev/input/event12 1 114 0 && adb shell sendevent /dev/input/event12 0 0 0

两者一结合即可模拟同时长按 POWER 键+ VOLUME DOWN 按键的操作:

adb shell sendevent /dev/input/event0 1 116 1 && adb shell sendevent /dev/input/event0 0 0 0 && adb shell sendevent /dev/input/event12 1 114 1 && adb shell sendevent /dev/input/event12 0 0 0 && sleep 3 && adb shell sendevent /dev/input/event0 1 116 0 && adb shell sendevent /dev/input/event0 0 0 0 && adb shell sendevent /dev/input/event12 1 114 0 && adb shell sendevent /dev/input/event12 0 0 0

需要留意的是上述命令需要在 root 环境下执行,即 adb root 之后再执行 sendevent 命令,当然如果你有真机就无需这么迂回啦。

成功模拟用户截屏操作之后,如愿看到了截屏的缩略图和系统在屏幕下方给用户 App 监听了当前截屏的 Toast 提醒

以及系统给予当前 App 的截屏操作的回调:

04-05 21:58:04.459  5230  5230 D ScreenShot: onScreenCaptured()

App 也依据回调弹出了代码里拟定的截屏警告 Dialog。

能监听到 adb 等方式发起的截屏吗?

了解 Android 上截屏的朋友会知道,截屏的发起方式有很多种,除了最常用的按键组合外还可以:

  • 代码中使用 DeviceCapture test 框架、MediaProjectionManager、SurfaceControl 发起
  • 调试中使用 adb 命令发起
  • AS 的 logcat 窗口里的 “Screen Capture” 图标、Emulator 窗口的 “Take Screenshot” 菜单

等等。

那这些场景下的截屏操作,14 的方式是否能监听到呢?

答案是否定的,官方予以了明确说明:

In Android 14, the system API only detects a screenshot if the user performs a specific combination of hardware button presses. The API doesn’t detect screenshots that are taken when running test commands related to screenshots, including ADB, or within instrumentation tests that capture the device’s current screen contents.

笔者也实际尝试了下,无论是 ADB 命令还是 AS 的 UI 入口触发的截屏,都没有回调上述的 ScreenCaptureCallback,系统亦没有截屏的提醒。

理由也可想而知,一般用户不会用这样的方式截屏,这种调试场景下、系统场景下的截屏需求甚至不会在屏幕下方展示缩略图,自然没有必要回调监听的 API 了。

原理

Android 14 的源码尚未公开,但可以打印 ScreenCaptureCallback 的堆栈瞥到相关细节:

04-06 22:35:23.593  4627  4627 D ScreenShot: onScreenCaptured()
04-06 22:35:23.593  4627  4627 D ScreenShot: java.lang.Throwable
04-06 22:35:23.593  4627  4627 D ScreenShot:    at eu.thomaskuenneth.textviewhighlightsdemo.ScreenShotActivity.screenCaptureCallback$lambda-0(ScreenShotActivity.kt:13)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at eu.thomaskuenneth.textviewhighlightsdemo.ScreenShotActivity.$r8$lambda$5lHWf6dEQmh2JMn9HXzbeN068DI(Unknown Source:0)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at eu.thomaskuenneth.textviewhighlightsdemo.ScreenShotActivity$$ExternalSyntheticLambda0.onScreenCaptured(Unknown Source:2)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.app.ScreenCaptureCallbackHandler$ScreenCaptureObserver.lambda$onScreenCaptured$0(ScreenCaptureCallbackHandler.java:66)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.app.ScreenCaptureCallbackHandler$ScreenCaptureObserver$$ExternalSyntheticLambda0.run(Unknown Source:2)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Handler.handleCallback(Handler.java:958)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Handler.dispatchMessage(Handler.java:99)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Looper.loopOnce(Looper.java:205)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.os.Looper.loop(Looper.java:294)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at android.app.ActivityThread.main(ActivityThread.java:8128)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at java.lang.reflect.Method.invoke(Native Method)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
04-06 22:35:23.593  4627  4627 D ScreenShot:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:946)

通过上述堆栈 ,再结合 13 的现有截屏逻辑,可以推测下该 Callback 的实现:

  1. SystemUI 的 TakeScreenshotService 在截屏完成之后通知 AMS,AMS 判断当前 Activity 的 ScreenCaptureCallbackHandler 中是否存在 ScreenCaptureObserver
  2. YES 则意味着注册了 ScreenCaptureCallback,便通过 AIDL 告知 App 进程,App 进程内部通过 Handler 告知 ScreenCaptureCallbackHandler 在预设的 Executor 执行 onScreenCaptured() 回调

总结

ScreenCaptureCallback 监听截屏 API 的使用简单、清晰,以后不需要再通过监听媒体文件的变化等逻辑来迂回实现,采用官方的方式去探测用户的截屏操作并按照文件读写的规范去提取文件。

但需要留意 adb、代码、AS 等方式发起的截屏无法通过该 API 监听得到,笔者以为这些不属于用户操作,没有必要纳入到监听范围中。另外,这个监听 API 并不是 Application 级别的,每个目标 Activity 都得注册,所以可以考虑在 BaseActivity 中完成 API 的注册和注销。

相信这个 API 后续亦会扩展到 Jetpack 当中,届时无论是否升级到了 Android 14 都可以尝试切换到官方的监听截屏方式中来。文章来源地址https://www.toymoban.com/news/detail-413591.html

参考

  • Detect when users take device screenshots
  • DeviceCapture
  • ADB 模拟输入事件总结
  • Android系统截屏的实现分析

到了这里,关于Android 14 新 API:直接监听截屏操作,不用再观察媒体文件了~的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 不用996,不用007,赚的还比我多?我直接好家伙

    今天打开手机就看见信息99+,哟吼,还挺热闹——感情都在上班摸鱼呢。 好奇心让我点了第一条未读信息,好家伙,直接让我手机闪退出APP了! 嗨,我这暴脾气,直接手动滑到了第一条!但是我没想到到他们只是在日常卷,一水就水了那么多。 更奇葩的是群里的一个人的发

    2023年04月20日
    浏览(81)
  • 观察者模式, 发布-订阅模式, 监听器模式

    观察者模式是一种 行为型 设计模式, 定义对象间的一种 一对多 的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 角色模型和结构图 在观察者模式中,只有两种主体:目标对象 ( Object ) 和 观察者 ( Observer )。宗门任务大殿就是目标对象

    2024年02月22日
    浏览(46)
  • Unity 事件监听与广播(高度解耦合,观察者模式)

    使用观察者模式降低模块间的耦合性 通过C# 的 Dictionary 存放事件码和事件的委托 添加事件: 判断字典是否有该事件码,没有添加 判断当前委托类型与添加的事件码的类型是否一致 最后订阅该事件 移除事件: 先判断事件码是否存在 取消订阅 最后判断事件码是否为空,是

    2024年02月12日
    浏览(47)
  • 【开发工具】gitee还不用会?我直接拿捏 >_>

    🌈键盘敲烂,年薪30万🌈 目录 📕揭开git面纱 📕git的一些前置操作 📕如何获取本地仓库 📕本地仓库的操作 📕远程仓库操作 📕分支操作 📕标签操作 📕常见问题 注意:在使用git命令的时候一定要注意路径,在不同路径下执行相同命令结果也是不一样的例如创建和克隆仓

    2024年02月05日
    浏览(50)
  • 设计模式——14. 观察者模式

    观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能够自动收到通知并更新自己的状态,以保持与被观察对象的同步。观察者模式也被称为发布-订阅模式。 观察者模式包含以

    2024年02月07日
    浏览(44)
  • IDEA直接请求controller,不用postman请求http接口

    generated-requests.http工具用法 第一步:点击下面按钮,HTTP Client  第二步、生成generated-requests.http文件  第三步、更改服务的ip和端口,启动服务  请求实例: 1、post请求,body传参: 2、get请求 2.1 2.2

    2024年02月15日
    浏览(53)
  • 【微信小程序系列:二】小程序常用功能:跳转地图、扫一扫、人脸识别、拍照、拨打电话、调整屏幕亮度、文字可复制、监听截屏...

    (~ ̄▽ ̄)~,hello,微信小程序系列第二篇,介绍下小程序里的 前端常用功能api ,可以快速copy使用~ 小程序页面里的文字默认是没有长按复制功能的,需要套个标签来实现:跳转官方文档 点击按钮,直接复制文本,直接调用微信方法: 有时显示一些地址需要在地图显示,

    2023年04月09日
    浏览(78)
  • 【flink番外篇】9、Flink Table API 支持的操作示例(14)- 时态表的join(java版本)

    一、Flink 专栏 Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。 3、

    2024年02月02日
    浏览(55)
  • 防止Android截屏

    一、背景介绍 对于涉及用户个人隐私的应用,比如银行、支付、社交等应用,其界面中可能会涉及到用户的个人信息,比如手机号、身份证号码、交易记录等。如果这些信息被人截屏,就可能会造成用户个人隐私的泄露。 另外一方面,一些企业和开发者可能会开发一些自己

    2024年02月08日
    浏览(39)
  • Android 10.0 截屏流程

    Android 10.0版本在截屏方面做了一些改进和优化,使得截屏更加方便和高效。在Android 10.0版本中,可以使用多种方式实现截屏,其中包括使用系统快捷键、使用手势操作、调用API等。 Android 10.0版本中,截屏的流程大致如下: 触发截屏操作:用户可以通过系统快捷键或手势操作

    2024年02月09日
    浏览(80)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包