最近项目中新接到一个需求,对手机截屏进行检测并进行后续操作,类似于Snapchat,iOS具有先天优势,因iOS系统提供了相关API!Google无果之后原作者决定再次造轮子,为了持续表达对Rx的敬意,命名为RxScreenshotDetector, github 源码地址 。

效果有图有真相

原理

安卓系统并没有提供任何截屏检测相关的API,网上针对Snapchat的这项功能进行了分析,大致猜测可能有以下几种途径:

  • 使用FileObserver,监听Screenshots目录下的文件变化;

  • 使用ContentObserver,监听MediaStore.Images.Media.EXTERNAL_CONTENT_URI资源的变化;

  • 重载(hook)截屏组合键(不靠谱),有的机型使用的是特殊手势进行截屏;

主要参考了 StackOverflow上面的这个回答 。

核心代码如下:

private static final String TAG = "RxScreenshotDetector";
private static final String EXTERNAL_CONTENT_URI_MATCHER =
MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString();
private static final String[] PROJECTION = new String[] {
MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DATE_ADDED
};
private static final String SORT_ORDER = MediaStore.Images.Media.DATE_ADDED + " DESC";
private static final long DEFAULT_DETECT_WINDOW_SECONDS = 10; final ContentResolver contentResolver = context.getContentResolver();
final ContentObserver contentObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.d(TAG, "onChange: " + selfChange + ", " + uri.toString());
if (uri.toString().matches(EXTERNAL_CONTENT_URI_MATCHER)) {
Cursor cursor = null;
try {
cursor = contentResolver.query(uri, PROJECTION, null, null,
SORT_ORDER);
if (cursor != null && cursor.moveToFirst()) {
String path = cursor.getString(
cursor.getColumnIndex(MediaStore.Images.Media.DATA));
long dateAdded = cursor.getLong(cursor.getColumnIndex(
MediaStore.Images.Media.DATE_ADDED));
long currentTime = System.currentTimeMillis() / 1000;
Log.d(TAG, "path: " + path + ", dateAdded: " + dateAdded +
", currentTime: " + currentTime);
if (path.toLowerCase().contains("screenshot") &&
Math.abs(currentTime - dateAdded) <=
DEFAULT_DETECT_WINDOW_SECONDS) {
// screenshot added!
}
}
} catch (Exception e) {
Log.d(TAG, "open cursor fail");
} finally {
if (cursor != null) {
cursor.close();
}
}
}
super.onChange(selfChange, uri);
}
};
contentResolver.registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, contentObserver);

RxScreenshotDetector.java hosted with ❤ by  GitHub

主要有以下几点需要注意:

  • 权限,读取资源的时候需要READ_EXTERNAL_STORAGE权限,这里我使用了 RxPermissions 来以reactive的方式请求权限;

  • 从ContentResolver查询资源的时候,需要按照资源创建时间降序排列,针对最新的一个资源判断是否为截屏的图片,为contentResolver.query的最后一个参数传递MediaStore.Images.Media.DATE_ADDED + " DESC"即可,而判断图片是否为截图则比较简单,路径包含screenshot关键字,且添加时间在10s之内;

使用示例

RxScreenshotDetector完整使用代码如下:

RxScreenshotDetector.start(getApplicationContext())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.<String>bindUntilEvent(ActivityEvent.PAUSE))
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) {
e.printStackTrace();
} @Override
public void onNext(String path) {
mTextView.setText(mTextView.getText() + "\nScreenshot: " + path);
}
});

这里使用了 RxLifecycle ,在Activity onPause之后unsubscribe,以保证不会发生内存泄漏。此外subscribe传入的是完整的Subscriber,是为了防止授权失败时没有onError处理器,导致crash。

