Home

Awesome

XPush

api I Star

一个轻量级、可插拔的Android消息推送框架。一键集成推送(极光推送、友盟推送、信鸽推送、华为、小米推送等),提供有效的保活机制,支持推送的拓展,充分解耦推送和业务逻辑,解放你的双手!

在提issue前,请先阅读【提问的智慧】,并严格按照issue模板进行填写,节约大家的时间。

在使用前,请一定要仔细阅读使用说明文档,重要的事情说三遍!!!

在使用前,请一定要仔细阅读使用说明文档,重要的事情说三遍!!!

在使用前,请一定要仔细阅读使用说明文档,重要的事情说三遍!!!

关于我

公众号掘金知乎CSDN简书思否哔哩哔哩今日头条
我的Android开源之旅点我点我点我点我点我点我点我

特征

Star趋势图

Stargazers over time

组成结构

本框架借鉴了OnePush(目前已不维护了)中的部分思想,加之我3年消息推送的经验,形成了如下几个部分:

以上5个组成部分可以根据你自身的业务需求进行自定义。

消息推送流程

在后台发出一则推送消息后:

第三方推送平台 --- (消息) ---> 第三方推送平台内部的接收消息的Receiver --->(重写其接收的方法)---> IPushDispatcher ---> (转发消息内容为XPushMsg/XPushCommand)---> IPushReceiver ---> (如不使用XPushManager提供的消息管理,这里直接结束)

    【使用XPushManager提供的消息管理】:---IPushReceiver---> XPushManager -----> IMessageFilterStrategy --->(对消息进行过滤处理)---> IMessageObservable ---> (消息转发到具体订阅的地方)

为什么要做这个项目

做过Android消息推送的人都知道,Android不仅设备碎片化严重,推送平台也是五花八门的。早在2017年工信部就号召所有的厂商来制定统一的Android消息推送平台,可到现在也没有下文(究其原因还是这其中的利益太大了,谁也不想妥协)。

可是我们也不能将希望全都寄托在这个完全没有定数的事件上,代码终归要写,功能终归要上,与其受制于人,不如自己革命,搞一个自己能控制的消息推送全平台解决方案来得靠谱。

可能有人又会说,现在友盟和信鸽都支持厂商推送的集成,为何你自己还要搞一套呢?如果你对推送的及时性和到达率都没什么要求的话,其实也是无所谓的(实践证明,友盟并不好用,信鸽还可以)。在这里我需要说明的是,你不可能把自己的命运交到别人的手里,推送有别于其他的业务,相对来说比较复杂,需要处理大批量的事件消息,对服务器的要求比较大,你愿意把你的推送消息交给第三方推送平台去处理?再说了,你能强制你们后台接入指定第三方的推送平台?如果都不能,与其受制于人,何不把这些命运把握在自己的手上,那么写出来的功能自己心安啊。

之前在QQ交流群里一直有人希望我开源一个消息推送框架,其实我在上一家公司的时候就写了一个推送框架,只不过捆绑业务太深,加之避开泄密之嫌,也就没有开源的必要。此次的推送框架完全是重新写了一个,加之全新的设计,会使框架更加通用,灵活。

演示(请star支持)

程序演示

xpush_demo.gif

Demo下载

XPush全平台集成Demo

XPushDemo

download_xpush.png

信鸽厂商集成Demo

信鸽demo

download_xgdemo.png


快速集成指南

添加Gradle依赖

1.先在项目根目录的 build.gradle 的 repositories 添加:

allprojects {
    repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}

2.添加XPush主要依赖:

dependencies {
  ...
  //推送核心库
  implementation 'com.github.xuexiangjys.XPush:xpush-core:1.0.1'
  //推送保活库
  implementation 'com.github.xuexiangjys.XPush:keeplive:1.0.1'
}

3.添加第三方推送依赖(根据自己的需求进行添加,当然也可以全部添加)

