win10系统家园 - 专注分享最好用的电脑系统

当前位置: win10系统家园 >  系统教程 >  电脑教程 >  android接收推送消息推送消息

android接收推送消息推送消息 Android 推送服务一行代码实现

更新时间:2023-05-04 11:49:07作者:jiang

  android接收推送消息推送消息,在移动互联网时代,推送服务已成为移动应用开发中不可或缺的一部分。而针对Android平台的推送服务更是备受关注。本文将介绍一种仅需一行代码即可实现Android推送服务的方法,帮助开发者快速搭建推送服务,提升应用的用户体验。

Android 推送服务一行代码实现

推送消息主要用来提示用户一些重要信息,或者引导用户进入App;消息的到达率,及时性,点击后消息处理等,每一个节点,都影响着用户体验;所以,实现一个友好的推送交互,是非常有意义的。

文章目录:

目前现状实现分析功能实现总结1.目前现状

目前国内推送现状,国产ROM无法使用GCM(Google Cloud Messaging,主要用于消息推送),为了提升用户体验,一些国内的厂商,第三方,不得不推出自己的推送方案,按照推送通道,大致划分为3种,系统级推送、三方推送、混合推送。

1、系统推送

2、三方推送

特征App级长连接推送,进程独立,由系统广播事件保活,链式唤醒。厂商友盟推送,腾讯信鸽推送,百度云推送等。优点通用性强,各类ROM都可通用,进程存活时,消息到达率与系统级推送相当。缺点进程被杀死,或其他App没有链式唤醒,导致消息到达率低。单独守护进程,链式唤醒,也导致耗电高。

3、混合推送

特征同时包含系统级长连接通道和 App 级长连接通道。厂商小米推送,极光推送,阿里云推送等。优点成功率相对于第三方高,适用性比纯系统推送强。缺点接入成本相对比较高。

推送按消息类型划分,分为通知消息和透传消息,通知消息由推送SDK来处理,消息格式较为固定,由系统公共通道完成,到达率有保证;透传消息需要App自己来实现,可以自定义消息,灵活度高,是由App通道来完成,与三方推送没有太大的区别。

2.实现分析

由以上现状分析和业务需求,最终选择使用系统推送 + 通知消息方案实现消息推送。为了保证消息到达率高,大品牌,比如华为,小米,根据ROM类型使用自家的推送,其他品牌统一使用小米推送;小米推送的完成度更高,在系统推送的基础上实现了三方通道,兼容了非 MIUI 的 Android 机;在此基础上,如果其他品牌(vivo,OPPO)消息到达率低,只需要增加相应ROM的推送SDK,保证消息到达率。

通过调研几家App发现,有些点击了推送消息,不了了之,没有任何动作,比如打开App,或者跳转到相应的界面;还有一些是进入了相应的界面,后退,又回到了桌面,此种情况属于没有判断App是否运行,或者App已经在后台运行,没有启动到前台,这样的体验非常的不舒服。

从点击消息,处理消息,页面跳转,整个过程,用户体验是非常的重要,那怎么样实现一个完美的用户体验,分为以下几种情况。

画了一个XMind思维导向图,看着更清楚。

android接收推送消息推送消息 Android 推送服务一行代码实现

通过以上逻辑实现,包含了所有的可能情况,用户点开推送消息进入相应界面,关闭界面,依旧App在前台运行,符合用户预期操作习惯。

3.功能实现

建立Push Module,为什么这样做?

每家厂商的推送SDK,都用jar或依赖来实现。又要到AndroidManifest中注册大量的清单内容,注册广播或者Service等,一大堆的内容,放到Base模块,显然不合理;推送相对于业务逻辑,是非常独立的,所以单独建立Module,与其他业务逻辑隔离,也符合组件化设计思想。

项目组件化方案实现,请看

实现组件化,接入推送业务逻辑,会变得非常简单。

