作为安卓自动跳过广告三部曲的第二部分,主要是实现系统截屏功能。继《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