1. 程式人生 > >Android4.0以上版本 後臺service跨程序擷取當前螢幕總結

Android4.0以上版本 後臺service跨程序擷取當前螢幕總結

最近個人在做一個android的APP應用,涉及到了後臺擷取當前螢幕的需求,如果只是在自己應用裡面擷取大家應該都知道如何做,關鍵就在於後臺跨程序擷取其他APP當前執行的畫面遇到了問題。

本人研究了一週左右的時間終於找到了一套相對而言比較可行的方案。

在這裡需要感謝 李博Garvin文章參考了他的部分程式碼,這位牛人也是在這方面花了不少精力。

當然,我只是初學android開發,如果裡面有不正確的言論還請大家及時指出。

擷取自身Activity的介面(這裡只是大概的貼出了主要的功能程式碼,詳細的自己去網上找,多的是)

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);  
    }  

後臺service跨程序截圖

1、android 4.0以下版本後臺截圖

通過JNI方式擷取螢幕,缺點是需要原始碼環境,詳情請參考:

2、android 4.0~4.2  版本後臺截圖

這個可以通過反射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;

該方法優點無需ROOT,缺點是隻支援4.0~4.2,4.3版本就不適用了。

或者通過 bufferframe讀取fb0這種方法,但是估計需要ROOT許可權

3、android 4.3版本後臺截圖

4.3版本其實也存在screenshot方法,只不過他所屬的整個類android.view.SurfaceControl都被hide了,所以通過一般的反射是無法呼叫的。

這裡我開始參考了CSDN 李博Garvin 這位博主的做法(android4.3 截圖功能的嘗試與失敗分析),就是在PC端執行adb shell  /system/bin/screencap -p /sdcard/screenshot.png命令是可以正確擷取螢幕的,但是換到android端執行該命令就會出錯,截出來的圖片大小為0.個人推測應該是android端執行shell命令出了什麼問題。

在嘗試了很多辦法之後,終於在網上找到了解決辦法。

原因就在於我們之前執行命令之前沒有獲取ROOT許可權,就算是當前手機已經有了ROOT許可權,我們也必須要在程式裡再次獲取ROOT許可權,

也就是先執行下 Runtime.getRuntime().exec(“su”),然後在執行我們需要的命令。

然後我們就可以看到SD卡里面生成的正常的圖片了。

這方面網上已經有了相應的工具包,我們開發起來可以事半功倍。

而我們要做的只是把它裡面的ShellUtils引用進來,然後呼叫execCommand(String command, boolean isRoot) 就可以了

總結一下: 4.0以上版本優先考慮ROOT方法,簡單,通用。如果沒有ROOT的話就判斷系統版本,4.3以下的通過反射呼叫,4.3以上暫時還不清楚