dependencies {
  ...
  //选择你想要集成的推送库
  implementation 'com.github.xuexiangjys.XPush:xpush-jpush:1.0.1'
  implementation 'com.github.xuexiangjys.XPush:xpush-umeng:1.0.1'
  implementation 'com.github.xuexiangjys.XPush:xpush-huawei:1.0.1'
  implementation 'com.github.xuexiangjys.XPush:xpush-xiaomi:1.0.1'
  implementation 'com.github.xuexiangjys.XPush:xpush-xg:1.0.1'
}

初始化XPush配置

1.注册消息推送接收器。方法有两种,选其中一种就行了。

    <!--自定义消息推送接收器-->
    <receiver android:name=".push.CustomPushReceiver">
        <intent-filter>
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_CONNECT_STATUS_CHANGED" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION_CLICK" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_MESSAGE" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_COMMAND_RESULT" />

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

    <!--默认的消息推送接收器-->
    <receiver android:name="com.xuexiang.xpush.core.receiver.impl.XPushReceiver">
        <intent-filter>
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_CONNECT_STATUS_CHANGED" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_NOTIFICATION_CLICK" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_MESSAGE" />
            <action android:name="com.xuexiang.xpush.core.action.RECEIVE_COMMAND_RESULT" />

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

注意,如果你的Android设备是8.0及以上的话,静态注册的广播是无法正常生效的,解决的方法有两种:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    //Android8.0静态广播注册失败解决方案一:动态注册
    XPush.registerPushReceiver(new CustomPushReceiver());

    //Android8.0静态广播注册失败解决方案二:修改发射器
    XPush.setIPushDispatcher(new Android26PushDispatcherImpl(CustomPushReceiver.class));
}

2.在AndroidManifest.xml的application标签下,添加第三方推送客户端实现类.

需要注意的是,这里注册的PlatformNamePlatformCode必须要和推送客户端实现类中的一一对应才行。

<!--name格式:XPush_[PlatformName]_[PlatformCode]-->
<!--value格式:对应客户端实体类的全类名路径-->

<!--如果引入了xpush-jpush库-->
<meta-data
    android:name="XPush_JPush_1000"
    android:value="com.xuexiang.xpush.jpush.JPushClient" />

<!--如果引入了xpush-umeng库-->
<meta-data
    android:name="XPush_UMengPush_1001"
    android:value="com.xuexiang.xpush.umeng.UMengPushClient" />
    
<!--如果引入了xpush-huawei库-->
<meta-data
    android:name="XPush_HuaweiPush_1002"
    android:value="com.xuexiang.xpush.huawei.HuaweiPushClient" />

<!--如果引入了xpush-xiaomi库-->
<meta-data
    android:name="XPush_MIPush_1003"
    android:value="com.xuexiang.xpush.xiaomi.XiaoMiPushClient" />
    
<!--如果引入了xpush-xg库-->
<meta-data
    android:name="XPush_XGPush_1004"
    android:value="@string/xpush_xg_client_name" />

3.添加第三方AppKey和AppSecret.

这里的AppKey和AppSecret需要我们到各自的推送平台上注册应用后获得。注意如果使用了xpush-xiaomi,那么需要在AndroidManifest.xml添加小米的AppKey和AppSecret(注意下面的“\ ”必须加上,否则获取到的是float而不是String,就会导致id和key获取不到正确的数据)。

<!--极光推送静态注册-->
<meta-data
    android:name="JPUSH_CHANNEL"
    android:value="default_developer" />
<meta-data
    android:name="JPUSH_APPKEY"
    android:value="a32109db64ebe04e2430bb01" />

<!--友盟推送静态注册-->
<meta-data
    android:name="UMENG_APPKEY"
    android:value="5d5a42ce570df37e850002e9" />
<meta-data
    android:name="UMENG_MESSAGE_SECRET"
    android:value="4783a04255ed93ff675aca69312546f4" />
    
<!--华为HMS推送静态注册-->
<meta-data
    android:name="com.huawei.hms.client.appid"
    android:value="101049475"/>

<!--小米推送静态注册,下面的“\ ”必须加上,否则将无法正确读取-->
<meta-data
    android:name="MIPUSH_APPID"
    android:value="\ 2882303761518134164"/>
<meta-data
    android:name="MIPUSH_APPKEY"
    android:value="\ 5371813415164"/>
    