Android 截屏检测的更多相关文章

  1. Android截屏的几种实现

    Android截屏的几种实现 微信公众号:CodingAndroid CSDN:http://blog.csdn.net/xinpengfei521 最近我们的APP要求需要截屏功能,网上看了看大致有 ...

  2. 【转】Android截屏

     http://blog.csdn.net/xww810319/article/details/17607749 Android截屏浅析 链接:http://blog.sina.com.cn/s/bl ...

  3. android截屏

    截屏是一个常用的操作,经常会有这种需求. 截屏的工具类 package com.fxb.screenshot; import android.app.Activity; import android. ...

  4. Android 截屏与 WebView 长图分享经验总结

    最近在做新业务需求的同时,我们在 Android 上遇到了一些之前没有碰到过的问题,截屏分享. WebView 生成长图以及长图在各个分享渠道分享时图片模糊甚至分享失败等问题,在这过程中踩了很多坑,到 ...

  5. Android 截屏的各种骚操作

    本文公众号「AndroidTraveler」首发. 背景 在实际的应用场景中,Android 手机的截屏其实是很普遍的. 比如说 PPT 演示,比如说技术博客图文并茂讲解. 因此懂得 Android ...

  6. android截屏:保存一个view的内容为图片并存放到SD卡

    项目中偶尔会用到截屏分享,于是就有了下面这个截屏的方法~ 下面得saveImage()方法就是保存当前Activity对应的屏幕所有内容的截屏保存. private void saveImage() ...

  7. 快速简化Android截屏工作

    1.安装Notepad++v6.9 2.插件管理器里Plugin Manager安装AndroidLogger 3.AndroidLogger里的capture功能抓取Android的当前屏幕截图到w ...

  8. Android手机截屏

    刚开始打算做一个简单的截屏程序时,以为很轻松就能搞定. 在Activity上放一个按钮,点击完成截屏操作,并将数据以图片形式保存在手机中. 动手之前,自然是看书和网上各种查资料.结果发现了解的知识越多 ...

  9. Android开发笔记:安卓程序截屏方法

    1,基于Android SDK的截屏方法 (1)主要就是利用SDK提供的View.getDrawingCache()方法.网上已经有很多的实例了.首先创建一个android project,然后进行L ...

随机推荐

  1. python基础之多线程与多进程(二)

    上课笔记整理: 守护线程的作用,起到监听的作用 一个函数连接数据库 一个做守护线程,监听日志 两个线程同时取一个数据 线程---->线程安全---->线程同时进行操作数据. IO操作--- ...

  2. New Concept English three (32)

    26w/m 68 The salvage operation had been a complete failure. The small ship, Elkor, which had been se ...

  3. Arcgis for javascript map操作addLayer详解

    本节的内容很简单,说说Arcgis for Javascript里面map对象的addLayer方法.在for JS的API中,addLayer方法有两种,如下图: addLayer方法 在addLa ...

  4. (二)java环境搭建

    Java运行环境的搭建: 什么是JRE,什么是JDK? JRE:(java运行环境)包括jvm(java虚拟机)和java运行的核心类库,如果只是运行java程序,只需安装JRE JDK:(java开 ...

  5. Storm开发过程中的问题与建议

    转自:http://blog.csdn.net/ouyang111222/article/details/50061305 (一) topology层级建议设不要设置过多 storm讲究是流式计算,s ...

  6. 复制的web工程为什么不能部署到tomcat

    An existing resource has been found at location D:\apache-tomcat-6.0.18\apache-tomcat-6.0.18\webapps ...

  7. avalon 总线时序关系理解

    对于读,等待时间指的是从端口捕获数据的时间相对于read信号的延时 建立时间指的是read信号相对于chipselect和addr的延时时间 对于写,等待时间指的是相对于非等待情况下各个信号的延时时间 ...

  8. 【java规则引擎】一个基于drools规则引擎实现的数学计算例子

    最近在研究JBPM工作流引擎,发现JBPM是基于Drools的,官方文档查看得知Drools是一款规则引擎.兴趣之下,仔细了解了下 Drools,Drools作为JBoss出品的一款开源推理和规则引擎 ...

  9. SublimeText3常用插件安装与使用

    packagecontroller的安装 https://packagecontrol.io/ 安装了它就可以更好的进行插件的安装和管理 复制代码,打开控制面板[ctrl+·]将代码拷贝,即可进行安装 ...

  10. rac ASM下最简单归档开启/关闭方法

    原创作品,出自 “深蓝的blog” 博客,深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/47172639本次先来介绍一下在rac环 ...