Android截屏监控(已适配Android 14)

GitHub Demo项目链接:https://github.com/DoubleD0721/Screenshot

前瞻

目前Android针对截屏的监控主要有三种方式:

  1. 利用FileObserver监听某个目录中资源的变化
  2. 利用ContentObserver监听全部资源的变化
  3. 直接监听截屏快捷键(由于不同的厂商自定义的原因,使用这种方法进行监听比较困难)

本文主要使用ContentObserver的方式来实现对截屏的监控。

Android 各版本适配

主要针对Android 13及Android 14更新的存储权限进行适配。

在Android 13中,存储权限从原来的READ_EXTERNAL_STORAGE细化成为READ_MEDIA_IMAGES/READ_MEDIA_VIDEO/READ_MEDIA_AUDIO三种权限,在进行权限判断的时候需要进行版本区分。

在Android 14中,存储权限从Android 13的细化权限中更新成为允许用户选择部分图片资源给应用访问。但是针对截屏增加了一个新的截屏监控权限DETECT_SCREEN_CAPTURE,该权限默认为开且用户无感知,针对用户只给部分权限的情况,我们可以通过该权限来获取用户的截屏动作,尝试一些不依赖截屏文件的操作。

权限状态 Android 13及以下机型 Android 14及以上机型
有全部相册权限 使用媒体库监控实现监控 使用媒体库监控实现监控
有部分相册权限 无法进行监控 使用系统API进行监控(但无法拿到截屏文件)
没有相册权限 无法进行监控 使用系统API进行监控(但无法拿到截屏文件)

Android 13及以下机型监控

针对Android 13及以下用户,使用监听媒体库方式进行截屏的监控

1. 建立相关截屏媒体库,分别监控内部存储及外部存储

private inner class MediaContentObserver(private val contentUri: Uri, handler: Handler?) : ContentObserver(handler) {
   
    override fun onChange(selfChange: Boolean, uri: Uri?) {
   
        // handle screenshot file
    }
}

在合适时机,通过registerActivityLifecycleCallbacks的方法将截屏的开始监控及取消监控注入到每个activity的生命周期中。将开始监控媒体库方法注入每个activity的onResume中,将停止监控注入每个activity的onPause中,保证activity在展示的时候开始监控截屏,在消失的时候结束对截屏的监控。

application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
   
    override fun onActivityResumed(activity: Activity) {
   
        CoroutineScope(Dispatchers.IO).launch {
   
            startListen(WeakReference(activity))
        }
    }

    override fun onActivityPaused(activity: Activity) {
   
        CoroutineScope(Dispatchers.IO).launch {
   
            stopListen(WeakReference(activity))
        }
    }

    override fun onActivityStarted(activity: Activity) {
   }

    override fun onActivityStopped(activity: Activity) {
   }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
   }

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
   }

    override fun onActivityDestroyed(activity: Activity) {
   }

})

如果不希望这样实现,也可以直接将相关能力注入到需要被监控activity的生命周期中,而不是所有的activity。

在对应的生命周期中实现对媒体库的绑定与解绑。

private fun registerObserver(activity: Activity) {
   
    internalObserver = MediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, uiHandler)
    externalObserver = MediaContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, uiHandler)
    startListenTime = System.currentTimeMillis()
    internalObserver?.let {
   
        activity.applicationContext.contentResolver.registerContentObserver(
            MediaStore.Images.Media.INTERNAL_CONTENT_URI,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值