欢迎使用CSDN-markdown编辑器

Android微信抢红包功能实现原理

利用手机自带的辅助服务(无障碍模式),监听手机的动态 : AccessibilityService

1、如果通知栏有[微信红包]的消息来,就会自动截取并模拟人手点击通知栏--进入微信聊天界面
2、在聊天界面匹配[查看红包、领取红包]字样的信息,再模拟人手点击
3、如果可以点击(也就是说不是文字,那就是红包)
4、匹配[开]按钮(以前是“拆”),如果有这个button,就模拟人手点击,进入下一界面
5、开之后就出现两种界面:匹配“已存入零钱”的textview有结果的话就说明抢到了红包,否则匹配“手慢了”的textview就说明没有抢到红包
6、如果有红包就找到“已存入零钱”前面的”元“的前一个位置,这个位置上就是红包钱数的textview
7、当然,打开界面后要返回


问题:
1、如何判断红包是否已经被打开?

   通过红包的Signature获得到红包的:发红包人名、留言、时间;通过这三个信息判定是否已经领过红包。这里又会出现两个问题:
        a、微信每条信息的时间只会精确到分,不会精确到秒,所以同一分钟内同一个人发送的同一留言的红包就不能判定唯一
        b、并不是每条信息都会获取到时间,有许多时间获得到是:unknownTime吗,也就是没有获取到时间,这更增加了标志的困难性

2、如何计算抢到红包的准确钱数?

   这个问题与上一个问题是联系在一起的,当不能判定是否为抢过的红包情况下,可能会重复打开已经抢过的红包,这样--记录过的红包钱数就会被再记录一次 ......

3、如何在锁屏的情况下实现抢红包?

   手机一旦锁屏,关于屏幕上的一切信息我们都无从得到,但是后台的服务是一直在运行的,所以我们只要用服务一直坚挺通知栏是否有[微信红包]等字样的信息来,如果检测到有此类信息,我们只要将屏幕点亮,再启动监听聊天界面的服务就可以获取到红包了。那么,问题来了?怎么点亮屏幕?---待会有代码奉上。

4、可以自动回复吗?

   肯定是可以的,只要在正确的实际发送触发聊天界面上的“发送”按钮,就能将你想回复的感谢语发送出去了

核心代码

/**
* Created by rinzz08 on 17/2/16.
*
* 抢红包服务类
*/

public class RedPacketService extends AccessibilityService {

/**
* 必须重写的方法:此方法用了接受系统发来的event。在你注册的event发生是被调用。在整个生命周期会被调用多次。
*/
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
/**
* 必须重写的方法:系统要中断此service返回的响应时会调用。在整个生命周期会被调用多次。
*/
@Override
public void onInterrupt() {
Toast.makeText(this, “中断了—–”, Toast.LENGTH_SHORT).show();
}
/**
* 服务已连接
*/
@Override
protected void onServiceConnected() {
Toast.makeText(this, “开启抢红包服务”, Toast.LENGTH_SHORT).show();
super.onServiceConnected();
}
/**
* 服务已断开
*/
@Override
public boolean onUnbind(Intent intent) {
Toast.makeText(this, “关闭抢红包服务已被”, Toast.LENGTH_SHORT).show();
return super.onUnbind(intent);
}
}

像这类重写AccessibilityService类的服务代码晚上多得去了,下面主要介绍一下重点功能实现的地方,代码确实有点low,功能确实是实现了…..

获取抢到红包的钱数

