无需FCM实现Xamarin.Android推送通知:解决应用休眠接收难题
解决Xamarin.Forms应用休眠状态下接收推送通知的问题
嘿,我太懂你这种情况了——SignalR在前台实时接收通知顺得不行,可一到App休眠(后台)就彻底哑火,查资料还找不到针对性的方案,确实挺闹心的。其实核心问题出在SignalR的长连接特性和移动系统的后台限制冲突上,咱们一步步来解决:
为什么SignalR在休眠时失效?
移动系统(不管Android还是iOS)为了节省电量和资源,当App进入后台/休眠状态时,会严格限制App的网络连接和进程活动:
- 长连接会被系统主动断开,SignalR没法维持和服务器的通信
- 除非App持有非常特殊的后台权限(比如定位、音频类),否则系统不会允许App在后台持续运行网络任务
所以要实现休眠状态下的推送,必须切换到原生推送服务,结合你的.NET Web API来触发通知。
具体解决方案:原生推送服务 + Web API改造
1. 分平台集成原生推送服务
Android端:集成Firebase Cloud Messaging(FCM)
- 先在Firebase控制台创建项目,为你的Android应用配置包名,下载
google-services.json文件放到Android项目的根目录 - 安装
Xamarin.Firebase.Messaging和Xamarin.Firebase.CoreNuGet包 - 自定义
FirebaseMessagingService子类,重写OnMessageReceived方法——这个方法会在收到推送时触发,哪怕App在后台/休眠:[Service] [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })] public class MyFirebaseMessagingService : FirebaseMessagingService { public override void OnMessageReceived(RemoteMessage message) { base.OnMessageReceived(message); // 解析推送内容,创建并显示通知 SendLocalNotification(message.GetNotification().Title, message.GetNotification().Body); } private void SendLocalNotification(string title, string body) { var channelId = "your_notification_channel_id"; // Android 8.0+ 需要创建通知渠道 if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { var channel = new NotificationChannel(channelId, "My Channel", NotificationImportance.Default); var notificationManager = GetSystemService(NotificationService) as NotificationManager; notificationManager.CreateNotificationChannel(channel); } var intent = new Intent(this, typeof(MainActivity)); intent.AddFlags(ActivityFlags.ClearTop); var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot); var notificationBuilder = new NotificationCompat.Builder(this, channelId) .SetSmallIcon(Resource.Drawable.ic_notification) .SetContentTitle(title) .SetContentText(body) .SetAutoCancel(true) .SetContentIntent(pendingIntent); var notificationManager = NotificationManagerCompat.From(this); notificationManager.Notify(0, notificationBuilder.Build()); } } - 在
AndroidManifest.xml中添加必要权限和服务声明(NuGet包一般会自动配置,但最好检查一下)
iOS端:集成Apple Push Notification service(APNs)
- 登录Apple开发者后台,为你的App启用Push Notifications能力,生成并下载推送证书(p12格式)
- 在iOS项目的
Info.plist中开启Background Modes里的Remote notifications选项 - 在
AppDelegate中实现远程通知注册和处理逻辑:public override bool FinishedLaunching(UIApplication app, NSDictionary options) { // 注册远程通知 UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound, (granted, error) => { if (granted) { InvokeOnMainThread(() => UIApplication.SharedApplication.RegisterForRemoteNotifications()); } }); return base.FinishedLaunching(app, options); } public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) { // 将设备令牌转换为字符串,发送到你的.NET Web API保存 var token = deviceToken.Description.Trim('<', '>').Replace(" ", ""); // 调用API保存token,关联用户 } public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler) { // 处理推送内容,不管App在前台还是后台 var alert = userInfo["aps"] as NSDictionary; var title = alert["alert"] as NSDictionary?["title"] as NSString; var body = alert["alert"] as NSDictionary?["body"] as NSString; // 显示本地通知 ShowLocalNotification(title, body); completionHandler(UIBackgroundFetchResult.NewData); } private void ShowLocalNotification(string title, string body) { var content = new UNMutableNotificationContent(); content.Title = title; content.Body = body; content.Sound = UNNotificationSound.Default; var request = UNNotificationRequest.FromIdentifier(Guid.NewGuid().ToString(), content, UNTimeIntervalNotificationTrigger.CreateTrigger(0.1, false)); UNUserNotificationCenter.Current.AddNotificationRequest(request, null); }注意:iOS模拟器无法接收APNs推送,必须用真机测试
2. 改造.NET Web API,触发原生推送
- 首先在你的API中添加存储设备令牌的逻辑,记录每个用户对应的Android/iOS令牌
- 当需要发送通知时,根据用户的设备类型,调用对应的推送服务API:
- Android(FCM):使用
FirebaseAdminSDK发送推送,示例代码:var message = new Message() { Token = "用户的FCM令牌", Notification = new Notification() { Title = "通知标题", Body = "通知内容" } }; var response = await FirebaseMessaging.DefaultInstance.SendAsync(message); - iOS(APNs):使用Apple的HTTP/2 API发送推送,你可以用第三方库(比如
ApnsClient)或者自己实现HTTP请求
- Android(FCM):使用
3. 可选:SignalR + 原生推送的混合方案
为了兼顾前台实时性和后台推送能力,可以在App中做判断:
- 当App处于前台时,用SignalR接收通知(体验更流畅,无需弹出系统通知)
- 当App进入后台/休眠时,切换到原生推送,由Web API直接调用FCM/APNs发送通知
几个关键注意点
- 设备令牌会定期变化,要在App启动或令牌更新时,同步到你的Web API
- Android 8.0+必须创建通知渠道,否则通知无法显示
- iOS的推送需要确保证书有效,且App的Bundle ID和开发者后台配置一致
- 测试后台推送时,不要直接用调试器挂着App,要把App退到后台甚至锁屏
内容的提问来源于stack exchange,提问作者Kaizer69
相关产品推荐
相关产品推荐

