一个简单的xposed模块示例——指定好友发布新朋友圈时弹出提示(无需root)

xposed是一个可以修改app内部逻辑的框架,基于xposed我们可以实现很多有趣的功能。但使用xposed框架有一个很麻烦的问题,那就是需要对手机进行root。虽然出现了太极等框架使得我们无需root也可以使用许多现成的xposed模块,但如果我们想自己写一个模块练练手的话,按照网上编写模块的方法是适配不了太极的。那这样才能免root运行自己编写的xposed模块呢?这可以使用github上的xpatch项目。xpatch可以重新签名打包Apk文件,使重打包后的Apk能加载安装在系统里的Xposed插件,从而实现免Root Hook任意App。

开始正式编写xposed模块前需要一些配置,大家可以参考https://www.colabug.com/5324975.htmlhttps://blog.csdn.net/qq_37567866/article/details/83019971这两篇博文。

下面正式进入我们的重点,实现指定好友发布新朋友圈时弹出提示的功能。整个代码的逻辑非常简单,每隔一定时间(代码中是10分钟)刷新一次朋友圈,判断关注的好友是否发布了新朋友圈。如果是的话,在你下一次打开微信时,就会弹出提示,如下图所示。
在这里插入图片描述
这里主要有几个问题,第一个是如何刷新朋友圈?由于朋友圈是私有协议,伪造请求十分困难,我采用的是直接打开朋友圈的方式进行刷新,也就是每隔一定时间模块就会自动打开朋友圈。但为了尽量减少干扰,比如我们锁屏的时候也许不希望手机突然亮起来,并显示出朋友圈的界面。那怎样才能既实现刷新朋友圈的功能,朋友圈又不会突然显示出来呢。打开朋友圈可以通过startactivity方法实现,但退出朋友圈就不能等到页面加载完再退出。如果能够在朋友圈已经刷新并写入手机数据库,但还未在界面上显示出来的时候退出最好不过了,这样手机就不会突然亮起来了。
通过打印堆栈,我发现刷新朋友圈的时候有一个a方法非常关键(微信的源码是经过混淆的,可以通过jadx反混淆勉强看一下,也可以通过打印堆栈查看方法调用顺序)。每次刷新朋友圈,a方法都会被调用一次。于是我hook了a方法,在a方法被调用后马上退出朋友圈,发现果然达到了刷新朋友圈但手机不亮屏的效果。

 XposedHelpers.findAndHookMethod(snsModelYClass, lpparam.classLoader, "a", int.class,int.class,
    int.class,String.class,Class.forName("com.tencent.mm.network.q"),byte[].class,new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                if(snsLaunchByXP){   //如果是xposed启模块启动的朋友圈,自己打开朋友圈则不会执行下列代码
                    Log.d("myLog", "a()方法被调用");
                    snsActivity.finish();
                    Log.d("myLog", "snsActivity.finish()");  //关闭朋友圈
                    snsOn = false;
                    Log.d("myLog", "snsOn false");   
                    snsLaunchByXP = false;    
                }
            }
        });

第二个问题,如何判断是不是关注的好友发布的朋友圈?刷新朋友圈的时候,新朋友圈信息写入手机数据库会调用insertWithOnConflictMethod这个方法。hook这个方法,读取它的参数可以获取朋友圈发布者的微信id。判断该id是不是自己关注好友的id即可。我发现如果有的好友更改了自己的微信id,但实际上他的微信id依旧是之前的默认id。那我们怎么查看这个默认id呢,可以下载微续这款软件登录自己微信,就可以查看好友的微信id了。

public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        XposedHelpers.findAndHookMethod(dataBaseName, lpparam.classLoader, insertWithOnConflictMethod, String.class, String.class, ContentValues.class, int.class, new XC_MethodHook() {

            @Override
            protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
                if (param.args[0].equals("SnsInfo")) {
                    ContentValues contentValues = ((ContentValues) param.args[2]);
                    int time = contentValues.getAsInteger("createTime");    //获取朋友圈发布时间
                    String name = contentValues.getAsString("userName");  //获取朋友圈发布者微信id
                    if(name.equals("wxid_xxx")) friend1 = true;   //wxid_xxx改成自己想要关注的好友的微信id即可
                    else if(name.equals("wxid_yyy")) friend2 = true;
                    else if(name.equals("wxid_zzz")) friend3 = true;
                    long msgCreatetime = Long.parseLong(time + "") * 1000L;
                    DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String snsDate = format.format(new Date(msgCreatetime));
                    Log.d("myLog:", "insert:" + snsDate + " " + name);   //打印朋友圈发布时间和发布者
                }
            }
        });

第三个问题,如何定时刷新朋友圈?这里我用的是java的timer定时器。也许使用android的service会更好一些,以后有时间可以尝试一下。

  public final void schedule()  {
        timerTask = new TimerTask() {
            @Override
            public void run() {
                try {
                    PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
                    if(!pm.isScreenOn()){  //黑屏时才运行程序,以免影响手机使用
                        if(snsOn && snsActivity != null){   //有时网络不佳,刷新朋友圈时a方法并没有调用,朋友圈因此没有关闭,下一次刷新朋友圈时先关闭之前打开的activity。
                            snsActivity.finish();
                            snsOn = false;
                        }
                        else {
                            Intent intent = new Intent(context, Class.forName(snsActivityName));
                            snsLaunchByXP = true;
                            context.startActivity(intent);  //打开朋友圈的activity
                            snsOn = true;
                            Log.d("myLog", "start sns");
                        }
                    }
                    else{
                        Log.d("myLog","screen on");
                    }
                }
                catch(ClassNotFoundException e){
                }
            }
        };
        timer.schedule(timerTask,20000,600000);  //每隔10分钟运行一次
        Log.d("myLog","timer.schedule(timerTask)");
    }

最后一个问题是怎样弹出提示,我直接用了android的toast,简单方便。大家可以尝试在状态栏弹出提示。

XposedHelpers.findAndHookMethod(launchActivityName, lpparam.classLoader, onResumeMethod, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                Log.d("myLog","launchActivity.onResume");
                Context con = (Context)param.thisObject;
                PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
                if(pm.isScreenOn()) {
                    if (friend1){
                        Toast.makeText(con, "你关注的大姐有新朋友圈了!", Toast.LENGTH_LONG).show();
                        friend1 = false;
                    }
                    if (friend2){
                        Toast.makeText(con, "你关注的二姐有新朋友圈了!", Toast.LENGTH_LONG).show();
                        friend2 = false;
                    }
                    if (friend3){
                        Toast.makeText(con, "你关注的好友有新朋友圈了!", Toast.LENGTH_LONG).show();
                        friend3 = false;
                    }
                }
            }
        });

这就是整个代码的主要内容了,第一次写xposed模块,不足之处,多多指教。模块已经上传到github(Moments_reminder),我测试的微信版本是7.0.3,应该7以上都可以。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值