<!--信鸽推送静态注册-->
<meta-data
    android:name="XGPUSH_ACCESS_ID"
    android:value="2100343759" />
<meta-data
    android:name="XGPUSH_ACCESS_KEY"
    android:value="A7Q26I8SH7LV" />

4.在Application中初始化XPush

初始化XPush的方式有两种,根据业务需要选择一种方式就行了:

/**
 * 静态注册初始化推送
 */
private void initPush() {
    XPush.debug(BuildConfig.DEBUG);
    //静态注册,指定使用友盟推送客户端
    XPush.init(this, new UMengPushClient());
    XPush.register();
}
/**
 * 动态注册初始化推送
 */
private void initPush() {
    XPush.debug(BuildConfig.DEBUG);
    //动态注册,根据平台名或者平台码动态注册推送客户端
    XPush.init(this, new IPushInitCallback() {
        @Override
        public boolean onInitPush(int platformCode, String platformName) {
            String romName = RomUtils.getRom().getRomName();
            if (romName.equals(SYS_EMUI)) {
                return platformCode == HuaweiPushClient.HUAWEI_PUSH_PLATFORM_CODE && platformName.equals(HuaweiPushClient.HUAWEI_PUSH_PLATFORM_NAME);
            } else if (romName.equals(SYS_MIUI)) {
                return platformCode == XiaoMiPushClient.MIPUSH_PLATFORM_CODE && platformName.equals(XiaoMiPushClient.MIPUSH_PLATFORM_NAME);
            } else {
                return platformCode == JPushClient.JPUSH_PLATFORM_CODE && platformName.equals(JPushClient.JPUSH_PLATFORM_NAME);
            }
        }
    });
    XPush.register();
}

如何使用XPush

1、推送的注册和注销

2、推送的标签(tag)处理

需要注意的是,友盟推送和信鸽推送目前暂不支持标签的获取,华为推送不支持标签的所有操作,小米推送每次只支持一个标签的操作。

3、推送的别名(alias)处理

需要注意的是,友盟推送和信鸽推送目前暂不支持别名的获取,华为推送不支持别名的所有操作。

4、推送消息的接收

这里需要注意的是,消息订阅的回调并不一定是在主线程,因此在回调中如果进行了UI的操作,一定要确保切换至主线程。下面演示代码中使用了我的另一个开源库XAOP,只通过@MainThread注解就能自动切换至主线程,可供参考。

/**
 * 初始化监听
 */
@Override
protected void initListeners() {
    XPushManager.get().register(mMessageSubscriber);
}

private MessageSubscriber mMessageSubscriber = new MessageSubscriber() {
    @Override
    public void onMessageReceived(CustomMessage message) {
        showMessage(String.format("收到自定义消息:%s", message));
    }

    @Override
    public void onNotification(Notification notification) {
        showMessage(String.format("收到通知:%s", notification));
    }
};

@MainThread
private void showMessage(String msg) {
    tvContent.setText(msg);
}


@Override
public void onDestroyView() {
    XPushManager.get().unregister(mMessageSubscriber);
    super.onDestroyView();
}

5、推送消息的过滤处理

/**
 * 初始化监听
 */
@Override
protected void initListeners() {
    XPushManager.get().addFilter(mMessageFilter);
}

private IMessageFilter mMessageFilter = new IMessageFilter() {
    @Override
    public boolean filter(Notification notification) {
        if (notification.getContent().contains("XPush")) {
            showMessage("通知被拦截");
            return true;
        }
        return false;
    }

    @Override
    public boolean filter(CustomMessage message) {
        if (message.getMsg().contains("XPush")) {
            showMessage("自定义消息被拦截");
            return true;
        }
        return false;
    }
};

@Override
public void onDestroyView() {
    XPushManager.get().removeFilter(mMessageFilter);
    super.onDestroyView();
}

6、推送通知的点击处理

对于通知的点击事件,我们可以处理得更优雅,自定义其点击后的动作,打开我们想让用户看到的页面。

我们可以在全局消息推送的接收器IPushReceiver中的onNotificationClick回调中,增加打开指定页面的操作。

