Android 能悄悄知道用户截屏?这里有你想要的答案

很多应用在当你截屏的时候能够感知到,并提示你是否要发送截屏等等。

很多应用在当你截屏的时候能够感知到,并提示你是否要发送截屏等等。

Andorid 官方 API 没有检测截屏的能力,但有一些变通的办法能够检测用户在使用应用时是否进行了截屏操作。本文将探讨如何实现这一功能。

在Android中监听用户截屏可以通过以下几种方案实现:

方案一:监听媒体库变化

当用户截屏后,截屏图片通常会被保存到设备的媒体库中。可以通过注册一个 ContentObserver 来监听媒体库的变化,从而判断是否有新的截屏图片被添加。

示例代码:

class ScreenshotObserver(val context: Context, val handler: Handler) :
    ContentObserver(handler) {

    override fun onChange(selfChange: Boolean) {
        // 检查是否有新的截屏图片
        checkForScreenshot()
    }

    private fun checkForScreenshot() {
        val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        val projection = arrayOf(MediaStore.Images.Media.DATA)
        val selection = MediaStore.Images.Media.DISPLAY_NAME + " LIKE ?";
        val selectionArgs = arrayOf("%screenshot%")
        val cursor = context.getContentResolver()
            .query(contentUri, projection, selection, selectionArgs, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                // 找到了新的截屏图片
                Logger.d("Screenshot detected!");
            }
            cursor.close();
        }
    }
}


private fun registerResolver() {
    // 在Activity或Service中注册ContentObserver
    val contentResolver = contentResolver;
    val handler = Handler(Looper.getMainLooper());
    val screenshotObserver = ScreenshotObserver(this, handler)
    contentResolver.registerContentObserver(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        true,
        screenshotObserver
    )
}

  • 这个方案通过监听媒体库的变化来检测截屏。当媒体库有变动时, onChange  方法会被调用。

  • 在  checkForScreenshot   方法中,通过查询媒体库中名称包含 “screenshot” 的图片来判断是否有新截屏。

  • 最后在 Activity 或 Service 中注册这个  ContentObserver   来开始监听。


方案二:监听系统广播

当用户截屏时,系统会发送一个广播 Intent.ACTION_SCREENSHOT 。可以通过注册一个  BroadcastReceiver 来监听这个广播。

示例代码:

class ScreenshotReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent) {
        if (Intent.ACTION_SCREENSHOT.equals(intent.action)) {
            // 用户截屏了
            Log.d("ScreenshotReceiver", "Screenshot detected!")
        }
    }
}

val intentFilter =  IntentFilter(Intent.ACTION_SCREENSHOT);
val screenshotReceiver = ScreenshotReceiver();
registerReceiver(screenshotReceiver, intentFilter);

注意:从Android 10开始,系统不再发送 Intent.ACTION_SCREENSHOT 广播,因此这个方案在Android 10及以上版本不可用。

  • 此方案通过注册 BroadcastReceiver 来监听系统发送的截屏广播。

  • 当接收到 Intent.ACTION_SCREENSHOT 广播时,表示用户进行了截屏操作。

方案三:使用AccessibilityService

通过创建一个 AccessibilityService ,可以监听系统中的各种事件,包括截屏事件。当用户截屏时,系统会生成一个无障碍事件,可以通过监听这个事件来判断用户是否截屏。

示例代码(部分):

class ScreenshotAccessibilityService : AccessibilityService() {

    override fun onAccessibilityEvent(event: AccessibilityEvent?) {
        if (event?.eventType == AccessibilityEvent.TYPE_VIEW_CLICKED) {
            // 检查是否是截屏按钮被点击
            if (isScreenshotButtonClicked(event)) {
                // 用户截屏了
                Logger.d("Screenshot detected!");
            }
        }
    }

    override fun onInterrupt() {

    }

    private fun isScreenshotButtonClicked(event: AccessibilityEvent): Boolean {
        // 实现检查截屏按钮被点击的逻辑
        // 注意:这只是一个示例,实际实现可能更复杂
        return false
    }
}

<service
    android:name=".service.ScreenshotAccessibilityService"
    android:exported="false"
    android:permission="android.permission.BIND_ACCESSIBILITY_ SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
</service>

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:packageNames="com.android.systemui"
    android:accessibilityEventTypes="typeViewClicked"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="true"/>
  • 通过创建 AccessibilityService 来监听系统中的各种事件,包括截屏事件。

  • 在 onAccessibilityEvent 方法中,判断事件类型并检查是否是截屏按钮被点击。

  • 使用此方案需要在 AndroidManifest.xml 中进行注册,并配置相关的权限和参数。

  • 要注意,使用 AccessibilityService 需要用户手动授权,并且在 Android 10 及以上版本中,对权限有更严格的限制,使用时要谨慎处理用户隐私和权限问题。


以上三种方案各有优缺点,可以根据实际需求选择合适的方案来实现监听用户截屏的功能。


来源: 互联网
本文观点不代表码客-全球程序员交流社区立场,不承担法律责任,文章及观点也不构成任何投资意见。

赞 ()

