在C#后端系统中打通移动端消息通道,Firebase Cloud Messaging(FCM)是目前最省心的方案之一。它提供了稳定的长连接通道,让服务器能够主动把通知推送到安卓或iOS设备,而不需要客户端不断发起请求。借助官方维护的FirebaseAdmin SDK,开发者可以避免手工构造鉴权令牌和HTTP请求的繁琐过程,用几行代码就完成发送逻辑。下面我们先看整体接入所需的准备工作。

获取Firebase服务账号与SDK接入
要在C#项目里使用Firebase推送,第一步是在Firebase控制台创建项目,并在项目设置中生成服务账号密钥文件。这个JSON文件包含了项目编号、客户端邮箱以及私钥,SDK会用它向Google服务器申请短期访问令牌。很多初学者误以为需要把Firebase配置文件放进安卓客户端才算完成接入,实际上后端推送完全依赖服务账号,和前端的google-services.json是两套独立凭证。
拿到密钥后,通过NuGet安装FirebaseAdmin包。在ASP.NET Core的Program.cs中,使用FirebaseApp.Create方法加载密钥并初始化全局实例。注意密钥文件路径不要硬编码在公开仓库里,推荐用环境变量或密钥管理服务。初始化只需要执行一次,后续所有发送操作都复用同一个应用上下文。
下面是一段典型的初始化代码,展示如何从文件流读取密钥并注册到依赖容器之外的作用域:
using FirebaseAdmin;
using Google.Apis.Auth.OAuth2;
using System.IO;
string path = Path.Combine(Directory.GetCurrentDirectory(), "firebase-key.json");
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
FirebaseApp app = FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromStream(stream)
});
封装C#发送通知的核心方法
FirebaseAdmin SDK提供了FirebaseMessaging类来发送消息。它可以针对单个设备令牌、设备组或者主题进行推送。在真实业务中,我们通常把设备令牌保存在用户表里,当用户触发某种事件时,从数据库取出令牌调用发送接口。为了不让发送逻辑散落在各处,建议抽出一个NotificationService服务类,统一处理异常和重试。
消息体由Message对象描述,可以设置通知标题、正文,也能附带自定义数据字段。如果只填通知字段,系统会自动在通知栏展示;如果附带Data字典,客户端应用即使在后台也能收到键值对用于处理业务逻辑。下面的示例演示向指定令牌发送一条带数据的通知:
using FirebaseAdmin.Messaging;
using System.Threading.Tasks;
public class NotificationService
{
public async Task<string> SendToDeviceAsync(string token, string title, string body)
{
var message = new Message()
{
Token = token,
Notification = new Notification()
{
Title = title,
Body = body
},
Data = new Dictionary<string, string>
{
{ "click_action", "OPEN_DETAIL" },
{ "order_id", "10086" }
}
};
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
return response;
}
}
这段代码返回的response是Google服务端生成的消息ID,可用于排查丢失问题。需要留意的是,FCM对单次请求体大小有限制,自定义数据的总长度不能过大。如果推送失败抛出FirebaseMessagingException,应根据错误码判断是令牌失效还是配额超限,再决定要不要清理本地令牌或降低发送频率。
客户端接收与后台处理逻辑
服务端推送只是链路的一半,另一半是安卓客户端如何接收并展现。在安卓原生开发中,通过添加Firebase Messaging依赖并继承FirebaseMessagingService,可以重写OnMessageReceived方法拿到到达的远程消息。当应用处于前台时,系统不会自动弹通知,必须自己在代码里调用通知管理器构建展示。
如果消息只包含Data字段且应用处于后台,FCM会自行在通知栏生成一条系统级通知,点击后才会拉起应用并传递数据。这种差异容易导致新手以为推送失败,其实是展示策略不同。为了让C#后端推送的内容在各类状态下都表现一致,推荐后端同时填写Notification和Data,并在客户端前台逻辑里也手动弹窗,避免遗漏。
以下Kotlin片段展示了前台接收时如何把C#发来的标题与内容显示出来:
class MyFirebaseService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
remoteMessage.notification?.let {
showNotification(it.title ?: "提示", it.body ?: "")
}
val orderId = remoteMessage.data["order_id"]
// 根据order_id执行本地刷新
}
private fun showNotification(title: String, body: String) {
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel("push", "推送", NotificationManager.IMPORTANCE_HIGH)
manager.createNotificationChannel(channel)
val notification = Notification.Builder(this, "push")
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.build()
manager.notify(1, notification)
}
}
从架构角度看,C#配合Firebase做推送比自建长连接服务成本低得多。服务器只需关心业务触发点,通道质量、离线存储和的多平台适配都交给Google。对于中小团队,这种实战组合能在一两天内完成接入并上线,且后期维护负担很小。