极光推送

jianshu_0031.jpg

极光官网

  1. 注册
  2. 创建应用
  3. 生成AppKey 、Master Secret

集成指南

文章只介绍Android Studio Jcenter 自动集成

支持jcenter

buildscript {
    repositories {
        jcenter()
    }
    ......
}

allprojets {
    repositories {
        jcenter()
    }
}

配置gradle

因为项目本身自定义config.gradle ,所以都用rootProject.exty引用,和实际一样

android {
 ...
    defaultConfig {
        applicationId rootProject.ext.android["applicationId"]

        ndk {
            abiFilters 'armeabi'
        }
    }
  ...

    buildTypes {
        debug {
            manifestPlaceholders = [
                    JPUSH_PKGNAME: rootProject.ext.android["applicationId"],
                    JPUSH_APPKEY : rootProject.ext.jpush["debugAppKey"],
                    JPUSH_CHANNEL: rootProject.ext.jpush["channel"]]
        }

        release {
            manifestPlaceholders = [
                    JPUSH_PKGNAME: rootProject.ext.android["applicationId"],
                    JPUSH_APPKEY : rootProject.ext.jpush["releaseAppKey"],
                    JPUSH_CHANNEL: rootProject.ext.jpush["channel"]]
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

config.gradle代码

    jpush = [
            //JPush上注册的包名对应的appkey
            debugAppKey  : "",
            releaseAppKey: "",
            //暂时填写默认值即可
            channel      : "developer-default"
    ]

配置AndroidManifest

注意:在AndroidManifest中使用 ${applicationId} 引用gradle中定义的包名
这里分三块展示给大家

  1. 权限相关 @Required必填
    <!-- Required -->
    <permission
        android:name="${applicationId}.permission.JPUSH_MESSAGE"
        android:protectionLevel="signature" />
    <!-- Required -->
    <uses-permission android:name="${applicationId}.permission.JPUSH_MESSAGE" />
    <!-- Required -->
    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <!-- Optional. Required for location feature -->
    <!-- 用于开启 debug 版本的应用在6.0 系统上 层叠窗口权限 -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.GET_TASKS" />
  1. 核心功能 @Required必填
    <application
      ...
        <!-- Required SDK 核心功能-->
        <!-- 可配置android:process参数将PushService放在其他进程中 -->
        <service
            android:name="cn.jpush.android.service.PushService"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="cn.jpush.android.intent.REGISTER" />
                <action android:name="cn.jpush.android.intent.REPORT" />
                <action android:name="cn.jpush.android.intent.PushService" />
                <action android:name="cn.jpush.android.intent.PUSH_TIME" />
            </intent-filter>
        </service>

        <!-- since 3.0.9 Required SDK 核心功能-->
        <provider
            android:name="cn.jpush.android.service.DataProvider"
            android:authorities="${applicationId}.DataProvider"
            android:exported="false" />

        <!-- since 1.8.0 option 可选项。用于同一设备中不同应用的JPush服务相互拉起的功能。 -->
        <!-- 若不启用该功能可删除该组件,将不拉起其他应用也不能被其他应用拉起 -->
        <service
            android:name="cn.jpush.android.service.DaemonService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="cn.jpush.android.intent.DaemonService" />
                <category android:name="${applicationId}" />
            </intent-filter>
        </service>

        <!-- Required SDK核心功能-->
        <receiver
            android:name="cn.jpush.android.service.PushReceiver"
            android:enabled="true">
            <intent-filter android:priority="1000">
                <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" />
                <category android:name="${applicationId}" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.USER_PRESENT" />
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
            <!-- Optional -->
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_ADDED" />
                <action android:name="android.intent.action.PACKAGE_REMOVED" />

                <data android:scheme="package" />
            </intent-filter>
        </receiver>

        <!-- Required SDK核心功能-->
        <activity
            android:name="cn.jpush.android.ui.PushActivity"
            android:configChanges="orientation|keyboardHidden"
            android:exported="false"
            android:theme="@android:style/Theme.NoTitleBar">
            <intent-filter>
                <action android:name="cn.jpush.android.ui.PushActivity" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="${applicationId}" />
            </intent-filter>
        </activity>

        <!-- SDK核心功能-->
        <activity
            android:name="cn.jpush.android.ui.PopWinActivity"
            android:configChanges="orientation|keyboardHidden"
            android:exported="false"
            android:theme="@style/MyDialogStyle">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="${applicationId}" />
            </intent-filter>
        </activity>

        <!-- Required SDK核心功能-->
        <service
            android:name="cn.jpush.android.service.DownloadService"
            android:enabled="true"
            android:exported="false">

        </service>

        <!-- Required SDK核心功能-->
        <receiver android:name="cn.jpush.android.service.AlarmReceiver" />
    </application>
  1. 自定义广播接收器 @必填
        <!-- User defined.  For test only  用户自定义的广播接收器-->
        <receiver
            android:name=".jpush.JPushReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <!--Required  用户注册SDK的intent-->
                <action android:name="cn.jpush.android.intent.REGISTRATION" />
                <!--Required  用户接收SDK消息的intent-->
                <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED" />
                <!--Required  用户接收SDK通知栏信息的intent-->
                <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED" />
                <!--Required  用户打开自定义通知栏的intent-->
                <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED" />
                <!-- 接收网络变化 连接/断开 since 1.6.3 -->
                <action android:name="cn.jpush.android.intent.CONNECTION" />
                <category android:name="${applicationId}" />
            </intent-filter>
        </receiver>
/**
 * 自定义接收器
 * 如果不定义这个 Receiver,则:
 * 1) 默认用户会打开主界面
 * 2) 接收不到自定义消息
 */
public class JPushReceiver extends BroadcastReceiver {

    public void onReceive(Context context, Intent intent) {
        if (intent == null) {
            return;
        }

        String extraData = intent.getExtras().getString(JPushInterface.EXTRA_EXTRA);
        if (StringUtil.isEmpty(extraData)) {
            return;
        }

        PushEntity pushEntity = new Gson().fromJson(extraData, PushEntity.class);

        //推送消息 收到
        if(false && JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())){
   
        }

        //推送消息 点击
        if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {

        }
    }
}

一行代码

    /**
     * 极光推送
     */
    private void initPush() {
        // 设置开启日志,发布时请关闭日志
        JPushInterface.setDebugMode(BuildConfig.LOG_DEBUG);
        // 初始化 JPush
        JPushInterface.init(this);
    }

好了,到这里,我们就集成完了,去官网发送一条通知,测试一波

jianshu_0032.png

调试指南

  1. SDK启动过程
  • 检查AndroidManifest.xml中是否有配置AppKey,如果没有,则启动失败
  • 检查 Androidmanifest.xml文件配置的正确性,必须要保证“Android SDK 集成指南”中所有标注“
  • Required的部分都正确配置,否则启动失败
  • 检查 JPush SDK库文件的有效性,如果库文件无效,则启动失败
  • 检查网络是否可用,如果网络可用则连接服务器登录,否则启动失败
  • 登陆成功后可以从log中看到如下log
  1. 网络问题
  • 关闭代理
  • 网络不稳定
  1. 部分系统的特殊处理
    详情请查看极光推送官方文档

测试指南

之前我们有定义两个AppKey,为什么要有两个AppKey呢?

最开始我们只有一个AppKey,然后App上线后,需要测试推送,这时,发送的话,线上的用户都会收到推送消息,如果只针对用户推的话,难免测试服与线上服ID一致,还是会有少部分用户收到推送,然后与极光团队邮件沟通,解决方案就是重新注册账号,新建应用,得到测试AppKey,用来只做测试。这样线上和测试就分两条通道走了。

    buildTypes {
        debug {
            manifestPlaceholders = [
                    JPUSH_APPKEY : rootProject.ext.jpush["debugAppKey"],
        }

        release {
            manifestPlaceholders = [
                    JPUSH_APPKEY : rootProject.ext.jpush["releaseAppKey"],
        }
    }

gradle小技巧

jianshu_0033.png
jianshu_0034.png

这里需要gradle设置一下签名即可,使用简单
感叹gradle的强大,如果想深入了解的同学,请移步
Gradle入门(一)

高级API

应项目需求,采用设置别名的方式,这里也只介绍setAlias

  1. 注册 & 登录 成功后,设置uid为别名,下次进来不用重复设置别名,所以最好记录一个状态值
    @Override
    public void initPush() {
        if (UserCache.getInstance().getJPushStatus()) {
            return;
        }

        mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_ALIAS, localUid));
    }
  1. 接收消息,设置别名
    private final Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_SET_ALIAS:
                    JPushInterface.setAlias(MainActivity.this, (String) msg.obj, mAliasCallback);
                    break;
            }
        }
    };
  1. 设置别名的回调
    private final TagAliasCallback mAliasCallback = new TagAliasCallback() {
        @Override
        public void gotResult(int code, String alias, Set<String> tags) {

            switch (code) {
                case 0:
                    //设置成功,存储状态值
                    UserCache.getInstance().saveJPushSuccess();
                    break;
                case 6002:
                    //失败,重复设置
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_ALIAS, alias), 1000 * 60);
                    break;
                default:
                    break;
            }
        }
    };
  1. 退出登录,删除别名
    @Override
    public void loginOut() {
        // JPushInterface.deleteAlias(,); 也可以
        JPushInterface.setAlias(AppSettingActivity.this, "", null);
        exitActivity();
    }

