You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase Cloud Messaging(FCM)推送通知本地化实现技术问询

实现FCM推送通知本地化(待办状态变更场景)

刚好做过类似的FCM本地化推送需求,针对你提到的待办事项状态变更场景,我来分享一套成熟的实现方案——核心是把本地化逻辑交给客户端处理,服务端只传递关键参数,这样既灵活又能完美适配用户的系统语言,还不用服务端维护一堆多语言文案。

核心思路

不要让服务端生成多语言的通知文本,而是让服务端发送「通知类型标识+动态参数」,客户端收到后,根据自身的本地化字符串资源,把参数填充到对应的模板里,最后展示给用户。这样不管用户设备是什么语言,都能自动匹配对应的翻译。

具体实现步骤

1. 客户端准备本地化字符串资源

以Android为例,我们需要在不同语言的资源文件夹里定义带占位符的模板字符串,以及状态枚举的本地化文本:

  • 英文模板(res/values/strings.xml):
<string name="todo_status_changed">Status of %1$s changed to %2$s.</string>
<string name="status_open">OPEN</string>
<string name="status_in_progress">IN PROGRESS</string>
<string name="status_done">DONE</string>
<string name="unknown_todo">Unknown Todo</string>
<string name="todo_update_title">Todo Update</string>
  • 中文模板(res/values-zh/strings.xml):
<string name="todo_status_changed">%1$s的状态已变更为%2$s。</string>
<string name="status_open">未开始</string>
<string name="status_in_progress">进行中</string>
<string name="status_done">已完成</string>
<string name="unknown_todo">未知待办</string>
<string name="todo_update_title">待办更新</string>

iOS端的话,对应在Localizable.strings里做同样的配置即可,语法类似:

"todo_status_changed" = "%1$@的状态已变更为%2$@。";
"status_open" = "未开始";
"unknown_todo" = "未知待办";

2. 服务端构造FCM消息

服务端不需要处理任何本地化,只需要发送data类型的FCM消息(注意不能用notification类型,因为会被系统直接展示,客户端没机会处理),包含以下关键参数:

  • notification_type:标识通知类型(比如todo_status_change),方便客户端区分不同的通知场景
  • todo_title:待办事项的标题(比如「吸尘」)
  • todo_status:待办的状态枚举值(比如OPEN/IN_PROGRESS/DONE)

示例JSON payload:

{
  "to": "用户的设备FCM令牌",
  "data": {
    "notification_type": "todo_status_change",
    "todo_title": "吸尘",
    "todo_status": "DONE"
  }
}

3. 客户端接收并处理FCM消息

以Android的FirebaseMessagingService为例,我们需要重写onMessageReceived方法,解析参数、填充本地化模板,最后构建通知:

class TodoFirebaseMessagingService : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        // 解析data中的参数
        remoteMessage.data.takeIf { it.isNotEmpty() }?.let { data ->
            when (data["notification_type"]) {
                "todo_status_change" -> handleTodoStatusChange(data)
                // 可以扩展其他通知类型
            }
        }
    }

    private fun handleTodoStatusChange(data: Map<String, String>) {
        // 获取参数,做空值处理避免崩溃
        val todoTitle = data["todo_title"] ?: getString(R.string.unknown_todo)
        val rawStatus = data["todo_status"] ?: ""
        
        // 将原始状态值映射为本地化文本
        val localizedStatus = when (rawStatus) {
            "OPEN" -> getString(R.string.status_open)
            "IN_PROGRESS" -> getString(R.string.status_in_progress)
            "DONE" -> getString(R.string.status_done)
            else -> rawStatus // 兜底处理未知状态
        }

        // 填充本地化模板
        val notificationContent = getString(R.string.todo_status_changed, todoTitle, localizedStatus)
        
        // 构建并显示通知
        showNotification(getString(R.string.todo_update_title), notificationContent)
    }

    private fun showNotification(title: String, content: String) {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val channelId = "todo_notification_channel"

        // Android O及以上需要创建通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channelId,
                "待办事项通知",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }

        val notification = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_todo_notification)
            .setContentTitle(title)
            .setContentText(content)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(true)
            .build()

        // 用当前时间作为通知ID,避免重复通知被覆盖
        notificationManager.notify(System.currentTimeMillis().toInt(), notification)
    }
}

关键注意事项

  • 必须用data payload:如果用notification payload,消息会直接被系统通知栏展示,客户端无法拦截处理本地化逻辑;只有data payload会传递到FirebaseMessagingService,让我们有机会自定义内容。
  • 参数校验:客户端一定要处理参数为空的情况,比如给todo_title设置默认值(比如「未知待办」),避免空指针崩溃。
  • 状态枚举一致性:服务端发送的todo_status值必须和客户端的映射逻辑完全一致,比如服务端不能发completed而客户端只处理DONE,否则会显示原始状态值。
  • iOS适配:iOS端的处理逻辑和Android一致,接收FCM的data消息后,用NSLocalizedString填充模板字符串即可,注意占位符的语法差异(Android用%1$s,iOS用%1$@)。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:38:27