接入友盟推送的实战总结

接入友盟推送实战

标签(空格分隔): Android

请注意:###

  • 消息推送SDK 不支持在QEMU模拟器上调试,调试时请尽量使用真机。
  • 友盟推送为什么对“广播”的发送次数有3次限制?博客
  • 友盟消息推送API调用有什么频率或者次数的限制 博客
    如果分别下发了两条消息,却只收到了一条,先不要着急。因为同一台设备在1分钟内收到同一个应用的多条通知时,不会重复提醒,同时在通知栏里新的通知会替换掉旧的通知。

1、首先是自己申请一个APPKey,不能偷懒,妈的!我就是想偷一下懒,直接用主管的demo里的APPKey,结果搞了半天没出,因为可能他在友盟上已经注销了这个AppKey对应的应用或者关闭了对这个应用的推送功能,所以肯定是不能收到推送的。

2、然后是最坑的一个Bug,可能是中国人的软肋吧,就是依赖中文,虽然自己是个程序员,但是很多时候还是用能用中文就尽量用中文吧。所以导致今天在友盟的官网上出现了用中文起名的悲剧,图中的用圆圈画住的部分,千万不要用中文,不然会出现意想不到的Bug。总的开说,在代码的世界里,最好一切都用英文!!!


接入友盟推送的实战总结_第1张图片
捕获.PNG

3、第三个就是自己真的太粗心了,竟然认为所以然就没有加上这一步,真是该打!
原文:

在所有的Activity 的onCreate方法或在应用的BaseActivity的onCreate方法中添加:
PushAgent.getInstance(context).onAppStart();
**注意**: 此方法与统计分析sdk中统计日活的方法无关!请务必调用此方法!
 如果不调用此方法,不仅会导致按照"几天不活跃"条件来推送失效,还将导致广播发送不成功以及设备描述红色等问题发生。可以只在应用的主Activity中调用此方法,但是由于SDK的日志发送策略,有可能由于主activity的日志没有发送成功,而导致未统计到日活数据。

我竟然还没看完就认为这行代码只是用来统计App启动的次数的,真是日了狗!殊不知没有这行代码的话,是无法接收到推送的,这行代码跟统计App的启动次数是两码事!

4、为什么一旦把应用关了就收不到推送?
除了跟着官方文档的说明步骤第四大步骤:轻松集成外,还要记得在自的项目中添加权限和在application标签中添加相应的组件,这样才能使应用不再运行在前台时,还可以开启一个在后台服务接受推送,才不会只能在应用开启时才能接到推送!
权限如下:

//下面列出的是必选的权限,还有可选的权限没有列出,例如前台是否可以显示通知这个可选权限
    
    
    
    
    
    
    
    
    
    
    
    

添加相应的友盟组件如下:

//注意一共有三处地方要将友盟得包名改为自己的包名

        
        
        
            
                
            
            
                
            
            
                
                
            
        
        
            
                
            
        
        
            
                
                
            
        
        
            
                //这是第一处地方要将友盟得包名改为自己的包名
            
        
        
            
                
            
        
        
            
                //这是第二处地方要将友盟得包名改为自己的包名
            
            
                //这是第三处地方要将友盟得包名改为自己的包名
            
            
                
                
            
        

        

        
            
                
            
            
                
            
        

        
            
                
            
            
                
            
            
                
            
            
                
            
        
        
        

