Android Skip Ads Android Project【截屏部分】

作为安卓自动跳过广告三部曲的第二部分,主要是实现系统截屏功能。继《Android Skip Ads Yolov5 Project》之后,下一步就是获取当前屏幕的截图,把截图传入分析引擎实现广告跳过按钮的识别,最后一步是按钮点击。

要在安卓系统上实现截图(截取整个屏幕,并且需要截取其他app的界面),通常有下面三个方法:

1.直接调用系统的截屏工具,需要root权限

adb shell screencap -p /sdcard/sreenshot1.png

2.通过系统私有api实现截屏:

Bitmap mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
//通过反射进行调用
public Bitmap takeScreenShot() {
        Bitmap bmp = null;
        mDisplay.getMetrics(mDisplayMetrics);
        float[] dims = {(float) mDisplayMetrics.widthPixels, (float) heightPixels};
        float degrees = getDegreesForRotation(mDisplay.getRotation());
        boolean requiresRotation = degrees > 0;
        if (requiresRotation) {
            mDisplayMatrix.reset();
            mDisplayMatrix.preRotate(-degrees);
            mDisplayMatrix.mapPoints(dims);
            dims[0] = Math.abs(dims[0]);
            dims[1] = Math.abs(dims[1]);

        }
        try {
            Class<?> demo = Class.forName("android.view.SurfaceControl");
            Method method = demo.getMethod("screenshot", new Class[]{Integer.TYPE, Integer.TYPE});
            bmp = (Bitmap) method.invoke(demo, new Object[]{Integer.valueOf((int) dims[0]), Integer.valueOf((int) dims[1])});
            if (bmp == null) {
                return null;
            }
            if (requiresRotation) {
                Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels, heightPixels, Bitmap.Config.RGB_565);
                Canvas c = new Canvas(ss);
                c.translate((float) (ss.getWidth() / 2), (float) (ss.getHeight() / 2));
                c.rotate(degrees);
                c.translate((-dims[0] / 2), (-dims[1] / 2));
                c.drawBitmap(bmp, 0, 0, null);
                c.setBitmap(null);
                bmp.recycle();
                bmp = ss;
            }
            if (bmp == null) {

                return null;
            }
            bmp.setHasAlpha(false);
            bmp.prepareToDraw();
            return bmp;
        } catch (Exception e) {
            e.printStackTrace();
            return bmp;
        }

    }

参考链接:https://www.jianshu.com/p/4ae89e1fb36a

3.通过MediaProjectionManager 录屏实现截屏:参考链接:https://www.jianshu.com/p/8a428fb45098

package cn.org.obaby.adsskiper;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.os.Build;
import android.os.DeadSystemException;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;

import java.nio.ByteBuffer;

/**
 * Created by Ln_Jan on 2018/12/13.
 * 截屏工具
 * 代码来源:https://github.com/LnJan/WechatLuckyMoneyGetter/  
 */

public class ScreenShotter {
    private static ScreenShotter instance = null;

    private MediaProjection mMediaProjection;
    private ImageReader mImageReader;
    private boolean mIsNormalScreen = true;
    private volatile Point[] mRealSizes = new Point[2];
    private int mScreenRealHeight;
    private int mScreenRealWidth;

    private static final int PORTRAIT = 0;
    private static final int LANDSCAPE = 1;

    private ScreenShotter() {
        mMediaProjection = null;
        mImageReader = null;
        mIsNormalScreen = checkScreenSizeIsNormal();
        mScreenRealHeight = mIsNormalScreen ? getScreenHeight() : getScreenRealHeight();
        mScreenRealWidth = getScreenWidth();
    }

    public static ScreenShotter getInstance() {
        if (instance == null) {
            instance = new ScreenShotter();
        }
        return instance;
    }

    public boolean isNormalScreen() {
        return mIsNormalScreen;
    }

    public void setMediaProjection(MediaProjection projection) {
        mMediaProjection = projection;
    }

    public boolean isShotterUseful() {
        return mMediaProjection != null;
    }