在项目中接入小米,华为等推送,按照官方文档接入即可;接下来需要整合各家推送SDK,以下分别从初始化推送,规范数据来源,接收数据,消息初始化前准备,启动App,分发消息,页面跳转,7个流程,介绍消息推送方案实现。

1、初始化推送

class PushInit {

    companion object {
        // app是否已经初始化
        var shouldInit = false

        fun with(): PushInit {
            return PushInit()
        }
    }

    /**
     * 初始化
     */
    fun init(context: Context) {
        shouldInit = true

        if (OSUtils.isEmui()) {
            huaweiPushInit(context)
        } else {
            xiaomiPushInit()
        }

        // 有推送消息,需要处理
        val data = PushSetting.pushData
        if (!TextUtils.isEmpty(data)) {
            MessageHandler.messageHandle(context, data)
            PushSetting.pushData = ""
        }
    }
}

根据不同的手机ROM,初始化推送SDK,如果有推送消息,则进行消息分发;shouldInit,用来标识App是否已经打开,后面会讲到。

2、规范数据来源,App端统一使用Scheme协议接收数据,服务端API指定intent参数。

自定义Scheme协议,一个应用中通常会有多个推送消息类型,只需要定义一个参数“extraData”(值用字符串JSON实现),扩展性强。

val intent = Intent(Intent.ACTION_VIEW)
// Scheme协议(例如:pushscheme://com.xingzhi.android.components/deeplink/pushreceiver?)需要您自定义
intent.setData(Uri.parse("pushscheme://com.xingzhi.android.components/deeplink/pushreceiver?"))
 
// 往intent中添加参数,根据自己的需求进行添加参数
intent.putExtra("extraData", "{"code": 0, "data":{}}")
 
// 应用必须带上该Flag,如果不添加该选项有可能会显示重复的消息
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val intentUri = intent.toUri(Intent.URI_INTENT_SCHEME)
 
// 打印出的intentUri值就是设置到推送消息中intent字段的值
Log.d("intentUri", intentUri)

生成的IntentUri为:

intent://com.xingzhi.android.components/deeplink/pushreceiver?#Intent;scheme=pushscheme;launchFlags=0x4000000;S.extraData={};end

extraData中的数据格式为"{"code": 0, "data":T}",code为消息类型,用来跳转不同的界面,data是泛型,可自定义每个页面不同的数据。

3、接收数据,用一个没有布局的Activity来实现,注册AndroidManifest时申明Scheme协议。

<activity android:name=".activity.PushReceiverActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data
                android:host="${applicationId}"
                android:path="/deeplink/pushreceiver"
                android:scheme="pushscheme" />
    </intent-filter>
</activity>
class PushReceiverActivity : BaseActivity() {
    companion object {
        private const val EXTRA_DATA = "extraData"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val data = intent.getStringExtra(EXTRA_DATA)

        MessageHandler.init(this, data)
        finish()
    }

}

这样,就可以接收到服务端传递的extraData字段内容;当用户点击推送消息时,系统会发送intent,Scheme协议来接收消息,在PushReceiverActivity中就可以获取到intent内容,就可以分发消息了。

4、消息初始化前准备,根据业务逻辑,App是否启动,是否在后台运行等,上面用XMind分析过,直接上代码。

fun init(context: Context?, data: String?) {
    if (context == null || TextUtils.isEmpty(data)) {
        return
    }
    val shouldInit = PushInit.shouldInit
    // TODO 此处根据自身业务页面逻辑实现 "isLogin"
    val isLogin = true
    
    // 没有登录,没有打开app
    if (!isLogin || !shouldInit) {
        PushSetting.pushData = data!!
        launcherApp(context, shouldInit)
        return
    }
    
    // app是否在后台运行
    val isBackground = AppUtils.isAppBackground(context)
    if (isBackground) {
        launcherApp(context, shouldInit)
    }
    
    // 分发消息
    messageHandle(context, data!!)
}