5、关于获取不到device_token的问题——参考友盟官方论坛
本人证实可行的方法:
【原理:因为首次获取device_token时用到的是 mPushAgent.enable(new IUmengRegisterCallback(),这种异步回调来获取device_token。注意点有两个:
第一:正是因为是异步回调的获取,所以不能保证在用到device_token的时候就已经完成了异步回调获取,所以会造成device_token还没获取到就已经执行了调用device_token的代码,造成device_token为空的原因,所以解决方法是一定要把那些用到device_token的全部代码放在获取到device_token的代码的后面,如第39-39行
第二:注意到第一点没有?首次获取device_token时用到的是 mPushAgent.enable(new IUmengRegisterCallback(),因为是首次启动应用及安装后运行的这种情况才会执行到它,如果退出应用后再次打开时就不走这个方法了,所以要做好是否第一次启动应用的判断,如第10-11行、36-37行、40-41行都是对是否第一次启动应用的判断以及数值记录】

private PushAgent mPushAgent;
private String device_token;
private static final int REQUEST_CODE=200;
private SharedPreferences sp;
private SharedPreferences.Editor editor;
    
mPushAgent = PushAgent.getInstance(this);
        mPushAgent.onAppStart();
      //在这里判断是否是第一次启动应用
        Boolean isFirstOpen=sp.getBoolean("isFirstOpen",true);//默认是true,第一次启动!
        if(isFirstOpen){//如果是第一次启动
            Log.i("Lee","第一次启动应用");
             mPushAgent.enable(new IUmengRegisterCallback() {//用这种回调方法的话,只有在首次安装时才会执行!用于初次获取测试设备的Device Token。
            @Override
            public void onRegistered(final String s) {
                Log.i("Lee","go into onRegistered()");
                new Handler().post(new Runnable() {
                    @Override
                    public void run() {
                        Log.i("Lee","go into run()");
                        int count=0;
                        do {//关键是在这里一直循环获取device_token,这里是在主线程不断循环,为什么不会造成ANR?难道是异步回调的原因吗?
                            count++;
                            device_token = UmengRegistrar.getRegistrationId(SetLanguage.this);
                            // device_token = mPushAgent.getRegistrationId();
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e)
                            {
                                Log.i("LeeInterruptedException",e.getMessage());
                            }
                        } while (TextUtils.isEmpty(device_token));//当device_token为null或""时,即还没获取到device_token,若是就继续循环
                        Log.i("Lee count",""+count);
                        Log.i("Lee ——onRegistered", "device_token=" + device_token);

                        editor.putBoolean("isFirstOpen",false);//已运行过应用一次,
                        editor.commit();
                        //以下是添加拿到device_token后的操作
                         AAAAAA..................
        }else {
            Log.i("Lee","不是第一次启动应用");
            //mPushAgent.enable();//因为上面已经开启了mPushAgent.enable(new IUmengRegisterCallback(),所以不用再次开启mPushAgent.enable()
            //device_token = UmengRegistrar.getRegistrationId(this);//使用这一句跟下面这句是一样的
            device_token = mPushAgent.getRegistrationId();
            Log.i("Lee ——Not onRegistered", "device_token=" + device_token);
            //以下是添加拿到device_token后的操作
         AAAAAA..................
        }

下面这个是对上面代码的一些优化,因为经过试验,就算是写了循环去获取device_token ,但是结果显示循环只执行了一次,所以说用不着循环(如果你过大胆的话,不过建议还是要用循环比较安全保守)

PushAgent mPushAgent = PushAgent.getInstance(this);
         mPushAgent.onAppStart();
         mPushAgent.enable(new IUmengRegisterCallback() {
            @Override
            public void onRegistered(final String registrationId) {
            //onRegistered方法的参数registrationId即是device_token
                //new Handler().post(new Runnable() {
                //    @Override
                //    public void run() {
                //        Log.i("xiyuan", "device_token=" + registrationId);
                //    }
               // });
//其实可以直接不写一个handler来执行一个runnable,然后再Run方法里打log,可以直接在onRegistered里直接打一个Log(不用写handler,如下)                Log.i("xiyuan", "device_token=" + s);
            }
        });
        //mPushAgent.enable();//因为上面已经开启了mPushAgent.enable(new IUmengRegisterCallback(),所以不用再次开启mPushAgent.enable()
       //String device_token = UmengRegistrar.getRegistrationId(this);//使用这一句跟下面这句是一样的
//关键点是这里,不要在onRegistered方法里获取device_token,虽然onRegistered方法的参数registrationId就是device_token,但是经过本人实践,是获取不到的!所以才会在enable后加上下面这句。
       String device_token = mPushAgent.getRegistrationId();
        Log.i("xiyuani 2", "device_token=" + device_token);

下面是自己另外做的调试代码,错误例子:

   //不使用异步的回调去一次获取device_token,第一次安装时获取不到,但那时第二次启动时可以获取到
//        mPushAgent.enable();
//        device_token = mPushAgent.getRegistrationId();
//        //device_token = UmengRegistrar.getRegistrationId(SetLanguage.this);
//        Log.i("Lee —NoCallBack", "device_token=" + device_token);

        //不使用异步的回调去循环获取device_token,这样的不断循环会出现ANR!
//        mPushAgent.enable();
//        int count=0;
//        do {//关键是在这里一直循环获取device_token
//            count++;
//            device_token = mPushAgent.getRegistrationId();
//            //device_token = UmengRegistrar.getRegistrationId(SetLanguage.this);
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e)
//            {
//                Log.i("LeeInterruptedException",e.getMessage());
//            }
//        } while (TextUtils.isEmpty(device_token));//判断device_token是否为空,若是就继续循环
//        Log.i("Lee count",""+count);
//        Log.i("Lee —NoCallBack", "device_token=" + device_token);

下面这个是用计时器去不断获取device_token ,但那时还没验证

 if (device_token.isEmpty()) {
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (device_token.isEmpty() && count < 10) {
                        String temp = UmengRegistrar.getRegistrationId(SetLanguage.this);
                        if (temp == null || temp.isEmpty()) {
                            count++;
                        } else {
                            device_token = temp;
                            count = 0;
                        }
                    } else {
                        count = 0;
                        cancel();
                        Log.d("device_token1", "task has cancle and deviceToken=" + device_token);
                    }
                }
            }, 0, 800);
        }

6、关于API23 6.0的系统集成友盟时,权限android.permission.WRITE_SETTINGS"——系统设置权限的授权的解决方案

android.permission.WRITE_SETTINGS不能自动授权,也不能运行时请求授权,咋整啊?通过打开Intent来让用户设置。貌似SETTINGS的权限只能这么处理,from CommonsWare research Android 6.0 changes

 @TargetApi(Build.VERSION_CODES.M)//当现在运行程序的系统是API23时才会执行这个方法
    public void permissionToWRITE_SETTINGS(){
        if(Build.VERSION.SDK_INT >= 23){
            if(!Settings.System.canWrite(this)){
            //打开设置界面让用户设置是否授权系统设置权限
                Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
                        Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, REQUEST_CODE);
            }
        }

    }
    @TargetApi(Build.VERSION_CODES.M)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE) {
            if (Settings.System.canWrite(this)) {
                //检查返回结果
                Toast.makeText(SetLanguage.this, "WRITE_SETTINGS permission granted", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(SetLanguage.this, "WRITE_SETTINGS permission not granted", Toast.LENGTH_SHORT).show();
            }
        }
    }

7、在友盟注册时忽略的一个小问题导致接收不到推送
官方文档说明如下:


此处输入图片的描述

app_master_secret要填写在安卓端的androidmanifest中还是只是填写在服务器的配置中?还是两个都要填写?不管怎样,两个端都写上就最安全!
使用情况:在有自己的服务器转接友盟的推送时,记得加上自己的服务器IP地址


此处输入图片的描述

你可能感兴趣的:(接入友盟推送的实战总结)