免ROOT实现模拟点击任意位置

Home / Android MrLee 2019-5-14 12265

微信7.0版本之前抢红包插件点击基本上都借助AccessibilityService无障碍的performClick方法点击控件,不过7.0版本的微信的红包控件(view)没有id这一项了,所以performClick就无法使用了,但是抢红包就在此停止了吗?非也,下面给出2种点击方法。

方法一(验证有效)

此方法免root,不过需要Android7.0及以上版本,AccessibilityService有个新的选项,canPerformGestures: 安卓7.0后可通过dispatchGesture实现点击屏幕的操作,如需用此方法需将canPerformGestures设置为true

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:canPerformGestures="true"
    android:description="@string/accessibility_service_description" />
<!--android:canPerformGestures 是否可以执行手势(api 24新增)-->

模拟点击的方法dispatchGesture

    @TargetApi(24)
    public void click(Point point) {
        //只有7.0才可以用
        GestureDescription.Builder builder = new GestureDescription.Builder();
        Path path = new Path();
        path.moveTo((float) point.x, (float) point.y);
        path.lineTo((float) point.x, (float) point.y);
        /**
         * 参数path:笔画路径
         * 参数startTime:时间 (以毫秒为单位),从手势开始到开始笔划的时间,非负数
         * 参数duration:笔划经过路径的持续时间(以毫秒为单位),非负数
         */
        builder.addStroke(new GestureDescription.StrokeDescription(path, 1, 1));
        final GestureDescription build = builder.build();
        /**
         * 参数GestureDescription:翻译过来就是手势的描述,如果要实现模拟,首先要描述你的腰模拟的手势嘛
         * 参数GestureResultCallback:翻译过来就是手势的回调,手势模拟执行以后回调结果
         * 参数handler:大部分情况我们不用的话传空就可以了
         * 一般我们关注GestureDescription这个参数就够了,下边就重点介绍一下这个参数
         */
        dispatchGesture(build, new GestureResultCallback() {
            public void onCancelled(GestureDescription gestureDescription) {
                super.onCancelled(gestureDescription);
            }
            public void onCompleted(GestureDescription gestureDescription) {
                super.onCompleted(gestureDescription);
            }
        }, null);
    }

然后配合MediaProjection录屏进行图片识别即可。

     /**
     * 申请屏幕录取权限
     */
    private void requestScreenShot() {
        startActivityForResult(
                ((MediaProjectionManager) this.getActivity().getSystemService("media_projection")).createScreenCaptureIntent(),
                REQUEST_MEDIA_PROJECTION);
    }
    
    
     public Bitmap getScreenShotSync() {
        if (!isShotterUseful()) {
            return null;
        }
        if (mImageReader == null) {
            mImageReader = ImageReader.newInstance(
                    getScreenWidth(),
                    getScreenHeight(),
                    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;
    }
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private VirtualDisplay virtualDisplay() {
        return mMediaProjection.createVirtualDisplay("screen-mirror",
                getScreenWidth(),
                getScreenHeight(),
                Resources.getSystem().getDisplayMetrics().densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mImageReader.getSurface(), null, null);
    }

抢红包开源地址:https://github.com/LnJan/WechatLuckyMoneyGetter


方法二(未验证)

此方法依然使用的是adb shell,不过并不需要root方法。其中奥秘在于app_process启动一个dex的java程序(shell启动的程序必然有shell权限),利用此程序的shell启动权限进行点击点击,程序的后台卸载、安装都可以。

这个引用一个已经实现的项目


本文链接:https://www.it72.com/12540.htm

上传的附件:
推荐阅读
最新回复 (3)
  • 梅兮 2019-12-24
    引用 2
    请问下第一种方法有demo么?
  • 梅兮 2019-12-24
    引用 3
    执行你这个方法dispatchGesture返回true,但是没效果啊
  • MrLee 2019-12-25
    引用 4
    第一种有效的,但是系统必须是Android7.0及以上才有用。我测试过,DEMO现在没有了。 android:canPerformGestures="true" 这句代码你加了没,这个必须加!
返回