此处用到了val shouldInit = PushInit.shouldInit,为什么这样实现?当你点击推送消息时,PushReceiverActivity收到消息。系统进程中就有了App的进程,无法再根据进程判断是否真正打开了App,所以在PushInit中申明了shouldInit变量,来标示,用户是否真正打开了App。

5、启动App

private fun launcherApp(context: Context, shouldInit: Boolean) {
    if (shouldInit) {
        val intent =AppUtils.getAppOpenIntentByPackageName(context, "com.xingzhi.android.components")
        context.startActivity(intent)
    } else {
        val intent = Intent(context, SplashActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        context.startActivity(intent)
    }
}

如果在后台运行,需要启动App到前台,再分发消息;如果App没有打开过,启动App,到Main页面后,再分发消息;如果在前台运行,直接分发消息。

6、分发消息

fun messageHandle(context: Context, data: String) {
    try {
        when (JSONObject(data).get("code") as Int) {
            PushType.SETTINGS_TYPE -> {
                toSettings(context)
            }
            PushType.TODAY_DETAILS_TYPE -> {
                val type = object : TypeToken<ResponsePush<TodayDetails>>() {}.type
                val response = ConvertUtils.fromJson<ResponsePush<TodayDetails>>(data, type)
                toTodayDetails(context, response.data.id)
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

解析消息JSON内容,根据Code分别解析数据类型,再跳转界面。

7、页面跳转,只需要 Push Module 依赖业务组件Api层,即可访问业务页面路由,推送模块与业务组件没有任何关系,非常便捷。

dependencies {
    implementation project(':module-biz-today-api')
    implementation project(':module-biz-mine-api')
}
/**
 * 我的组件 - 设置页面
*/
private fun toSettings(context: Context) {
    Launcher.navigation(SettingsLauncher::class.java).startActivity(
        context,
        Intent.FLAG_ACTIVITY_NEW_TASK
    )
}

/**
 * 今日组件 - 今日详情页面
*/
private fun toTodayDetails(context: Context, id: Int) {
    Launcher.navigation(TodayDetailsLauncher::class.java).startActivity(
        context,
        Intent.FLAG_ACTIVITY_NEW_TASK,
        id
    )
}

最后,只需要在app Module中,加入 Push Module 依赖和初始化代码,即可加入推送模块。

dependencies {
    implementation project(':module-biz-push')
}

app build.gradle中加入推送模块依赖,即可编译推送模块代码;删除依赖,则去除整个推送模块的代码;业务层代码不会因为加入依赖或者删除依赖,做任何修改。

// push init
PushInit.with().init(this)

MainActivity中加入PushInit,完成初始化推送模块任务;注释这行代码,则不初始化推送模块,也不接收推送消息。

真正意义上实现,android接收推送消息推送消息推送功能,与项目现有业务逻辑没有任何牵扯。

4.总结小米推送,业界口碑很好,接入简单,覆盖大部分安卓手机。第三方推送使用进程保活和链式唤醒,也是国内ROM优化严打的对象。混合推送方案,适用性比纯系统推送强,极光,阿里云推送是不错的选择。多平台推送方案,和文章中使用一样,高幅度提升消息到达率,需自行整合各厂商推送SDK。推送功能要实现的完美,需要组件化支撑,组件化也是每个App必然发展趋势。

说在最后,Demo包含组件化 + 推送功能实现,项目地址:https://github.com/ixingzhi/Components

Apk下载二维码:

http://d.firim.pro/xm6k?utm_source=fir&utm_medium=qr (二维码自动识别)

总的来说,Android 推送服务的一行代码实现帮助开发者轻松接入推送消息,实现即时通讯和消息推送等功能。在当今竞争激烈的移动应用市场中,及时有效的消息推送可以帮助应用不断增加用户和活跃度,提高用户黏度和留存率,因此 Android 推送服务是每个开发者都应该学习和掌握的技能。

Copyright ©  2012-2024 win10系统家园 版权声明