接入友盟推送的实战总结

接入友盟推送实战

标签(空格分隔): Android

请注意:###

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

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

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


捕获.PNG

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

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

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

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

//下面列出的是必选的权限,还有可选的权限没有列出,例如前台是否可以显示通知这个可选权限
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    

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

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

        <receiver
            android:name="com.umeng.message.NotificationProxyBroadcastReceiver"
            android:exported="false" >
        </receiver>
        <receiver
            android:name="com.umeng.message.SystemReceiver"
            android:process=":push" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED" />
                <data android:scheme="package" />
            </intent-filter>
        </receiver>
        <receiver
            android:name="com.umeng.message.MessageReceiver"
            android:exported="false"
            android:process=":push" >
            <intent-filter>
                <action android:name="org.agoo.android.intent.action.RECEIVE" />
            </intent-filter>
        </receiver>
        <receiver
            android:name="com.umeng.message.ElectionReceiver"
            android:process=":push" >
            <intent-filter>
                <action android:name="org.agoo.android.intent.action.ELECTION_RESULT_V4" />
                <category android:name="umeng" />
            </intent-filter>
        </receiver>
        <receiver
            android:name="com.umeng.message.RegistrationReceiver"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.zun1.whenask.intent.action.COMMAND" />//这是第一处地方要将友盟得包名改为自己的包名
            </intent-filter>
        </receiver>
        <receiver android:name="com.umeng.message.UmengMessageBootReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <service
            android:name="com.umeng.message.UmengService"
            android:label="PushService"
            android:exported="true"
            android:process=":push" >
            <intent-filter>
                <action android:name="com.zun1.whenask.intent.action.START" />//这是第二处地方要将友盟得包名改为自己的包名
            </intent-filter>
            <intent-filter>
                <action android:name="com.zun1.whenask.intent.action.COCKROACH" />//这是第三处地方要将友盟得包名改为自己的包名
            </intent-filter>
            <intent-filter>
                <action android:name="org.agoo.android.intent.action.PING_V4" />
                <category android:name="umeng" />
            </intent-filter>
        </service>

        <service android:name="com.umeng.message.UmengIntentService"
            android:process=":push" />

        <service
            android:name="com.umeng.message.UmengMessageIntentReceiverService"
            android:process=":push"
            android:exported="true" >
            <intent-filter>
                <action android:name="org.android.agoo.client.MessageReceiverService" />
            </intent-filter>
            <intent-filter>
                <action android:name="org.android.agoo.client.ElectionReceiverService" />
            </intent-filter>
        </service>

        <service android:name="com.umeng.message.UmengMessageCallbackHandlerService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.umeng.messge.registercallback.action" />
            </intent-filter>
            <intent-filter>
                <action android:name="com.umeng.message.unregistercallback.action"/>
            </intent-filter>
            <intent-filter>
                <action android:name="com.umeng.message.message.handler.action"/>
            </intent-filter>
            <intent-filter>
                <action android:name="com.umeng.message.autoupdate.handler.action"/>
            </intent-filter>
        </service>
        <service android:name="com.umeng.message.UmengDownloadResourceService" />
        

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地址


此处输入图片的描述
此处输入图片的描述
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • 上周,公司要实现推送通知的功能,并决定在项目中集成友盟推送的 SDK来代替之前集成的云巴推送。 云巴推送是什么鬼?...
    4VZhang阅读 13,041评论 35 15
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,370评论 25 707
  • 极光推送: 1.JPush当前版本是1.8.2,其SDK的开发除了正常的功能完善和扩展外也紧随苹果官方的步伐,SD...
    Isspace阅读 6,694评论 10 16
  • 猫喜欢吃鱼,可猫不会游泳,鱼喜欢吃蚯蚓,可鱼不能上岸 ; 一个整宿睡的很好的人,会嫉妒一个睡眠质量不怎么好、甚至半...
    不忘初心___阅读 193评论 0 1
  • 短暂的分身术训练营结束了,在这几天里学到了不少实用性很强的知识,在以后的工作生活中会多加运用。 一次刻意训练 在这...
    忘却的纪念wp阅读 333评论 0 0