相关推荐

  • 置顶 开发项目接单群,免费入群了

    无论你是Android、ios、java、php,或者你是产品经理、老板,都可以免费入群接单或者发布项目,全程不收取任何费用。

    2025年02月21日 15点27分
  • Android加快你的编译速度

    工欲善其事,必先利其器。如果每次运行项目都要花费5-10分钟,那人的心态都要崩了。

    2025年02月25日 15点40分
  • Flutter多渠道打包的解决方案(walle)

    我们的应用集成了TalkingData这个第三方工具来统计日活、事件等,需要在应用启动时初始化SDK,这个时候需要传入当前渠道,以便数据的统计。 由于最开始是用脚本一个个打包,一直想解决打包过慢的问题,但是网上大多教程是基于命令行参数或flavor,实质上并没有根本解决打包效率的问题。直到发现了文章的主角 walle。

    2025年02月25日 15点36分
  • Android-分享一个对RecyclerView二次封装的库(EasyRecyclerView)

    在日常的Android开发当中,我们肯定会有使用到RecyclerView的需求,这里分享一个对RecyclerView二次封装的开源库——EasyRecyclerView。它基本上满足基本的开发需求,希望能帮看文章的小伙伴提高开发效率。

    2025年02月25日 15点31分
  • Android原生系统真的那么好用吗?安卓原生系统吊打其他系统,因为有Google-Play,所以应用都是纯净的?

    实际方面,原生 Android 的最大优势是更新快速,对供应商特别是 Android 上游的补丁的合并速度非常快,几乎总能在第一时间更新。因为系统越原生,更新的代价就越小。反之,如果一个停止更新的原生 Android 其实是没有多大意义的,它失去了它最大的优势。

    2025年02月25日 15点30分
  • Application 作为 Dialog 的 Context?小心踩坑!

    大家好,相信大家在使用 Dialog 时,都有一个非常基本的认知:就是 Dialog 的 context 只能是 Activity,而不能是 Application,不然会导致弹窗崩溃:

    2025年02月25日 15点25分
  • Android 应用的线程世界:最少需要几个线程才能启动?

    这篇文章主要介绍了 Android App 中的多种线程,包括守护线程(如 Signal Catcher 等)、渲染线程、主线程、三方线程(如 OkHttp、Glide、ARouter 相关线程)等,还提及三方库中线程池的情况及可能存在的问题。

    2025年02月25日 15点13分
  • Android 复杂项目崩溃率收敛至0.01%实践

    在我们的项目中,每个版本发布之后,我们会创建一个opt分支,用于修复线上崩溃以及业务逻辑BUG。

    2025年02月25日 15点11分
  • Android 能悄悄知道用户截屏?这里有你想要的答案

    很多应用在当你截屏的时候能够感知到,并提示你是否要发送截屏等等。

    2025年02月25日 15点07分
  • 科大讯飞讯飞星火API能力免费开放,引领大模型商业化新篇章

    合肥本土科技巨头科大讯飞传来振奋人心的消息:讯飞星火API能力正式向公众免费开放,其中,讯飞星火Lite API更是实现了永久免费。这一举措无疑为整个行业注入了新的活力,也彰显了科大讯飞在大模型商业化进程中的坚定决心。

    2025年02月21日 15点57分
  • 一木林接入AI大模型,实现智能体功能

    一木林——全能型AI电子工具箱。这是一款集多功能于一体的工具类应用,凭借小巧的体积与全面且强大的功能,赢得了极高的口碑。应用内汇聚了上百款实用工具,诸如指南针、计算器、分贝仪等,一应俱全。如今,一木林已携手星火AI大模型,实现了AI对话与智能体的创新功能。

    2025年02月21日 15点42分
  • PrivacySentry:隐私政策守护利器

    近年来,工信部对APP个人隐私要求越来越多,之后各大应用市场也开始要求,有违规情况的会导致APP下架或者无法上架。这不,我的app就因为三方SDK频繁获取Android ID 导致无法上架,等SDK商场更新也很浪费时间,所以只能想办法去处理这件事,好在找到了PrivacySentry这个神器,可规避应用市场上架合规检测的大部分问题

    2025年02月18日 23点20分
  • Kotlin协程:MutableSharedFlow的实现原理

    在Koltin协程:异步热数据流的设计与使用中,提到了可以通过MutableSharedFlow方法创建一个MutableSharedFlow接口指向的对象,代码如下:

    2025年02月18日 11点03分
  • 探索Markdown之父John Gruber对Markdown的看法

    Markdown的缔造者——约翰·格鲁伯,其形象正如上方头像所示。不禁让人遐想,国外的大师们是否都偏爱蓄须? 约翰·格鲁伯,1973年出生于美国宾夕法尼亚州,他是一位才华横溢的作家、博主、UI设计师,更是Markdown的创始人。他毕业于Drexel University(卓克索大学),并获得了计算机科学学士学位。在职业生涯中,他曾在Joyent公司任职,为大型企业提供了基础架构和平台服务。自2002年起,他开始撰写备受欢迎的科技博客《Daring Fireball》,并主持了知名的播客节目The Talk Show。2013年,他与两位友人共同创立了Q Branch,并开发了Vesper笔记应用。

    2025年02月18日 10点52分
  • 浅聊一下JVM内存结构

    2025年02月17日 14点29分
  • Android屏幕适配(6) — 今日头条屏幕适配

    在之前的文章中,我们讲到了Android屏幕适配的一些知识,大家感兴趣的话可参考 Android屏幕适配(1) — 概念解释 Android屏幕适配(2) — drawable与mipmap Android屏幕适配(3) — 资源文件夹命名与匹配规则 Android屏幕适配(4) — 宽高限定符 Android屏幕适配(5) — 最小宽度smallWidth适配 这节我们讲讲今日头条屏幕适配方案。

    2025年02月15日 11点19分

发表回复

评论列表

点击查看更多

    联系我们

    在线咨询: QQ交谈

    微信:dxmcpjl

    邮件:1529097251#qq.com

    工作时间:周一至周五,9:30-18:30,节假日休息

    微信