IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android后台截屏方案选型与实现 -> 正文阅读

[移动开发]android后台截屏方案选型与实现

问题场景

在通过辅助功能获取用户等级的时候,发现他们对用户等级采取了非常与众不同的方案,当然该方案有效地阻挡了我的直接获取。

大家可以看到有 荣誉等级 但是无法获取到下面的20的view

解决方案

为了获取这个等级,直接获取肯定是不行了,只能选择曲线救国。

一个大胆的想法出现在脑海中,

截图,然后识别数字

从理论上讲这是一个可行的方案。

显而易见该方案有两个步骤

1、截图

2、识别

因为识别还没有找到完美的解决方案,就先写下截图的事情。

选型

补充个背景知识,辅助服务和被监控的应用是没有办法直接沟通的,需要有系统帮助。

候选方案有以下几个:

方案名优点缺点备注
view.getDrawingCache()系统提供方案,可以准确获取bitmap需要先获取到对应的view因为无法获取到目标应用的view对象,方案排除
adb可以直接获取到所有场景下的view需要adb权限,权限不好获取,并且一些rom上隔一段时间需要重新授权不能保障adb权限的获取,方案排除
Accessibility CAPABILITY_CAN_TAKE_SCREENSHOT系统自带能力api30可用因为api要求太高,方案排除
模拟系统截图方法系统方法不同机型实现的方案不一样,存在兼容性问题因为兼容成本问题,方案排除
MediaProjectionManager系统方案需要用户授权因为是自用,权限可控,系统方案稳定,入选

实现 MediaProjectionManager 方案

  1. 获取MediaProjectionManager服务实例

mediaProjectionManager?=?(MediaProjectionManager)?getSystemService(MEDIA_PROJECTION_SERVICE);
  1. 通过MediaProjectionManager创建请求屏幕捕捉的隐式Intent,发送到目标Activity。这时会显示一个弹窗,“xxx将开始截取您屏幕上显示的所有内容”,申请用户同意。

?Intent?intent?=?new?Intent(mediaProjectionManager.createScreenCaptureIntent());
?startActivityForResult(intent,?REQUEST_CODE);
  1. 在发送方Activity的onActivityResult(int requestCode, int resultCode, Intent data)处理请求结果,若用户同意了请求,就可以通过返回的结果获取MediaProjection对象执行后面的流程进行屏幕画面捕捉

????@Override
????protected?void?onActivityResult(int?requestCode,?final?int?resultCode,?final?Intent?data)?{
????????super.onActivityResult(requestCode,?resultCode,?data);
????????if?(REQUEST_CODE?==?requestCode)?{
????????????
????????????//通过返回的结果获取MediaProjection对象执行后面的流程进行屏幕画面捕捉
????????????MediaProjection?mediaProjection?=?mediaProjectionManager.getMediaProjection(resultCode,?data);
????????????//创建用于接收投影的容器
????????????mImageReader?=?ImageReader.newInstance(mWidthPixels,?mHeightPixels,?PixelFormat.RGBA_8888,?2);
????????????//通过MediaProjection创建创建虚拟显示器对象,创建后物理屏幕画面会不断地投影到虚拟显示器VirtualDisplay上,输出到虚拟现实器创建时设定的输出Surface上。
????????????VirtualDisplay?mVirtualDisplay?=?mediaProjection.createVirtualDisplay("mediaprojection",?mWidthPixels,?mHeightPixels,
????????????????????mDensityDpi,?DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,?mImageReader.getSurface(),?null,?null);
????????????//从容器中获取image
????????????Image?image?=?mImageReader.acquireLatestImage();
????????????//获取bitmap
????????????if?(image?!=?null)?{
????????????????final?Image.Plane[]?planes?=?image.getPlanes();
????????????????if?(planes.length?>?0)?{
????????????????????final?ByteBuffer?buffer?=?planes[0].getBuffer();
????????????????????int?pixelStride?=?planes[0].getPixelStride();
????????????????????int?rowStride?=?planes[0].getRowStride();
????????????????????int?rowPadding?=?rowStride?-?pixelStride?*?mWidthPixels;
????????????????????Bitmap?bitmap?=?Bitmap.createBitmap(mWidthPixels?+?rowPadding?/?pixelStride,?mHeightPixels,?Bitmap.Config.ARGB_8888);
????????????????????bitmap.copyPixelsFromBuffer(buffer);
????????????????????image.close();

????????????????}
????????????}

????????}
????}

整个代码进行拆解

3.1. 获取用户授权后的MediaProjection对象,用来处理后续的屏幕捕获

3.2. 创建用于接收投影的容器

3.3. 通过MediaProjection对象创建虚拟显示器VirtualDisplay,并将内容不断投影到3.2中创建的容器中的Surface上

3.4. 从3.2的容器中获取image对象

3.5. 从3.4的image对象中获取bitmap

至此,在当前页面截图的功能实现。

等等,我们是想要在后台截图的!!!

升级为后台截图

后台截图有两个方案

  1. 通过service来实现,在前台实现一个悬浮框,然后在上面操作

  2. 通过全局工具类来实现

因为我这个是要给辅助服务使用的,所以方案1不是我想要的,我就实现了方案2

后台截图工具类

  1. 将image对象传给工具类

????public?static?void?setmImageReader(Activity?activity,ImageReader?mImageReader)?{
????????ShotScreenUtil.mImageReader?=?mImageReader;
????}
  1. 创建截图方法

????public?static?Bitmap?getSystemScreenBitmap(int?dx,int?dy,int?w,int?h)?{

????????Image?image?=?mImageReader.acquireLatestImage();
????????if?(image?!=?null)?{
????????????final?Image.Plane[]?planes?=?image.getPlanes();
????????????if?(planes.length?>?0)?{
????????????????final?ByteBuffer?buffer?=?planes[0].getBuffer();
????????????????int?pixelStride?=?planes[0].getPixelStride();
????????????????int?rowStride?=?planes[0].getRowStride();
????????????????int?rowPadding?=?rowStride?-?pixelStride?*?mWidthPixels;
????????????????Bitmap?bitmap?=?Bitmap.createBitmap(mWidthPixels?+?rowPadding?/?pixelStride,?mHeightPixels,?Bitmap.Config.ARGB_8888);
????????????????bitmap.copyPixelsFromBuffer(buffer);
????????????????image.close();
????????????????return?Bitmap.createBitmap(bitmap,dx,dy,w,h);
????????????}
????????}
????????return?null;
????}
  1. 简单来说就是将前台截图方案中的截图方法给移到了工具类中,这样在任何地方都可以获取到截图了

总结

遇到问题有时候可以绕一下。如果有多个方案备选,就做下对比,贴合自己的业务选择一个认为最优的方案去尝试、优化。最终总可以找到一个自己想要的方案。

关注公众号: arigeweixin ,取得更多联系

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 19:00:48  更:2022-07-20 19:02:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 3:51:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码