@Override
public void onNotificationClick(Context context, XPushMsg msg) {
    super.onNotificationClick(context, msg);
    //打开自定义的Activity
    Intent intent = IntentUtils.getIntent(context, TestActivity.class, null, true);
    intent.putExtra(KEY_PARAM_STRING, msg.getContent());
    intent.putExtra(KEY_PARAM_INT, msg.getId());
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    ActivityUtils.startActivity(intent);
}

需要注意的是,这需要你在消息推送平台推送的通知使用的是自定义动作或者打开指定页面类型,并且传入的Intent uri 内容满足如下格式:

xpush://com.xuexiang.xpush/notification?title=这是一个通知&content=这是通知的内容&extraMsg=xxxxxxxxx&keyValue={"param1": "1111", "param2": "2222"}

当然你也可以自定义传入的Intent uri 格式,具体可参考项目中的XPushNotificationClickActivityAndroidManifest.xml


推送平台说明

目前已支持的推送平台

推送平台平台名平台码模块名客户端类
极光推送JPush1000xpush-jpushcom.xuexiang.xpush.jpush.JPushClient
友盟推送UMengPush1001xpush-umengcom.xuexiang.xpush.umeng.UMengPushClient
华为推送HuaweiPush1002xpush-huaweicom.xuexiang.xpush.huawei.HuaweiPushClient
小米推送MIPush1003xpush-xiaomicom.xuexiang.xpush.xiaomi.XiaoMiPushClient
信鸽推送XGPush1004xpush-xgcom.xuexiang.xpush.xg.XGPushClient

除此之外,如果你使用MQTT协议来做消息推送的话,我也同样提供了案例给你:XPush-MQTT

推送平台的注意事项

极光推送平台所有特性都支持。

友盟推送

信鸽推送

华为推送

小米推送

如何拓展第三方推送

由于Android推送平台的众多,目前本项目不可能也没必要提供所有推送平台的集成库。如果你想使用的推送平台在我这没有找到对应的集成库的话,那么就需要你自己写一个了。

其实拓展一个第三方推送库也不是很难,只要遵循以下4步骤就可以完成了:

IPushClient接口方法详细如下:

public interface IPushClient {
    /**
     * 初始化【必须】
     *
     * @param context
     */
    void init(Context context);
    /**
     * 注册推送【必须】
     */
    void register();
    /**
     * 注销推送【必须】
     */
    void unRegister();
    /**
     * 绑定别名【别名是唯一的】
     *
     * @param alias 别名
     */
    void bindAlias(String alias);
    /**
     * 解绑别名
     *
     * @param alias 别名
     */
    void unBindAlias(String alias);
    /**
     * 获取别名
     */
    void getAlias();
    /**
     * 增加标签
     *
     * @param tag 标签
     */
    void addTags(String... tag);
    /**
     * 删除标签
     *
     * @param tag 标签
     */
    void deleteTags(String... tag);
    /**
     * 获取标签
     */
    void getTags();
    /**
     * @return 获取推送令牌
     */
    String getPushToken();
    /**
     * 注意千万不要重复【必须】
     * @return 获取平台码
     */
    int getPlatformCode();
    /**
     * 注意千万不要重复【必须】
     * @return 获取平台名
     */
    String getPlatformName();
}

主要调用以下五个方法:

(1)XPush.transmitMessage(): 转发自定义(透传)消息.

(2)XPush.transmitNotification(): 转发通知到达消息.

(3)XPush.transmitNotificationClick(): 转发通知点击事件.

(4)XPush.transmitCommandResult(): 转发IPushClient命令执行结果.

(5)XPush.transmitConnectStatusChanged(): 转发推送连接状态发生改变的事件.

以上即完成了推送平台的集成。剩下的就是在初始化XPush的时候对推送平台进行选择了.如果你看完了还是不会的话,你可以参考项目中的xpush-xiaomixpush-huawei.

保活机制说明

