Xamarin.iOS调用FCM推送API返回InvalidRegistration错误求助
在Xamarin iOS项目中通过RegisteredForRemoteNotifications方法获取设备DeviceToken,存入Preferences后再通过基于Entity Framework的API接口同步到服务端数据库,后续调用FCM接口发送推送时返回InvalidRegistration错误。
客户端获取DeviceToken代码(AppDelegate.cs)
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) { byte[] bytes = deviceToken.ToArray<byte>(); string[] hexArray = bytes.Select(b => b.ToString("x2")).ToArray(); DeviceToken = string.Join(string.Empty, hexArray); Preferences.Set("TokenDevice", DeviceToken); }
当前获取到并存入数据库的DeviceToken值为:
6b60feecad920471ccde5a3447ab22d3f820abae821daeac726cc7e6d0863465
服务端推送接口代码
[HttpPost] public void SendNotification(string devicetoken, string title, string body, string link, string icon) { try { dynamic data = new { to = devicetoken, priority = "high", notification = new { title = title, body = body, link = link, icon = icon } }; var json = JsonConvert.SerializeObject(data); Byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(json); string SERVER_API_KEY = "AAAAqOId6Is:APA91bHJ5pQgLlanU8gwQwnpxdBlKS00i1xxxxxxxxxxxxxxxxxxxxxxxxxxx"; string SENDER_ID = "72xxxxxxxx"; WebRequest tRequest; tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send"); tRequest.Method = "post"; tRequest.ContentType = "application/json"; tRequest.Headers.Add(string.Format("Authorization: key={0}", SERVER_API_KEY)); tRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID)); tRequest.ContentLength = byteArray.Length; Stream dataStream = tRequest.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); WebResponse tResponse = tRequest.GetResponse(); dataStream = tResponse.GetResponseStream(); StreamReader tReader = new StreamReader(dataStream); String sResponseFromServer = tReader.ReadToEnd(); tReader.Close(); dataStream.Close(); tResponse.Close(); } catch (Exception) { throw; } }
代码中SERVER_API_KEY和SENDER_ID均从Firebase控制台项目设置-Cloud Messaging板块获取。
错误现象
调用推送接口测试时,FCM返回如下错误:
{"multicast_id":7343900550378569449,"success":0,"failure":1,"canonical_ids":0, "results":[{"error":"InvalidRegistration"}]}
核心诉求:希望沿用现有支持自定义跳转link、icon参数的代码逻辑,确认现有推送代码是否过时,以及InvalidRegistration错误的产生原因和修复方案。
现有推送代码是否过时
当前使用的FCM旧版HTTP发送接口(https://fcm.googleapis.com/fcm/send)仍可正常调用,未完全停止服务,只是谷歌官方已推荐迁移到HTTP v1版本。旧版接口本身不会触发InvalidRegistration错误,现有自定义通知参数的逻辑可以完全保留,不需要推翻重写。
InvalidRegistration错误根本原因
存入数据库的64位十六进制字符串是苹果APNs服务的原生DeviceToken,不是FCM服务认可的注册Token,两类Token完全不通用,FCM无法识别APNs原生Token,直接返回注册无效错误。
现有代码只处理了原生APNs注册回调,没有接入Firebase Messaging SDK的Token获取逻辑:FCM需要先拿到APNs Token,再向谷歌服务端注册换取专属的FCM注册Token,这类Token格式为长字符串、中间带冒号分隔符,和当前获取的64位十六进制Token有明显区别,只有这个FCM Token才能作为推送接口的to参数使用。
修复方案
- 完成Xamarin.iOS端Firebase Messaging基础配置
- 将
GoogleService-Info.plist文件加入iOS项目,设置正确的生成操作 - 在
AppDelegate的FinishedLaunching方法中初始化Firebase App,配置Messaging代理,申请推送权限
- 将
- 修正Token获取逻辑,不要直接存储APNs Token用于FCM推送
参考代码如下:// FinishedLaunching方法中加入初始化逻辑 Firebase.Core.App.Configure(); Messaging.SharedInstance.Delegate = this; // 实现Firebase Messaging的Token回调,这里拿到的才是可用于FCM推送的有效Token [Export("messaging:didReceiveRegistrationToken:")] public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken) { // 存储fcmToken到本地,同步到服务端数据库 Preferences.Set("TokenDevice", fcmToken); } // 原有RegisteredForRemoteNotifications方法保留,作用仅为将APNs Token传递给FCM SDK public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) { Messaging.SharedInstance.ApnsToken = deviceToken; } - 服务端代码无需大改,将数据库中之前存储的所有APNs原生Token替换为新获取的FCM Token,再调用发送接口即可解决
InvalidRegistration错误,原有自定义title、body、link、icon的逻辑完全不受影响。 - 额外注意事项:开发环境测试时需使用沙盒环境对应的FCM Token,同时要在Firebase控制台正确上传对应环境的APNs证书,发送请求时可加上
"mutable_content": true参数,避免因环境不匹配导致推送失败。
内容的提问来源于stack exchange,提问作者Chim Di Tru