其它

关于拉起

  1. 不是所有使用了极光服务的App都愿意开启拉起功能 来拉起别的应用或者被别的应用拉起
  2. 拉起同样会受到系统的限制,该功能只是尽量提高点重启的几率,相当于有比没有好
  3. 测试拉起的具体步骤方法
  4. 成功设置了拉起也不是说马上你杀死,推送测试他就能收到的,你要等他拉起成功

注意

互相拉起服务,使用的后果一定要考虑清楚

使用了互相拉起服务,确实,你们APP推送的及时到达率都提升了很多,但是,APP开启的一段时间里,手机会卡顿,因为会唤醒,同样注册了极光推送互相拉起服务的应用,手机里面有2-3个还好,用户还发现不了什么,如果手机里面有100,200,300个应用,那最少唤醒10- 30个,开启的一段时间,手机绝对会卡顿,所以为什么会有垃圾联盟了,为什么手机越用越卡。

当然也看你们产品定位,毕竟手机里面装100,200,300个应用的用户占少数,牺牲少部分用户,博得大部分群体也可以,看实际需求。

最后呢,我们的产品最开始开启互相拉起服务,一段时间我又删除了,就是关闭互相拉起服务,正常情况,APP不该唤醒其它应用,也不会被其它应用唤醒,结果,删除了,还是没法解决互相唤醒,现在就是想关关不掉!!!和极光服务沟通过,让我们多测试一下,现在也没时间测试,暂时记一个Bug,也有可能不是极光服务的问题。总之,慎重!

后记

上线后怎么测试推送和广播?
事情起因,测试人员不小心推送、广播全部人,结果,线上的用户都收到了 test 这样的信息,无法点击查看。其实,我也经常会收到新浪推送的test信息,真的非常影响用户体验。

iOS为什么不会出现这样的问题呢?
他们在设置时,已经有生产环境和开发环境,配置不同的签名,结合后端的业务,来推生产环境,还是开发环境,这样线上的用户就不会收到测试人员的推送

android怎么解决呢?

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