美文网首页
友盟推送第一次安装时获取不到deviceToken的问题

友盟推送第一次安装时获取不到deviceToken的问题

作者: 碧桃鹦鹉 | 来源:发表于2022-02-21 14:40 被阅读0次

    最近又对接了一次友盟推送,但是没有之前的那么顺利,因为在华为P30手机上出现了之前没见过的现象。现象就是应用第一次安装到手机上大概率获取不到devicetoken。第二次启动应用后才能获取到token。而且手机在充电情况下是能正常获取的,不充电情况很难获取。也就是调用pushAgent.register()方法,没有任何回调。查看日志和友盟的源码之后发现了端倪。在了解了友盟的注册流程和代码原来之后,我根据其中逻辑建立了新的流程,能够解决刚才说的第一次启动获取不到devicetoken的问题。下面的内容就是探究和解决这个问题的过程。
    先说实现方案:

    pushAgent.register(new UPushRegisterCallback() {
                @Override
                public void onSuccess(String s) {
                    String deviceToken = s;
                }
    
                @Override
                public void onFailure(String s, String s1) {
                }
            });
    

    后面增加这段代码:

    new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
                    String deviceToken = Config.f(context);
                }
            }, 0, 300);
    //这段只是示例用循环来反复读取 Config.f(context),具体循环速度、次数、判空、回收资源等细节需自行把握。
    

    -----下面开始探究之路------

    顺着pushAgent.register()源码跟踪进去,进入到一个ak.class文件。主要注册逻辑在一个叫做c的私有方法中。下面是该方法中的部分代码:

    y.b(new Runnable() {
                    public void run() {
                        try {
                            UPLog.i("", new Object[]{"appkey:" + var2, " secret:" + var3});
                            TaobaoRegister.register(var1, "default", "umeng:" + var2, var3, "android@umeng", new IRegister() {
                                public void onSuccess(String var1x) {
                                    UPLog.i("", new Object[]{"register success. deviceToken:" + var1x});
                                    ak.this.a(var1x);
                                }
    
                                public void onFailure(String var1x, String var2x) {
                                    UPLog.e("", new Object[]{"register failed! code:" + var1x + ", desc:" + var2x});
                                    ak.this.a(var1x, var2x);
                                    UMLog.aq(ao.a, 0, "\\|");
                                }
                            });
                        } catch (Throwable var2x) {
                            UPLog.e("", new Object[]{"register failed:" + var2x.getMessage()});
                        }
    
                    }
                });
    

    能看到这段代码调用了TaobaoRegister.register来注册,注册成功后会调用ak文件下的a方法:

        private void a(String var1) {
            ......
            UMJobIntentService.enqueueWork(am.b(), UmengMessageCallbackHandlerService.class, var2);
        }
    

    a方法又启动执行了一个叫做UmengMessageCallbackHandlerService的JobIntentService,下面是UmengMessageCallbackHandlerService中的相关代码:

    final Context var2 = am.b();
            if (var2 == null) {
                UPLog.i("MsgCallback", new Object[]{"context null!"});
            } else {
                String var3 = UMGlobalContext.getInstance(var2).getProcessName(var2);
                UPLog.i("MsgCallback", new Object[]{"processName:", var3});
                if (var1 != null && var1.getAction() != null) {
                    UPLog.i("MsgCallback", new Object[]{"action:", var1.getAction()});
                    String var4 = var1.getAction();
                    byte var5 = -1;
                    ...........
                    final String var6;
                    String var9;
                    boolean var17;
                    UPushSettingCallback var20;
                    String var23;
                    switch(var5) {
                    case 0:
                        try {
                            var6 = var1.getStringExtra("registration_id");
                            boolean var22 = var1.getBooleanExtra("status", false);
                            UPLog.i("MsgCallback", new Object[]{"u-push regId:", var6, ", status:" + var22});
                            final UPushRegisterCallback var24 = PushAgent.getInstance(var2).getRegisterCallback();
                            if (var22) {
                                y.b(new Runnable() {
                                    public void run() {
                                        String var1 = "";
    
                                        try {
                                            MessageSharedPrefs var2x = MessageSharedPrefs.getInstance(var2);
                                            var1 = var2x.getDeviceToken();
                                            if (var6 != null && var1 != null && !var6.equals(var1)) {
                                                var2x.setRegistered(false);
                                                var2x.setDeviceToken(var6);
                                                var2.getContentResolver().delete(aw.e, (String)null, (String[])null);
                                                var2x.resetTags();
                                            }
                                        } catch (Exception var3) {
                                        }
    
                                        if (var24 != null) {
                                            var24.onSuccess(var6);
                                        }
    
                                        an.a().a(var1);
                                        PushAgent.getInstance(var2).onAppStart();
                                    }
                                });
                            } else if (var24 != null) {
                                var9 = var1.getStringExtra("s");
                                String var10 = var1.getStringExtra("s1");
                                var24.onFailure(var9, var10);
                            }
                        } catch (Throwable var16) {
                            var16.printStackTrace();
                        }
                        break;
                        .......
    

    能看到UmengMessageCallbackHandlerService中的代码,如果注册成功获取到devicetoken之后,会有一系列操作,包括保存token,设置状态,调用成功的回调方法等等。根据日志能观察到,如果注册成功了,日志会输出MsgCallback u-push regId:xxxxxxxx,也就是输出devicetoken。

    这一套流程就是,友盟调用TaobaoRegister.register()方法去注册,如果TaobaoRegister.register注册成功了会执行JobIntentService来发送注册成功的广播。对比了日志后发现,在出问题的情况,也就是收不到token 的时候,ak文件的a方法中

    UMJobIntentService.enqueueWork(am.b(), UmengMessageCallbackHandlerService.class, var2);
    

    这行代码正常情况下会启动UmengMessageCallbackHandlerService,并执行里面的回调,再去回调前面pushAgent的register的成功回调。但是这个Service不一定会如约启动,经过观察对比,如果手机没充着电,90%以上概率不会启动这个服务。具体原因还需要再研究,但是现象已经观测出来了。
    总结流程:
    1.pushAgent.register
    2.TaobaoRegister.register
    3.回调ak.a()
    4.启动UmengMessageCallbackHandlerService
    5.回调UPushRegisterCallback的onSuccess
    6.获取到devicetoken
    现在就是在第4步失败,不能启动Service。所以解决方案就在第4步之前去找。
    关注第4步之前的TaobaoRegister.register,进到TaobaoRegister.register内部查看源码:

     public static synchronized void register(Context var0, String var1, String var2, String var3, String var4, IRegister var5) throws AccsException {
                .......
                com.taobao.accs.b var9 = ACCSManager.getAccsInstance(var0, var2, var1);
                var9.a(var7, var2, var3, var4, new h(var7, var0, var5, var2, var4, var9));
                ......
        }
    

    var5就是注册结果响应的callback,var5被用来创建了一个h对象。进到h类中查看源码,var5传进去变成了h类的c参数,在onBindApp的方法中被调用:

     public void onBindApp(int var1, String var2) {
            ......
            if (this.c != null) {
                this.c.onSuccess(Config.f(this.a));
            }
            ......
        }
    

    看到这里有个Config.f(this.a),也就是这个方法的返回值就是devicetoken,就是把它经过刚才的好几个步骤回调回去才是注册成功。然后查看一下这个类是个public的,方法也是public,所以通过这个方法就可以在第4步之前,实际上第2步就拿到devicetoken。
    这时候只需要在pushAgent.register注册之后做一个循环,反复调用Config.f(context)方法,只到返回有值的时候就认为获取到了token。经过多次测试,最多在5秒就可以获取到。要记得,这一系列过程只是解决了应用第一次安装时没有token的问题,并不是每次启动应用都是需要最多5秒来获取token。
    其中service为什么只在充电时候启动的原理还没有深入研究。初步检查源码应该是和电源管理,进程调度有关,需要再花时间研究一下。`

    相关文章

      网友评论

          本文标题:友盟推送第一次安装时获取不到deviceToken的问题

          本文链接:https://www.haomeiwen.com/subject/hpwlcrtx.html