这里提供的应用保活机制也是借鉴了前人终结出来的各种方案的混合处理。目前在9.0及以下版本都能有很好的保活效果(只要你不主动杀死程序),如果你的应用希望能够一直在后台运行(比如推送服务)而不被系统自动杀死的话,可以尝试一下。需要注意的是,程序保活并不代表能做到程序杀不死,除非你把你的应用做成系统应用或者加入到系统的白名单内,否则也只是提高了程序的优先级权重,减少程序被系统回收杀死的概率而已。

关于保活机制的使用可以参考保活机制使用


实体介绍

XPushMsg

推送消息转译实体,携带消息的原始数据

字段名类型备注
mIdint消息ID / 状态
mTitleString通知标题
mContentString通知内容
mMsgString自定义(透传)消息
mExtraMsgString消息拓展字段
mKeyValueString消息键值对

Notification

推送通知,由XPushMsg转化而来

字段名类型备注
mIdint消息ID / 状态
mTitleString通知标题
mContentString通知内容
mExtraMsgString消息拓展字段
mKeyValueString消息键值对

CustomMessage

自定义(透传)消息,由XPushMsg转化而来

字段名类型备注
mMsgString自定义(透传)消息
mExtraMsgString消息拓展字段
mKeyValueString消息键值对

XPushCommand

IPushClient执行相关命令的结果信息实体

字段名类型备注
mTypeint命令类型
mResultCodeint结果码
mContentString命令内容
mExtraMsgString拓展字段
mErrorString错误信息

常量介绍

CommandType

命令的类型

命令名命令码备注
TYPE_REGISTER2000注册推送
TYPE_UNREGISTER2001注销推送
TYPE_ADD_TAG2002添加标签
TYPE_DEL_TAG2003删除标签
TYPE_GET_TAG2004获取标签
TYPE_BIND_ALIAS2005绑定别名
TYPE_UNBIND_ALIAS2006解绑别名
TYPE_GET_ALIAS2007获取别名
TYPE_AND_OR_DEL_TAG2008添加或删除标签

ResultCode

命令的结果码

结果名结果码备注
RESULT_OK0成功
RESULT_ERROR1失败

ConnectStatus

推送连接状态

状态名状态码备注
DISCONNECT10已断开
CONNECTING11连接中
CONNECTED12已连接

混淆配置

# XPush的混淆
-keep class * extends com.xuexiang.xpush.core.IPushClient{*;}
-keep class * extends com.xuexiang.xpush.core.receiver.IPushReceiver{*;}

# 极光推送混淆
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-dontwarn cn.jiguang.**
-keep class cn.jiguang.** { *; }
-keep class * extends cn.jpush.android.service.JPushMessageReceiver{*;}

# umeng推送
-dontwarn com.umeng.**
-dontwarn com.taobao.**
-dontwarn anet.channel.**
-dontwarn anetwork.channel.**
-dontwarn org.android.**
-dontwarn org.apache.thrift.**
-dontwarn com.xiaomi.**
-dontwarn com.huawei.**
-dontwarn com.meizu.**
-keep class com.taobao.** {*;}
-keep class org.android.** {*;}
-keep class anet.channel.** {*;}
-keep class com.xiaomi.** {*;}
-keep class com.huawei.** {*;}
-keep class com.meizu.** {*;}
-keep class org.apache.thrift.** {*;}
-keep class com.alibaba.sdk.android.**{*;}
-keep class com.ut.**{*;}
-keep class com.ta.**{*;}

# 信鸽推送
-keep class com.tencent.android.tpush.** {*;}
-keep class com.tencent.mid.** {*;}
-keep class com.qq.taf.jce.** {*;}
-keep class com.tencent.bigdata.** {*;}

# 华为推送
-keep class com.huawei.hms.**{*;}
-keep class com.huawei.android.hms.agent.**{*;}

# 小米推送
-keep class * extends com.xiaomi.mipush.sdk.PushMessageReceiver{*;}

特别感谢

如果觉得项目还不错,可以考虑打赏一波

你的打赏是我维护的动力,我将会列出所有打赏人员的清单在下方作为凭证,打赏前请留下打赏项目的备注!

pay.png

联系方式

更多资讯内容,欢迎扫描关注我的个人微信公众号:【我的Android开源之旅】

gzh_weixin.jpg