截屏 多难未遂

     看到未遂,就知道这只是一篇分享感受的文章,但是,或多或少,有过同样过程的人至少会有一点同感。。或有一点思路以及灵感。

     其实网上关于截屏的demo很多,以及思路也很多。我也不知道自己是哪里出了问题,总是未遂。

    但是还是有几个值得注意的:

    不管什么FrameBuffer呀,还是Android源码里面截屏的ScreenShot。。还是ScreenControll。。。and。。。这里要去掏Android更深,更底层或是最原始的都是需要root的。。。但是,本人root真不是很在行。

    开始,我问了很多大神,他们都说Android屏幕绝对来截到。。但是,,,等他们看到我应用的界面的时候,然后我将我的应用代码与他们所说的截屏代码放在一起的时候,oho。。。没戏了。不能,所谓的截屏也只能截到此界面的背影。要不,代码上起,堪忧大神能解不:

    if (null == mContext) {

            mContext = getApplicationContext();

        }
        MyApplication.getInstance().addActivity(this);
        webView = new WebView(mContext);
        android.view.ViewGroup.LayoutParams params = new LayoutParams(
                android.view.ViewGroup.LayoutParams.MATCH_PARENT,
                android.view.ViewGroup.LayoutParams.MATCH_PARENT);
        webView.setLayoutParams(params);
        windowsMan = (WindowManager) getApplicationContext().getSystemService(
                Context.WINDOW_SERVICE);
        WindowManager.LayoutParams vmParams = new WindowManager.LayoutParams();
        // TYPE_PHONE TYPE_SYSTEM_ERROR

        vmParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
        vmParams.format = PixelFormat.RGBX_8888;
        vmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE
                | LayoutParams.FLAG_NOT_TOUCHABLE;
        vmParams.gravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL;
        vmParams.x = 0;
        vmParams.y = 0;
        vmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        vmParams.height = WindowManager.LayoutParams.MATCH_PARENT;
        if (webView.getParent() == null) {
            windowsMan.addView(webView, vmParams);

        }

当当。。能知道是什么原因阻碍了我们的截屏吗?bingo,就是WindowManager,我用的是系统谈错误消息的那一层,如果我没有记错的话,这应该是窗口的第一层,而且,我还用了not touch这个属性,也就是这个界面只要我没让他死亡,你是拿他无可奈何的,他会一直浮在界面的上层。。遮盖了其他的界面。所以,若果大神不小心看见了,然后会解的话。。。。希望不吝赐教哦!

