Android 截屏监听(截图分享功能)

一、需求背景

如果检测到用户在 app 中有截图行为,那么弹出一个分享提示框,提示用户去分享这个截图。

本文主要从三个方面来讲:

1、截图检测的具体实现

2、截图检测踩到的坑

3、截图合成

二、截图分享实现

1、截图分享实现分为两个部分,首先是截图事件的监听。安卓系统并没有提供 api 来监听系统截图事件,也没有什么广播可以用来监听这类事件,那要

怎么解决呢?我们先来看下截图源码。

两个类都在目录framework/base/package/SystemUI/src/com/android/systemui/screenshot 下

从代码里可以看到,截图之后做的主要事情是:

a、保存截屏 Bitmap 到本地文件

b、把图片记录插入到 ContentProvider 中

c、发送一个截图相关的 Notification

那么看到这里,我们大致可以想到两种用来监听截图事件的方式:

监听 ContentProvider 数据改变

监听截图文件目录数据改变

监听截图事件的三种方式

2、截图检测遇到的问题

坑1:监听截图事件的三种方式,这个方法有个问题就是:无法监听到通知栏中提供的截图按键。

坑2:TakeScreenshotService 所运行的进程名为 com.android.systemui.screenshot这个方法在主流的 ROM 上经过测试,目前没有发现问题,

但是这个方案最终没有用在App上,主要担心的就是某些奇葩的国产 ROM 把进程名给改了,导致这个函数判断出错。

坑3:其次是截图文件获取的问题,从之前的系统源码里我们看到,GlobalScreenShot 截图之后,做的工作首先是保存图片,然后再去修改图片数

据库,所以在某些没有大改的系统里,我们在 ContentObserver 的 onChange 回调里是可以获取到图片文件的。但是后来在魅族的系统上测试时,

发现在 onChange 里 获取不到图片文件,大概原因猜测就是魅族把这部分的源码修改了,先通知数据库改变,再保存文件。

要解决这个问题,大概有两种办法:

  1. FileObserver 监听文件写完成事件,我们只要监听 CLOSE_WRITE 即可

坑4:按照剧本来说,这里的代码大概是没有问题的,然后放到魅族系统上测试了一下,只监听到了 CREATE 事件,这个方案被迫放弃。

2.轮询+延迟

坑5:因为某些魅族手机保存有延迟 , 轮询与延迟,设置最大等待时间500ms

坑6:要判断是否是截屏,有可能是用户自己再文件夹中添加了一张图片

坑7:个别手机会自己修改截图文件夹的文件, 截屏功能会误以为是用户在截屏操作,进行捕获。 所以加了一个时间判断

坑8:部分机器写入截图实在是太慢,给个800ms延迟去通知显示分享

三、终上所述,两种方案实现截屏监听分享:

方案1:监听截图文件目录数据改变。

继承FileObserver类,筛选择出手机截屏文件夹,监听截屏文件事件变化,由于某些魅族手机保存有延迟且某些魅族系统上只监听到了CREATE事

件,那么同时监听CLOSE_WRITE(8)、CREATE(256)事件分别做特殊处理;

方案2:监听 ContentProvider 数据改变。

继承ContentObserver类,在handleMediaContentChange方法内处理数据。主要注意点:1、要判断是否是截屏,有可能是用户自己再文件夹中添

加了一张图片;2、个别手机会自己修改截图文件夹的文件, 截屏功能会误以为是用户在截屏操作,进行捕获。 所以加一个时间判断;

四、图片合成

截图图片合成主要做的工作大概就是图片的大小控制了。假如我们把全质量的截图读取到内存中,那么对于小屏幕手机来说,可能影响不大,但

是对于配有2k屏的手机来说,这就是一场灾难了。

坑10:注意bitmap oom

坑11:若需求要去掉顶部状态栏和底部栏

总结:

最终我采用方案1完美实现截图分享功能。

拿来即用,项目GitHub地址 ScreenshotsShare,喜欢关注一个吧。

一个变种需求:H5截屏监听分享功能

同理:App本地利用上述方式监听截图,发送特定指令给H5(需两端提前约定指令\回调方法)即可

25人点赞
技术文档

作者:程序员大耳
链接:https://www.jianshu.com/p/9e9e7545f0b4

结语

以上这篇文章的全部内容了,感谢各位的阅读,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎扫描关注博主一起学习!!

还有一些学习福利送给大家,有需要可扫描下方二维码免费领取

由于篇幅有限,这里以图片的形式给大家展示一小部分。

详细整理扫描下方二维码直接领取;

Android架构视频+BAT面试专题PDF+学习笔记

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
监听 Android 相机应用的拍照和截图事件,可以使用 CameraManager 和 MediaScannerConnection 类。下面是一个示例代码,它可以在 Android监听相机应用的拍照和截图事件: ```java public class CameraListenerService extends Service { private CameraManager cameraManager; private String cameraId; private CameraDevice cameraDevice; private ImageReader imageReader; private MediaScannerConnection scannerConnection; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { cameraId = cameraManager.getCameraIdList()[0]; imageReader = ImageReader.newInstance(1, 1, ImageFormat.JPEG, 1); imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Image image = null; try { image = reader.acquireLatestImage(); if (image != null) { // 处理图片 // ... scannerConnection = new MediaScannerConnection(getApplicationContext(), new MediaScannerConnection.MediaScannerConnectionClient() { @Override public void onMediaScannerConnected() { scannerConnection.scanFile(imageFileName, "image/jpeg"); } @Override public void onScanCompleted(String path, Uri uri) { scannerConnection.disconnect(); } }); scannerConnection.connect(); } } catch (Exception e) { e.printStackTrace(); } finally { if (image != null) { image.close(); } } } }, null); cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { cameraDevice = camera; try { final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(imageReader.getSurface()); captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); cameraDevice.createCaptureSession(Collections.singletonList(imageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { session.capture(captureBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(CameraDevice camera) { if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } } @Override public void onError(CameraDevice camera, int error) { if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } } }, null); } catch (Exception e) { e.printStackTrace(); } } @Override public void onDestroy() { super.onDestroy(); if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } if (scannerConnection != null) { scannerConnection.disconnect(); } } } ``` 这个示例代码中,我们创建了一个 Service,并在 onCreate() 方法中监听拍照和截图事件。我们使用 CameraManager 获取相机设备,并使用 CameraDevice 和 CaptureRequest.Builder 对象来实现拍照和截图。我们还使用 ImageReader.OnImageAvailableListener 监听 ImageReader 对象,以便在图片准备好时处理它们。最后,我们使用 MediaScannerConnection 类来将图片添加到系统媒体库中。 请注意,这个示例代码仅仅是一个简单的示例,它可能无法满足所有情况。在实际使用中,您可能需要对代码进行修改和优化以满足您的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值