前言

最近公司领导要求我做一个截屏的功能,说是为了方便监控小屏。本来以为没什么难度,然后就答应了下来。谁知道全都是坑。
这里要说明一点,我这里做的Android程序是 安装在 Android小屏上和机顶盒上的。其次机器都是root过的。然后 机器是自用的。所以,也就不会有 涉及到 隐私什么的。

第一次测试

一开始也没感觉有什么难度于是就写了一个demo

View dView = getWindow().getDecorView();
dView.setDrawingCacheEnabled(true);
dView.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(dView.getDrawingCache());
if (bitmap != null) {try {// 获取内置SD卡路径String sdCardPath = Environment.getExternalStorageDirectory().getPath();// 图片文件路径String filePath = sdCardPath + File.separator + "screenshot.png";File file = new File(filePath);FileOutputStream os = new FileOutputStream(file);bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);os.flush();os.close();DebugLog.d("a7888", "存储完成");} catch (Exception e) {}
}

然后测试了一下,ok没问题可以用。于是,就去找老板说,可以了。然后给他演示了一下。谁知道,接下来他说希望这个截图功能可以运行在后台服务中。当时也没多想,便应了下来 。然后就掉坑里了,差点没爬上来。

第二次测试

getWindow()方法在service中无法正常使用。即使,通过某些手段使其变的可用。然而截下来的图却是黑屏,所以第一种方法不符合要求,pass。
既然自己解决不了,那就查资料吧。在网上查了好久,很多人都推荐使用 “修改并编译源码中的screencap类然后通过JNI来调用这种方法”。然而 我不会 编译源码 这就很尴尬了。第二方法因为个人能力原因,pass。
之后又找到一种方法 “通过反射android.view.Surface类的 screenshot 方法完成截图”

sc = Class.forName("android.view.Surface");
method=sc.getMethod("screenshot", new Class[] {int.class, int.class});
Object o = method.invoke(sc, new Object[]{(int) dims[0],(int) dims[1]});
mScreenBitmap =(Bitmap)o;

虽然说这个方法可以用但是他却存在一个很严重的缺点 只支持4.0~4.2。之后的版本出于安全等方面原因screenshot方法所属的整个类android.view.SurfaceControl都被hide了,所以通过一般的反射是无法调用的。虽然,公司小屏4.0–4.2的Android版本比较多但是高版本的机器也不在少数,然而此方法只能解决部分机型所以不可用,pass。

第三次测试

之后又查了一些其他的资料。比如说Android5.0之后支持了实时录屏的功能。通过实时录屏我们可以拿到截屏的图像。同时可以通过在Service中处理实现后台的录屏。

//初始化数据private void init() {mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);it = mediaProjectionManager.createScreenCaptureIntent();mImagePath = Environment.getExternalStorageDirectory().getPath() + "/jietu/";mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);mWindowWidth = mWindowManager.getDefaultDisplay().getWidth();mWindowHeight = mWindowManager.getDefaultDisplay().getHeight();mImageReader = ImageReader.newInstance(mWindowWidth, mWindowHeight, 0x1, 2);DisplayMetrics displayMetrics = new DisplayMetrics();mWindowManager.getDefaultDisplay().getMetrics(displayMetrics);mScreenDensity = displayMetrics.densityDpi;}
//开始截图private void startCapture() {mImageName = "截图" + System.currentTimeMillis() + ".png";Log.i(TAG, "image name is : " + mImageName);Image image = mImageReader.acquireLatestImage();if (image == null) {Log.e(TAG, "image is null.");return;}int width = image.getWidth();int height = image.getHeight();final Image.Plane[] planes = image.getPlanes();final ByteBuffer buffer = planes[0].getBuffer();int pixelStride = planes[0].getPixelStride();int rowStride = planes[0].getRowStride();int rowPadding = rowStride - pixelStride * width;mBitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);mBitmap.copyPixelsFromBuffer(buffer);mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height);image.close();stopScreenCapture();saveToFile();}private void stopScreenCapture() {if (mVirtualDisplay != null) {mVirtualDisplay.release();mVirtualDisplay = null;}}
//保存图片的功能private void saveToFile() {try {File fileFolder = new File(mImagePath);if (!fileFolder.exists())fileFolder.mkdirs();File file = new File(mImagePath, mImageName);if (!file.exists()) {Log.d(TAG, "file create success ");file.createNewFile();}FileOutputStream out = new FileOutputStream(file);mBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);out.flush();out.close();Log.d(TAG, "file save success ");Toast.makeText(this.getApplicationContext(), "截图成功", Toast.LENGTH_SHORT).show();} catch (IOException e) {Log.e(TAG, e.toString());Toast.makeText(this.getApplicationContext(), "截图失败", Toast.LENGTH_SHORT).show();e.printStackTrace();}}
//在result中处理 获取到的截屏图片@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);if (null != mediaProjection) {mVirtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture", mWindowWidth, mWindowHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null);startCapture();}}

本来是想如果这种方法可行,那么就让老板 更新一波机器。毕竟现在4.0-4.3版本的Android系统机器已经不常见了。还有就是低版本Android系统有局限性。很多新功能,新技术在上面用不了。然而我的想法还是太天真,虽然说实现了Service后台截屏。但是这个方法有个很坑的地方,每次截屏都会跳出一个弹框,必须用户手动点击 “开始截屏” 后才可以用。而且弹框是不能取消的。第四中方法,pass。

第四次测试

经过前几次的失败,说实话我已经想放弃了。这时候突然间想到,Android 的 adb 命令既然说 可以通过 adb 命令进行apk的安装、卸载,app应用的强制打开和关闭。那为什么不能 通过 adb 命令来进行 截屏呢?于是网上搜了一下,你别说还真的可以用。

adb shell screencap -p /sdcard/pic.png  //一句命令搞定

在pc上测试成功后,便开始在Service中进行实验

public static void savecreen(String name) {String cmd="screencap -p /sdcard/pic/"+name+".png";try {// 权限设置Process p = Runtime.getRuntime().exec("su");// 获取输出流OutputStream outputStream = p.getOutputStream();DataOutputStream dataOutputStream = new DataOutputStream(outputStream);// 将命令写入dataOutputStream.writeBytes(cmd);// 提交命令dataOutputStream.flush();// 关闭流操作dataOutputStream.close();outputStream.close();} catch (Throwable t) {t.printStackTrace();}}

经过测试,可用。第五中方法可行。

总结

最后说一点,通过shell 命令进行截屏 操作并不是在 所有的机器上都可行了。首先,你必须要保证你的机器的root的,如果没root一切免谈。当然了,也不是说 root 的机器就一定能用。经过,各Android系统机型的测试。这个方法在Android 8.0及以上的系统 好像并不适用(这里我指的是root的Android手机)。(因为,我们公司Android小屏和机顶盒都是定制的机器,系统也是根据要求刷的并且机器也都是root的。所以并不会出现Android 8.0及以上的系统不适用的问题)。
额,就这样吧。写的比较烂,将就看吧。

Android后台截屏功能相关推荐

  1. android自动截图实现,Android实现截屏功能

    原标题:Android实现截屏功能 该方法主要利用SDK提供的view.getDrawingCache()方法,主要步骤如下: 设置view.setDrawingCacheEnabled(true) ...

  2. android 后台截屏代码,Android实现截图和分享功能的代码

    先给大家展示下效果图吧 直接上代码: xml的布局: android:id="@+id/btn_jp" android:layout_marginTop="10dip&q ...

  3. Android 中截屏功能的实现

    之前写过一个关于截图的功能,但那个是基于咱们控件的截取,如果出了自己的项目,或者层次结构复杂了,一般不好操作了就.今天学习了一个截屏工具的制作方法,在这里记录一下. 我们的代码全部基于Android中 ...

  4. android后台截屏实现(2)--screencap源码修改

    首先找到screencap类在Android源码中的位置,/442/frameworks/base/cmds/screencap/screencap.cpp. 源码如下: [cpp] view pla ...

  5. android后台截屏实现(3)--编译screencap

    修改好之后就要编译了,screencap的编译是要在源码环境中进行的. 将修改后的screencap.cpp文件替换源码中的原始文件,然后修改screencap的Android.mk文件,修改后的文件 ...

  6. android中截屏功能实现,android代码实现截屏功能

    android开发中通过View的getDrawingCache方法可以达到截屏的目的,只是缺少状态栏! 原始界面 截屏得到的图片 代码实现 1. 添加权限(AndroidManifest.xml文件 ...

  7. android代码实现截屏,android实现截屏功能代码

    2. 添加1个Button(activity_main.xml文件) xmlns:tools="http://schemas.android.com/tools" android: ...

  8. android自定义截图,Android实现截屏功能

    该方法主要利用SDK提供的view.getDrawingCache()方法,主要步骤如下: 设置view.setDrawingCacheEnabled(true) 调用view.buildDrawin ...

  9. android调用截屏功能,调用安卓原生的截图功能

    做app的时候经常会遇到头像上传截图这样的功能,截取一个图片网上有不少demo,很复杂,其实安卓本身就自带了一个强大好用的截图功能,比如更换壁纸的时候,你就会看到这个截图功能,下面是调用系统的截图功能 ...

最新文章

  1. java web中文乱码处理笔记
  2. 一直想测试的NGINX变量输出,最于有办法了。
  3. 设置root密码,su与sudo的区别
  4. C#中LINQ技术的简单小例
  5. javascript 将内容复制到剪贴板
  6. Vue中的 computed 和 watch的区别
  7. ABP从入门到精通(2):aspnet-zero-core 使用MySql数据库
  8. xsi:schemaLocation=http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd报...
  9. php new static 效率,PHP中new static()与new self()的比较
  10. 服务器无法拖动文件复制文件,​IT服务器运维:艾锑人为您整理Win10系统下移动、复制、删除文件需要管理员权限的解决方法...
  11. 日本要向中国收二维码使用费?每人一分钱?
  12. SDL2源代码分析7:显示(SDL_RenderPresent())
  13. JAVA 调用NetDraw((*^__^*) 嘻嘻……)
  14. redis 菜鸟教程中脚本笔记
  15. 社群就是微信群吗?社群的本质是什么?
  16. UBUNTU系统设置窗口打不开解决办法(精)
  17. 春夜宴诸从弟桃李园序 李白
  18. 面试官:如何用a标签实现文件下载?(一文带你手撕知识点)
  19. 怎么能看出来一个人善不善良?
  20. 一段顺序颠倒能读通的文字_专家解释汉字顺序不影响阅读--人脑自动排序

热门文章

  1. 用java的输出姓名_用java程序输出自己的姓名
  2. 企业在进行新闻营销时如何才能打造爆点?
  3. 防火墙——IPSec协议框架(IPSec1)
  4. java 设计音乐播放器设计与实现_基于java的音乐播放器的设计(源代码+实验报告)...
  5. QC协议2.03.04.0区别
  6. OnsenUI-页面切换
  7. 一文带你深入理解 Spring 事务原理
  8. JS获取当前时间(24小时制)
  9. nacos 注册python bottle服务,一会儿服务就不健康了
  10. Fear the REAPER A System for Automatic Multi-Document Summarization with Reinforcement Learning