You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何向MainActivity发送FCM消息并实现底部导航徽章显示(解决重复打开)

解决FCM消息传递与底部导航栏徽章显示的问题

嘿,我来帮你搞定这两个需求,一步步拆解:

一、如何向MainActivity发送FCM消息

FCM消息主要分两类,对应不同的传递方式:

  • 通知消息:当App在后台时,系统会自动展示通知,点击后默认打开App的启动Activity。如果想指定打开MainActivity,需要在FCM的payload里配置click_action为MainActivity的全类名(比如com.yourpackage.MainActivity),同时在Manifest里给MainActivity添加对应的intent-filter:
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="com.yourpackage.MAIN_ACTIVITY" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
    
    对应的FCM payload(JSON格式)示例:
    {
      "notification": {
        "title": "新消息提醒",
        "body": "你有一条未读消息",
        "click_action": "com.yourpackage.MAIN_ACTIVITY"
      },
      "to": "目标设备令牌"
    }
    
  • 数据消息:不管App在前台还是后台,都会直接触发onMessageReceived方法,这也是你当前使用的方式,接下来重点解决这种方式下的Activity实例重复问题。

二、解决MainActivity重复实例+底部导航栏徽章显示

你当前代码用FLAG_ACTIVITY_NEW_TASK会创建新的Activity实例,我们可以通过调整Intent的Flag复用已存在的MainActivity,再通过onNewIntent接收数据并更新徽章:

1. 修改FCM Service中的代码

把Intent的Flag改成FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP,这样如果MainActivity已经在栈中,就会复用它并调用onNewIntent方法,而不是创建新实例:

override fun onMessageReceived(p0: RemoteMessage) { 
    super.onMessageReceived(p0) 
    val intent = Intent(this, MainActivity::class.java) 
    // 替换原有Flag,复用已存在的MainActivity实例
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
    // 传递消息数据,兼容通知消息和数据消息的内容
    intent.putExtra("badge", p0.notification?.body ?: p0.data["badge"])
    
    // 如果App在后台,建议配合PendingIntent构建系统通知,点击后唤醒Activity
    val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
    // 这里可以选择性构建系统通知(比如App后台时提示用户)
    // ...(通知构建代码)
    
    startActivity(intent)
}

2. 在MainActivity中接收数据并显示徽章

重写onNewIntent方法获取传递的badge数据,然后给底部导航栏的对应item添加徽章:

class MainActivity : AppCompatActivity() {
    private lateinit var bottomNav: BottomNavigationView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bottomNav = findViewById(R.id.bottom_navigation)
        
        // 检查启动时是否有传递的badge数据
        intent?.getStringExtra("badge")?.let { updateBadge() }
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent) // 更新当前Intent,确保后续获取数据正确
        intent?.getStringExtra("badge")?.let { updateBadge() }
    }

    private fun updateBadge() {
        // 获取底部导航栏的目标item(比如首页对应的index为0)
        val targetItemId = bottomNav.menu.getItem(0).itemId
        // 创建或获取徽章实例
        val badge = bottomNav.getOrCreateBadge(targetItemId)
        badge.isVisible = true
        // 这里用计数方式更新徽章,也可以设置自定义文本
        badge.number = badge.number + 1
    }
}

补充小提示

  • 如果App处于后台状态,单纯调用startActivity可能无法直接唤醒Activity,配合系统通知+PendingIntent的方式体验会更好。
  • 要是App在前台时想实时更新徽章,用LiveData/ViewModel或者本地广播传递数据会比直接启动Activity更优雅哦。

内容的提问来源于stack exchange,提问作者Mohammad Derakhshan

火山引擎 最新活动