    @SuppressLint("WrongConstant")
    public Bitmap getScreenShotSync() throws DeadSystemException {
        if (!isShotterUseful()) {
            return null;
        }

        if (mImageReader == null) {
            mImageReader = ImageReader.newInstance(
                    mScreenRealWidth,
                    mScreenRealHeight,
                    PixelFormat.RGBA_8888,//此处必须和下面 buffer处理一致的格式 ,RGB_565在一些机器上出现兼容问题。
                    1);
        }

        VirtualDisplay tmpDisplay = virtualDisplay();
        try {
            Thread.sleep(50);                   //需要稍微停一下,否则截图为空
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Image img = mImageReader.acquireLatestImage();

        if (img == null) {
            return null;
        }

        int width = img.getWidth();
        int height = img.getHeight();
        final Image.Plane[] planes = img.getPlanes();
        final ByteBuffer buffer = planes[0].getBuffer();
        //每个像素的间距
        int pixelStride = planes[0].getPixelStride();
        //总的间距
        int rowStride = planes[0].getRowStride();
        int rowPadding = rowStride - pixelStride * width;
        Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height,
                Bitmap.Config.ARGB_8888);//虽然这个色彩比较费内存但是 兼容性更好
        bitmap.copyPixelsFromBuffer(buffer);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
        img.close();
        //mImageReader.close();
        tmpDisplay.release();
        return bitmap;
    }


    public int getScreenWidthPublic() {
        return mScreenRealWidth;
    }

    public int getScreenHeightPublic() {
        return mScreenRealHeight;
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private VirtualDisplay virtualDisplay() {
        return mMediaProjection.createVirtualDisplay("baby-screen-mirror",
                getScreenWidth(),
                getScreenHeight(),
                Resources.getSystem().getDisplayMetrics().densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mImageReader.getSurface(), null, null);
    }

    private int getScreenWidth() {
        return Resources.getSystem().getDisplayMetrics().widthPixels;
    }

    private int getScreenHeight() {
        return Resources.getSystem().getDisplayMetrics().heightPixels;
    }

    /**
     * 某些全面屏手机获取的屏幕宽度不对,需用此方法获取宽度
     *
     * @return
     */
    private int getScreenRealHeight() {
        int orientation = LuckyMoneyTinkerApplication.getContext().getResources().getConfiguration().orientation;
        orientation = orientation == Configuration.ORIENTATION_PORTRAIT ? PORTRAIT : LANDSCAPE;

        if (mRealSizes[orientation] == null) {
            WindowManager windowManager = (WindowManager) LuckyMoneyTinkerApplication.getContext().getSystemService(Context.WINDOW_SERVICE);
            if (windowManager == null) {
                return getScreenHeight();
            }
            Display display = windowManager.getDefaultDisplay();
            Point point = new Point();
            display.getRealSize(point);
            mRealSizes[orientation] = point;
        }
        return mRealSizes[orientation].y;
    }

    /**
     * 检查屏幕尺寸是否16:9
     * 某些18:9的全面屏手机会出现截屏位置偏移的问题
     *
     * @return
     */
    private boolean checkScreenSizeIsNormal() {
        DisplayMetrics dm = new DisplayMetrics();
        dm = Resources.getSystem().getDisplayMetrics();
        int screenWidth = dm.widthPixels;
        int screenHeight = dm.heightPixels;
        return screenHeight < screenWidth * 1.8;
    }
}

整体项目地址:https://github.com/obaby/skip_ads_android

☆版权☆

* 网站名称:obaby@mars
* 网址:https://obaby.org.cn/
* 个性:https://oba.by/
* 本文标题: 《Android Skip Ads Android Project【截屏部分】》
* 本文链接:https://obaby.org.cn/2021/09/9042
* 短链接:https://oba.by/?p=9042
* 转载文章请标明文章来源,原文标题以及原文链接。请遵从 《署名-非商业性使用-相同方式共享 2.5 中国大陆 (CC BY-NC-SA 2.5 CN) 》许可协议。


You may also like

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注