基于自有服务器实现Xamarin跨平台应用动态推送通知方案咨询
嘿,我之前帮不少Xamarin开发者搞定过类似的需求——绕开Firebase用自有服务器实现动态推送,其实核心就是让你的服务器直接对接苹果和谷歌的官方推送API,Xamarin端只负责拿设备令牌、上报给服务器,再处理收到的通知就行。我给你拆解成清晰的步骤,跟着来应该没问题:
第一步:Xamarin端实现令牌获取与上报
首先得让每个设备把自己的推送令牌(iOS叫deviceToken,Android叫FCM Token)上报到你的自有服务器,这样服务器才知道要推给谁。
iOS端配置与令牌上报
- 开启推送权限:在iOS项目的
Info.plist里添加推送相关配置,然后在AppDelegate.cs的FinishedLaunching方法里请求用户授权:
public override bool FinishedLaunching(UIApplication app, NSDictionary options) { // 请求通知权限 UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound, (granted, error) => { if (granted) { // 注册远程通知 UIApplication.SharedApplication.RegisterForRemoteNotifications(); } }); return base.FinishedLaunching(app, options); }
- 获取并上报令牌:重写
RegisteredForRemoteNotifications方法拿到deviceToken,转换成字符串后POST到你的服务器:
public override async void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) { // 格式化deviceToken(去掉尖括号和空格) var token = deviceToken.Description.Replace("<", "").Replace(">", "").Replace(" ", ""); // 上报到自有服务器(这里记得替换成你的API地址) using var httpClient = new HttpClient(); var payload = new { Token = token, Platform = "iOS", UserId = "当前用户ID(可选)" }; var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); var response = await httpClient.PostAsync("https://你的服务器域名/api/register-push-token", content); // 可以加个简单的重试逻辑,避免网络波动导致上报失败 if (!response.IsSuccessStatusCode) { // 重试逻辑,比如延迟几秒后再发一次 } }
Android端配置与令牌上报
注意:Android没有原生的系统推送服务,所以还是得集成FCM的客户端SDK,但咱只用来获取令牌和接收通知,推送逻辑完全由你的自有服务器控制,不用依赖Firebase的控制台或其他服务
- 集成FCM SDK:在Android项目的NuGet里安装
Xamarin.Firebase.Messaging和Xamarin.GooglePlayServices.Base,然后从Firebase控制台下载google-services.json放到Android项目根目录(设置生成操作为GoogleServicesJson)。 - 创建消息服务类:继承
FirebaseMessagingService,重写OnNewToken方法获取FCM令牌并上报,同时重写OnMessageReceived处理收到的通知:
[Service] [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })] public class MyFirebaseMessagingService : FirebaseMessagingService { // 获取新的FCM令牌并上报 public override async void OnNewToken(string token) { base.OnNewToken(token); using var httpClient = new HttpClient(); var payload = new { Token = token, Platform = "Android", UserId = "当前用户ID(可选)" }; var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); await httpClient.PostAsync("https://你的服务器域名/api/register-push-token", content); } // 处理收到的推送通知,显示本地通知 public override void OnMessageReceived(RemoteMessage message) { base.OnMessageReceived(message); var title = message.Notification.Title; var body = message.Notification.Body; // 构建并显示本地通知(Android 13+需要先申请POST_NOTIFICATIONS权限) var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager; // 这里省略具体的通知构建代码,你可以用Xamarin Android的NotificationCompat类来实现 } }
- 申请权限:在AndroidManifest里添加必要权限,Android 13+还需要动态申请
POST_NOTIFICATIONS权限。
第二步:自有服务器实现推送逻辑
服务器这边要做的就是存储所有设备的令牌,然后在需要推送时,分别调用苹果APNs和谷歌FCM的官方API发送通知。
iOS推送:调用APNs HTTP/2 API
- 准备凭证:在Apple开发者后台创建推送证书,生成
p8格式的密钥,记录下你的团队ID、密钥ID和应用Bundle ID。 - 服务器端代码示例(C#):
public async Task SendIosPushNotification(string deviceToken, string title, string body) { var apnsAuthKey = "你的p8密钥内容"; var teamId = "Apple开发者团队ID"; var keyId = "p8密钥的ID"; var bundleId = "iOS应用的Bundle ID"; // 生成APNs需要的JWT令牌 var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(apnsAuthKey)); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var jwt = new JwtSecurityToken( issuer: teamId, expires: DateTime.UtcNow.AddMinutes(20), signingCredentials: credentials, headers: new JwtHeader { { "kid", keyId } } ); var jwtToken = new JwtSecurityTokenHandler().WriteToken(jwt); // 发送请求到APNs using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); httpClient.DefaultRequestHeaders.Add("apns-topic", bundleId); var payload = new { aps = new { alert = new { title = title, body = body }, sound = "default", badge = 1 // 可选:设置应用图标角标 } }; var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); // 测试环境用https://api.development.push.apple.com,生产环境用https://api.push.apple.com var response = await httpClient.PostAsync($"https://api.push.apple.com/3/device/{deviceToken}", content); // 处理响应,比如记录日志或处理失败情况 if (!response.IsSuccessStatusCode) { var errorContent = await response.Content.ReadAsStringAsync(); // 记录错误信息,方便排查 } }
Android推送:调用FCM HTTP v1 API
- 准备凭证:在Firebase控制台创建服务账号,下载JSON格式的密钥文件,记录下你的Firebase项目ID。
- 服务器端代码示例(C#):
public async Task SendAndroidPushNotification(string fcmToken, string title, string body) { var serviceAccountJson = "你的Firebase服务账号JSON内容"; var projectId = "Firebase项目ID"; // 获取FCM API的访问令牌 var credential = GoogleCredential.FromJson(serviceAccountJson) .CreateScoped(new[] { "https://www.googleapis.com/auth/firebase.messaging" }); var accessToken = await credential.UnderlyingCredential.GetAccessTokenForRequestAsync(); // 发送请求到FCM API using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); var payload = new { message = new { token = fcmToken, notification = new { title = title, body = body }, android = new { notification = new { sound = "default" } } } }; var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); var response = await httpClient.PostAsync($"https://fcm.googleapis.com/v1/projects/{projectId}/messages:send", content); // 处理响应 if (!response.IsSuccessStatusCode) { var errorContent = await response.Content.ReadAsStringAsync(); // 记录错误 } }
第三步:测试与排坑要点
- iOS环境区分:测试用真机(模拟器不支持推送),测试环境用APNs的沙箱地址,上线前切换到生产地址。
- Android权限:Android 13+必须动态申请
POST_NOTIFICATIONS权限,否则通知不会显示。 - 令牌有效期:FCM令牌可能会刷新,所以Xamarin端要在
OnNewToken里重新上报;APNs的deviceToken一般不会变,但卸载重装会更新。 - 服务器IP白名单:如果你的服务器有防火墙,要确保允许访问APNs和FCM的API地址。
内容的提问来源于stack exchange,提问作者Roberen
相关产品推荐
相关产品推荐