/**
* 遍历查找文本框(这里主要获取钱数)
*
* @param node
* @return
*/
private AccessibilityNodeInfo findOpenTextView(AccessibilityNodeInfo node) {

    float allHong = RinnzSharedUtil.getFloat(MyApp.getContext(), SharedConstants.HISTORY_MONEY, 0.0f);
    float todayHong = RinnzSharedUtil.getFloat(MyApp.getContext(), SharedConstants.TODAY_MONEY, 0.0f);

 List<String> texts = new ArrayList<>();
    if (node == null)
        return null;

//非layout元素
    if (node.getChildCount() == 0) {
        if ("android.widget.TextView".equals(node.getClassName()))
            return node;
        else
            return null;
    }

    //layout元素,遍历找文本框
    AccessibilityNodeInfo textView;
    for (int i = 0; i < node.getChildCount(); i++) {
        textView = findOpenTextView(node.getChild(i));
        if (textView != null)
            if (textView.getText() != null) {
                String textName = textView.getText().toString();
                texts.add(textName);
                // Log.i(TAG, "findOpenTextView_text: " + textName);
                if (textName.contains("已存入零钱")) {

                    //说明抢到一个红包,给本地一个信息
                    int hongbaoNum = RinnzSharedUtil.getInt(MyApp.getContext(), SharedConstants.HONGBAO_NUM);
                    RinnzSharedUtil.putInt(MyApp.getContext(), SharedConstants.HONGBAO_NUM, hongbaoNum + 1);

           //在这里就去截取钱数所在的文本框吧(getText().toString();)
                }
            }
        //return textView;

    }
    return null;
}

自动回复

如果有自动回复的功能,只要在抢红包的时候在找到“开”的时候做一个标记,然后返回到聊天界面的时候检测编辑框,然后给编辑框赋值,再找到“发送”按钮,再触发按钮就OK了

/**
* 遍历查找EditText
*
* @param node
* @return
*/
private AccessibilityNodeInfo findOpenEditText(AccessibilityNodeInfo node) {
Log.i(TAG, “findOpenButton: 找到编辑框了”);
if (node == null)
return null;

    //非layout元素
    if (node.getChildCount() == 0) {
        if ("android.widget.EditText".equals(node.getClassName()))
            return node;
        else
            return null;
    }

    //layout元素,遍历找EditText
    AccessibilityNodeInfo editText;
    for (int i = 0; i < node.getChildCount(); i++) {
        editText = findOpenEditText(node.getChild(i));
        if (button != null) {
            return editText;
        }
    }
    return null;
}

回复

private void autoReponse() {

AccessibilityNodeInfonodeInfo=findOpenEditText(this.rootNodeInfo);

        //  Log.i(TAG, "autoReponse: 有个编辑框");
        isInput++;
        if (isInput == 1) {
            Bundle arguments = new Bundle();
            String autoSend = RinnzSharedUtil.getString(MyApp.getContext(), SharedConstants.AUTO_RESPONSE_TEXT);
            if (autoSend != null) {

            arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, autoSend);
                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
                //编辑了文本需要点击发送
                send();
            } else {
                arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "谢谢老板");
                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
                //编辑了文本需要点击发送
                send();
            }
            return;
        }
    }
}

发送按钮

/**
* 寻找窗体中的“发送”按钮,并且点击。

@SuppressLint("NewApi")
 private void send() {
      AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
    if (nodeInfo != null) {
        List<AccessibilityNodeInfo> list = nodeInfo
                .findAccessibilityNodeInfosByText("发送");
        if (list != null && list.size() > 0) {
            for (AccessibilityNodeInfo n : list) {
                n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }

        } else {
            List<AccessibilityNodeInfo> liste = nodeInfo
                    .findAccessibilityNodeInfosByText("Send");
            if (liste != null && liste.size() > 0) {
                for (AccessibilityNodeInfo n : liste) {
                    n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                }
            }
        }
    }
}

屏蔽不想抢的红包

这个就简单了,只要在聊天界面检测发来红包的Signature值,这个值有三个信息(用户名、留言信息、时间),然后将你屏蔽的文字与这个红包的Signature值是否匹配,匹配的话直接过滤就行了,这里就补粘贴代码了

手机锁屏依旧抢红包

/**
*唤醒屏幕:这里要注意的是手机如何设置了锁屏密码,那么这个功能就不能唤醒了,怎么唤醒?撬了手机锁屏?呵呵哒。

只要一直用服务判断通知栏是否有红包信息来就行了,有信息来直接唤醒,其他的事就不用你做了
*/
public static void wakeUpAndUnlock(){

    //屏锁管理器
    KeyguardManager km= (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
    KeyguardManager.KeyguardLock kl = km.newKeyguardLock("unLock");
    //解锁
    kl.disableKeyguard();
    //获取电源管理器对象
    PowerManager pm=(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    //获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK,"bright");
    //点亮屏幕
    wl.acquire();
    //释放
    wl.release();
}

第一次写CSDN,写的是乱七八糟,见谅见谅。有问题请多多指教!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值