当然,我们往往截屏会使用一种很简单的方法,如果截屏在此次任务中没有显得那么重要的话。

    private void CutImage() {
        cur_Time = System.currentTimeMillis() / 1000;

        if (null == isSdcard()) {
            Toast.makeText(this, "内存卡不存在", Toast.LENGTH_SHORT).show();
        } else {
            Path = isSdcard() + fileName;
            String SavePath = Path + mId + "_" + cur_Time + ".jpg";
            bmp = shot();
            File pathFile = new File(Path);
            if (!pathFile.exists()) {
                System.out.println("mkdir");
                pathFile.mkdir();
            }
            File file = null;
            try {

                file = new File(SavePath);
                if (!file.exists()) {
                    file.createNewFile();
                    System.out.println("createNewFile");
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(file);

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (null != fos) {
                bmp.compress(Bitmap.CompressFormat.PNG, 90, fos);
                System.out.println("compress");
                try {
                    fos.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    fos.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {

            }

        }
    }

    /**
     * 截屏方法
     * 
     * @return
     */
    private Bitmap shot() {
        View view = getWindow().getDecorView();
        Display display = this.getWindowManager().getDefaultDisplay();
        view.layout(0, 0, display.getWidth(), display.getHeight());
        view.setDrawingCacheEnabled(true);// 允许当前窗口保存缓存信息,这样getDrawingCache()方法才会返回一个Bitmap
        Bitmap bmp = Bitmap.createBitmap(view.getDrawingCache());
        return bmp;
    }

    /**
     * 先判断是否有SD卡
     * */
    private String isSdcard() {
        File sdcardDir = null;
        boolean isSDExist = Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED);
        if (isSDExist) {
            // 如果存在SDcard 就找到跟目录
            sdcardDir = Environment.getExternalStorageDirectory();
            return sdcardDir.toString();
        } else {
            return null;
        }
    }

上面的就是一个得到截屏,然后保存的写法,下面这个可以选择去掉标题栏。

   
import java.io.File;  
import java.io.FileNotFoundException;  
import java.io.FileOutputStream;  
import java.io.IOException;  
   
import android.app.Activity;  
import android.graphics.Bitmap;  
import android.graphics.Rect;  
import android.view.View;  
   
public class ScreenShot {  
   
    private static Bitmap takeScreenShot(Activity activity) {  
        // View是你需要截图的View  
        View view = activity.getWindow().getDecorView();  
        view.setDrawingCacheEnabled(true);  
        view.buildDrawingCache();  
        Bitmap b1 = view.getDrawingCache();  
   
        // 获取状态栏高度  
        Rect frame = new Rect();  
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);  
        int statusBarHeight = frame.top;  
   
        // 获取屏幕长和高  
        int width = activity.getWindowManager().getDefaultDisplay().getWidth();  
        int height = activity.getWindowManager().getDefaultDisplay()  
                .getHeight();  
        // 去掉标题栏  
        Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height  
                - statusBarHeight);  
        view.destroyDrawingCache();  
        return b;  
    }  
   
    private static void savePic(Bitmap b, File filePath) {  
        FileOutputStream fos = null;  
        try {  
            fos = new FileOutputStream(filePath);  
            if (null != fos) {  
                b.compress(Bitmap.CompressFormat.PNG, 100, fos);  
                fos.flush();  
                fos.close();  
            }  
        } catch (FileNotFoundException e) {  
            // e.printStackTrace();  
        } catch (IOException e) {  
            // e.printStackTrace();  
        }  
    }  
   
    public static void shoot(Activity a, File filePath) {  
        if (filePath == null) {  
            return;  
        }  
        if (!filePath.getParentFile().exists()) {  
            filePath.getParentFile().mkdirs();  
        }  
        ScreenShot.savePic(ScreenShot.takeScreenShot(a), filePath);  
    }  
}

以上两个代码都差不多而已。

所以,当我选择想要放弃截取当前这个应用的时候,想要自己打开一个服务,然后再后台定时扑捉界面,然后保存到一个我给定的目录下面,以便我能确认。所以,就动手在网上搜了一大堆关于标签是“android中实现后台截屏”,结果,得知的基本上是手机需要root或者这个程序需要root。我是哭的心都有了。本人自知自己水平连菜鸟都还不如,怎么会很快的吧程序给root了呢?说道root,曾经我也是试过很多方法。什么为了编译源码,使用NDK,什么在注册文件里面添加哈桑UId属性啦,或者在Android.mk里面添加

LOCAL_CERTIFICATE := platform

这样一句话呀,我算是折腾呀。但是,程序员就这宿命。

Notice:以前我一直认为,Android.mk需要每次把自己root权限的项目亲自给生成。但是,后来,我请教了一个我认为是大神的人,他告诉我,Android.mk可以直接从其他项目里面给copy过来。只要改几个地方就okay。嘿嘿

只要将:

LOCAL_PACKAGE_NAME 

给一个给自己本项目的name即可,没什么特殊要求。不知道我理解错没。

后来知道原来,Android‘一直默默在底层安装了一个缓存帧的小把戏。。呵呵,那就是FrameBuffer,但是,知道了又怎么样呢。因为这个还是需要一个root了的手机。而且,现在手机的多样化以及很多喜欢自己改装,所以导致FrameBuffer花屏呀,或者是他缓存的路径不对("/dev/graphics/fb0")都是可能的。

但是,还是为了能方便起见,还是把代码给出来吧。在我的文件里面的“FrameBuffer截屏.jar”里面也可以直接给看到:

当然,这里会有更直接的链接,我觉得够料哦!

http://pan.baidu.com/s/1jG43QfW

然后哦还有基于源码的截屏,我也直接给链接了吧:

http://blog.csdn.net/buptgshengod/article/details/21958183

当然,这里还有SurfaceControl.java的链接:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/view/SurfaceControl.java/

有时候下载一个关于什么的资料或者Demo真够费我的小币的。所以,这里有一些关于截屏的demo:我给出了链接:

http://pan.baidu.com/s/1o6HSXOQ

。。。先就将这些外界来的信息写到这里吧。

毕竟我想要的是一个可以直接启动一个服务,然后来在后台打开这个程序的,然后运行截屏的。然后就考虑了一个不用root权限的。也就是DDMS原理的。但是也跟网上有朋友交流过,他们说这个方法行不通。但是,还是写了,但是。。。。在导入jar包的时候,总是报一个让我无法理解的错误。

[2014-11-19 01:08:39 - TakeSrenn] Conversion to Dalvik format failed with error 1

这个错误真的是让我无法理解。网上也查了很多,除了我没哟升级SDK外,其余的都检查了。而且,我觉得我的SDK已经可以不用升级了。

还有这里需要的dt.jar已经rt.jar都在jdk以及jre下面就可以找到。

但是就是这个dt.jar和rt.jar导入就报这样的错误。ddmlib.jar都不会引起。

这里还是把这个给贴出来。后台开启一个程序,然后定时去执行截屏。但是添加三面提到的三个包就okay。小人算是未遂了·。希望能有大神指点迷津。。

现有一个主类,用来启动服务:

package com.lhl.startservice;

import java.io.File;
import java.io.FileOutputStream;

import com.lhl.service.StartService;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;

/**
 * 
 * 主界面
 * @author Catherine
 * */
public class MainActivity extends Activity {
    private Handler handler = new Myhandler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

    }

    private void initView() {

        Intent in = new Intent(MainActivity.this, StartService.class);
        startService(in);
        finish();
    }

    private class Myhandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            Toast.makeText(MainActivity.this, "接受了 消息", 0).show();
            super.handleMessage(msg);
        }
    }

    public void GetandSaveCurrentImage() {
        WindowManager widowManager = getWindowManager();
        Display display = widowManager.getDefaultDisplay();
        int w = display.getWidth();
        int h = display.getHeight();

        Bitmap Bmp = Bitmap.createBitmap(w, h, Config.ARGB_8888);

        View decorview = this.getWindow().getDecorView();
        decorview.setDrawingCacheEnabled(true);
        Bmp = decorview.getDrawingCache();
        try {
            String SavePath = getSDCardPath() + "/ScreenImage";
            File path = new File(SavePath);
            String filepath = SavePath + "/Screen_1.jpg";
            File file = new File(filepath);
            if (!path.exists()) {
                path.mkdirs();
            }
            if (!file.exists()) {
                file.createNewFile();
            }
            FileOutputStream fos = null;
            fos = new FileOutputStream(file);
            if (null != fos) {
                Bmp.compress(Bitmap.CompressFormat.PNG, 90, fos);
                fos.flush();
                fos.close();
                Log.i("LW", "截屏文件已保存至SDCard/ScreenImage/下");
                Message m = handler.obtainMessage();
                handler.sendMessage(m);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getSDCardPath() {
        File sdCardDir = null;
        boolean sdcardExit = Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);
        if (sdcardExit) {
            sdCardDir = Environment.getExternalStorageDirectory();
        }
        return sdCardDir.toString();
    }
}

然后一个服务打开:

package com.lhl.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;


import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.RawImage;
import com.android.ddmlib.TimeoutException;
import com.lhl.application.GetApplication;

import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;

/**
 * 
 * 开启一个服务
 * @author Catherine
 * */
public class StartService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    @Deprecated
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        new Timer().schedule(new TimerTask() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("123");
                /**
                 * 被注释的这个方法 可以截屏 指定的 某个界面
                 */
                // GetandSaveCurrentImage() ;

                CunCrruntPage();
            }

            private void CunCrruntPage() {
//                try {
                    IDevice device;
                    AndroidDebugBridge bridge = AndroidDebugBridge
                            .createBridge();
                    waitDeviceList(bridge);
//
                    IDevice devices[] = bridge.getDevices();
                    device = devices[0];
//                    RawImage rawScreen = device.getScreenshot();
//                    if (rawScreen != null) {
//                        BufferedImage image = null;
//                        boolean landscape = false;
//                        int width2 = landscape ? rawScreen.height
//                                : rawScreen.width;
//                        int height2 = landscape ? rawScreen.width
//                                : rawScreen.height;
//                        if (image == null) {
//                            image = new BufferedImage(width2, height2,
//                                    BufferedImage.TYPE_INT_RGB);
//                        } else {
//                            if (image.getHeight() != height2
//                                    || image.getWidth() != width2) {
//                                image = new BufferedImage(width2, height2,
//                                        BufferedImage.TYPE_INT_RGB);
//                            }
//                        }
//                        int index = 0;
//                        int indexInc = rawScreen.bpp >> 3;
//                        for (int y = 0; y < rawScreen.height; y++) {
//                            for (int x = 0; x < rawScreen.width; x++, index += indexInc) {
//                                int value = rawScreen.getARGB(index);
//                                if (landscape)
//                                    image.setRGB(y, rawScreen.width - x - 1,
//                                            value);
//                                else
//                                    image.setRGB(x, y, value);
//                            }
//                        }
//                        // ImageIO.write((RenderedImage)image,"PNG",new
//                        // File("D:/temp.jpg"));
//
//                        String SavePath = getSDCardPath() + "/ScreenImage";
//                        File path = new File(SavePath);
//                        String filepath = SavePath + "/Screen_1.jpg";
//                        File file = new File(filepath);
//                        if (!path.exists()) {
//                            path.mkdirs();
//                        }
//                        if (!file.exists()) {
//                            file.createNewFile();
//                        }
//                        ImageIO.write((RenderedImage) image, "PNG", file);
//
//                        Log.i("LW", "截屏文件已保存至SDCard/ScreenImage/下");
//                    }
//
//                } catch (TimeoutException e) {
//                    // TODO Auto-generated catch block
//                    e.printStackTrace();
//                } catch (AdbCommandRejectedException e) {
//                    // TODO Auto-generated catch block
//                    e.printStackTrace();
//                } catch (IOException e) {
//                    // TODO Auto-generated catch block
//                    e.printStackTrace();
//                }
            }

        }, 5000);
        return super.onStartCommand(intent, flags, startId);
    }

    private static void waitDeviceList(AndroidDebugBridge bridge) {
        int count = 0;
        while (bridge.hasInitialDeviceList() == false) {
            try {
                Thread.sleep(100); // 如果没有获得设备列表,则等待
                count++;

            } catch (InterruptedException e) {
            }
            if (count > 300) {
                // 设定时间超过300×100 ms的时候为连接超时
                System.err.print("Time out");
                break;
            }
        }
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
    }

    public void GetandSaveCurrentImage() {
        WindowManager widowManager = (WindowManager) getSystemService(getApplicationContext().WINDOW_SERVICE);
        Display display = widowManager.getDefaultDisplay();
        int w = display.getWidth();
        int h = display.getHeight();

        Bitmap Bmp = Bitmap.createBitmap(w, h, Config.ARGB_8888);

        View decorview =GetApplication.getMain().getWindow().getDecorView();
        decorview.setDrawingCacheEnabled(true);
        Bmp = decorview.getDrawingCache();
        try {
            String SavePath = getSDCardPath() + "/ScreenImage";
            File path = new File(SavePath);
            String filepath = SavePath + "/Screen_1.jpg";
            File file = new File(filepath);
            if (!path.exists()) {
                path.mkdirs();
            }
            if (!file.exists()) {
                file.createNewFile();
            }
            FileOutputStream fos = null;
            fos = new FileOutputStream(file);
            if (null != fos) {
                Bmp.compress(Bitmap.CompressFormat.PNG, 90, fos);
                fos.flush();
                fos.close();
                Log.i("LW", "截屏文件已保存至SDCard/ScreenImage/下");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getSDCardPath() {
        File sdCardDir = null;
        boolean sdcardExit = Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);
        if (sdcardExit) {
            sdCardDir = Environment.getExternalStorageDirectory();
        }
        return sdCardDir.toString();
    }

}

最后这个只是aoolication:

package com.lhl.application;

import com.lhl.startservice.MainActivity;

import android.app.Application;

/**
 * 
 * 用来锁定当前的application
 * 
 * @author Catherine
 * */
public class GetApplication extends Application {
    private static MainActivity main;

    public static MainActivity getMain() {
        return main;
    }

    public static void setMain(MainActivity main) {
        GetApplication.main = main;
    }

}

这里给出链接,也可以直接下载源码,或者在我的文件里面也有下载。

http://pan.baidu.com/s/1pJ7H1Nl

原文地址:https://www.cnblogs.com/Catherine-Brain/p/4107416.html