zoukankan      html  css  js  c++  java
  • 截屏 多难未遂

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

         其实网上关于截屏的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

  • 相关阅读:
    log4net
    winform datagridview 刷新数据不需要重新绑定
    Git 简明教程(一)
    Task详解【转载】
    虚拟机Linux系统手动指定IP
    DataGrip连接sqlserver,提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
    c#中Equals方法和GetHashCode
    获取程序集的类型信息
    第一个windows桌面应用程序
    在运行时让PropertyGrid动态显示我们想要的对象属性
  • 原文地址:https://www.cnblogs.com/Catherine-Brain/p/4107416.html
Copyright © 2011-2022 走看看