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

无需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.Core NuGet包
  • 自定义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):使用FirebaseAdmin SDK发送推送,示例代码:
      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请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:50:22