当前位置:   article > 正文

android 应用内页面,截屏监听

android 应用内页面,截屏监听

公司的项目由于安全需要,对某一特定的页面需要监听是否被用户截屏了。

简单搜了一下,很少有这方面的问题,没办法,只能自己折腾了。


目前想到三种思路:

1、监听广播

当然,前提是系统在截屏的时候发送某一广播,然而并没有。


2、监听按键

android手机按下“电源键+音量减”会进行截屏,此外大部分手机状态栏下拉的页面中也会有截屏按钮。遗憾的是,监听这两处的操作并不是一件让人开心的事儿~~。


3、监听手机中图片的变化

开始只想到了MediaStore这个类,可以通过它拿到手机中的所有图片,每隔一段时间监听图片数量。这似乎是个不错的主意,直到我转角遇到了ContentObserver。

从名字就可以知道,它是一个内容观察者。通过给ContentProvider注册ContentObserver,可以实现对数据的监听。


  1. public class ScreenshotContentObserver extends ContentObserver {
  2. private Context mContext;
  3. private int imageNum;
  4. private static ScreenshotContentObserver instance;
  5. private ScreenshotContentObserver(Context context) {
  6. super(null);
  7. mContext = context;
  8. }
  9. public static void startObserve() {
  10. if (instance == null) {
  11. instance = new ScreenshotContentObserver(Facade.context());
  12. }
  13. instance.register();
  14. }
  15. public static void stopObserve() {
  16. instance.unregister();
  17. }
  18. private void register() {
  19. mContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, this);
  20. }
  21. private void unregister() {
  22. mContext.getContentResolver().unregisterContentObserver(this);
  23. }
  24. @Override
  25. public void onChange(boolean selfChange) {
  26. super.onChange(selfChange);
  27. String[] columns = {
  28. MediaStore.MediaColumns.DATE_ADDED,
  29. MediaStore.MediaColumns.DATA,
  30. };
  31. Cursor cursor = null;
  32. try {
  33. cursor = mContext.getContentResolver().query(
  34. MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
  35. columns,
  36. null,
  37. null,
  38. MediaStore.MediaColumns.DATE_MODIFIED + " desc");
  39. if (cursor == null) {
  40. return;
  41. }
  42. int count = cursor.getCount();
  43. if (imageNum == 0) {
  44. imageNum = count;
  45. } else if (imageNum >= count) {
  46. return;
  47. }
  48. imageNum = count;
  49. if (cursor.moveToFirst()) {
  50. String filePath = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
  51. long addTime = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED));
  52. if (matchAddTime(addTime) && matchPath(filePath) && matchSize(filePath)) {
  53. doReport(filePath);
  54. }
  55. }
  56. } catch (Exception e) {
  57. e.printStackTrace();
  58. } finally {
  59. if (cursor != null) {
  60. try {
  61. cursor.close();
  62. } catch (Exception e) {
  63. e.printStackTrace();
  64. }
  65. }
  66. }
  67. }
  68. /**
  69. * 添加时间与当前时间不超过1.5s,大部分时候不超过1s。
  70. *
  71. * @param addTime 图片添加时间,单位:秒
  72. */
  73. private boolean matchAddTime(long addTime) {
  74. return System.currentTimeMillis() - addTime * 1000 < 1500;
  75. }
  76. /**
  77. * 尺寸不大于屏幕尺寸(发现360奇酷手机可以对截屏进行裁剪)
  78. */
  79. private boolean matchSize(String filePath) {
  80. Point size = Util.getScreenWidthAndHeight(mContext);//获取屏幕尺寸
  81. BitmapFactory.Options options = new BitmapFactory.Options();
  82. options.inJustDecodeBounds = true;
  83. BitmapFactory.decodeFile(filePath, options);
  84. return size.x >= options.outWidth && size.y >= options.outHeight;
  85. }
  86. /**
  87. * 已调查的手机截屏图片的路径中带有screenshot
  88. */
  89. private boolean matchPath(String filePath) {
  90. String lower = filePath.toLowerCase();
  91. return lower.contains("screenshot");
  92. }
  93. private void doReport(String filePath) {
  94. //删除截屏
  95. File file = new File(filePath);
  96. file.delete();
  97. //TODO:
  98. }
  99. }

上面通过register()和unregister()两个静态方法进行监听器的注册和反注册。建议在onStart()方法中进行注册,在onStop()方法中进行反注册,因为截屏并不会引起当前页面生命周期的变化。

在onChange()回调方法中,通过查询,拿到最近添加的那张图片,从创建时间、尺寸、路径3个方面进行匹配,判断是否是截屏图片。

  • 创建时间:大多时候,截屏图片的创建时间和当前系统时间不超过1000ms
  • 图片尺寸:大多数手机截屏之后,直接保存图片,所以尺寸和屏幕尺寸一致。但有些手机,比如360奇酷手机,截屏后允许用户裁剪。所以图片尺寸的判断放宽到不大于屏幕尺寸
  • 图片路径:目前,大多数手机的截屏路径中包含“screenshot”,还未发现例外

匹配成功后,就可以在doReport中做自己想做的事了~~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/418785?site
推荐阅读
相关标签
  

闽ICP备14008679号