求助:如何实现Android全设备Firebase推送通知应用图标角标(默认开启+低版本兼容)
解决方案:Firebase推送实现全版本Android应用图标角标
我来帮你搞定这两个角标适配的问题,结合Firebase推送的场景,给你整理了经过真机验证的可行方案:
一、Android 8+:引导默认启用角标(减少手动操作)
首先得明确:Android 8+系统没有原生API能强制默认开启应用图标角标,因为这属于用户的通知权限范畴。但我们可以通过以下步骤,让角标功能自动生效,避免用户手动找设置:
创建Notification Channel时强制开启角标支持
在初始化Firebase推送的通知渠道时,一定要加上setShowBadge(true)——这是系统允许该渠道通知显示角标的基础配置,没加的话就算用户开了权限也白搭:val channelId = "your_push_channel" val channelName = "应用推送通知" val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT).apply { description = "接收应用的实时推送消息" setShowBadge(true) // 核心配置:开启渠道的角标支持 } val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channel)自动检测并引导用户开启角标权限
不同厂商的角标权限入口不一样,我们可以在App首次启动或收到第一条推送前,检测权限状态,未开启就直接跳转到对应厂商的设置页面:fun checkAndGuideBadgePermission(context: Context) { // 先检查基础通知权限(角标依赖通知权限) if (!NotificationManagerCompat.from(context).areNotificationsEnabled()) { val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) } context.startActivity(intent) return } // 针对主流厂商做引导适配 val manufacturer = Build.MANUFACTURER.lowercase() when { manufacturer.contains("xiaomi") -> { val intent = Intent("android.settings.APP_NOTIFICATION_SETTINGS").apply { putExtra("app_package", context.packageName) putExtra("app_uid", context.applicationInfo.uid) } context.startActivity(intent) } manufacturer.contains("huawei") -> { val intent = Intent("com.huawei.android.launcher.action.CHANGE_BADGE").apply { putExtra("package", context.packageName) putExtra("class", context.packageManager.getLaunchIntentForPackage(context.packageName)?.component?.className) } // 找不到专属入口就跳应用详情页 if (context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) == null) { val fallbackIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.fromParts("package", context.packageName, null) } context.startActivity(fallbackIntent) } else { context.startActivity(intent) } } // 三星、OPPO、vivo等厂商可参照上述逻辑添加适配 } }
二、Android 8以下版本:适配各大厂商自定义角标API
Android 8及以下原生不支持角标,必须适配主流厂商的自定义API,下面是封装好的通用工具类,直接用就行:
角标工具类:BadgeUtils
object BadgeUtils { fun updateBadgeCount(context: Context, count: Int) { val manufacturer = Build.MANUFACTURER.lowercase() try { when { manufacturer.contains("xiaomi") -> setXiaomiBadge(context, count) manufacturer.contains("huawei") -> setHuaweiBadge(context, count) manufacturer.contains("samsung") -> setSamsungBadge(context, count) manufacturer.contains("oppo") -> setOppoBadge(context, count) manufacturer.contains("vivo") -> setVivoBadge(context, count) } } catch (e: Exception) { // 避免厂商API变更导致崩溃 e.printStackTrace() } } // 小米角标设置 private fun setXiaomiBadge(context: Context, count: Int) { val intent = Intent("android.intent.action.APPLICATION_MESSAGE_UPDATE").apply { val launcherComponent = context.packageManager.getLaunchIntentForPackage(context.packageName)?.component putExtra("android.intent.extra.update_application_component_name", launcherComponent?.flattenToString()) putExtra("android.intent.extra.update_application_message_count", count) } context.sendBroadcast(intent) } // 华为角标设置 private fun setHuaweiBadge(context: Context, count: Int) { val bundle = Bundle().apply { putString("package", context.packageName) putString("class", context.packageManager.getLaunchIntentForPackage(context.packageName)?.component?.className) putInt("badgenumber", count) } context.contentResolver.call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, bundle) } // 三星角标设置 private fun setSamsungBadge(context: Context, count: Int) { val intent = Intent("android.intent.action.BADGE_COUNT_UPDATE").apply { putExtra("badge_count", count) putExtra("badge_count_package_name", context.packageName) putExtra("badge_count_class_name", context.packageManager.getLaunchIntentForPackage(context.packageName)?.component?.className) } context.sendBroadcast(intent) } // OPPO角标设置 private fun setOppoBadge(context: Context, count: Int) { try { val intent = Intent("com.oppo.unsettledevent").apply { putExtra("pakeageName", context.packageName) putExtra("number", count) } if (context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { context.sendBroadcast(intent) } else { val contentValues = ContentValues().apply { put("package", context.packageName) put("class", context.packageManager.getLaunchIntentForPackage(context.packageName)?.component?.className) put("badgenumber", count) } context.contentResolver.insert(Uri.parse("content://com.android.badge/badge"), contentValues) } } catch (e: Exception) { e.printStackTrace() } } // VIVO角标设置 private fun setVivoBadge(context: Context, count: Int) { val intent = Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM").apply { putExtra("packageName", context.packageName) putExtra("className", context.packageManager.getLaunchIntentForPackage(context.packageName)?.component?.className) putExtra("notificationNum", count) } context.sendBroadcast(intent) } }
结合Firebase推送使用
在你的FirebaseMessagingService中,收到推送后调用工具类更新角标(注意自己维护未读计数,比如用SharedPreferences存储):
class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 处理推送内容、创建通知... // 更新角标计数(示例:从SP读取当前未读数+1) val sp = getSharedPreferences("app_config", MODE_PRIVATE) val currentUnread = sp.getInt("unread_count", 0) val newUnread = currentUnread + 1 sp.edit().putInt("unread_count", newUnread).apply() BadgeUtils.updateBadgeCount(this, newUnread) } }
额外注意事项
- 部分厂商需要声明权限,比如华为要在
AndroidManifest.xml中添加:<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE"/> - 角标计数需要自己维护,用户查看消息时记得清零,调用
BadgeUtils.updateBadgeCount(context, 0)即可。 - 一定要在真机上测试,模拟器大多不支持厂商自定义角标。
内容的提问来源于stack exchange,提问作者Gowrisankari Ravindran
相关产品推荐
相关产品推荐

