-
-
Notifications
You must be signed in to change notification settings - Fork 75
RE1-T88 Looking at using FCM to forward APNS messages with Novu #264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -132,7 +132,7 @@ private async Task<bool> UpdateSubscriberFcm(string id, string token, string fcm | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private async Task<bool> UpdateSubscriberApns(string id, string token, string apnsId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private async Task<bool> UpdateSubscriberApns(string id, string token, string apnsId, string fcmId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -144,16 +144,40 @@ private async Task<bool> UpdateSubscriberApns(string id, string token, string ap | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request.Headers.Add("idempotency-key", Guid.NewGuid().ToString()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request.Headers.Add("Authorization", $"ApiKey {ChatConfig.NovuSecretKey}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var payload = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string jsonContent = string.Empty; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!string.IsNullOrWhiteSpace(apnsId)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| providerId = "apns", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| credentials = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var payload = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deviceTokens = new string[] { token } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| integrationIdentifier = apnsId | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string jsonContent = JsonConvert.SerializeObject(payload, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| providerId = "apns", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| credentials = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deviceTokens = new string[] { token } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| integrationIdentifier = apnsId | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jsonContent = JsonConvert.SerializeObject(payload, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else if (!string.IsNullOrWhiteSpace(fcmId)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var payload = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| providerId = "fcm", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| credentials = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deviceTokens = new string[] { token } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| integrationIdentifier = fcmId | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jsonContent = JsonConvert.SerializeObject(payload, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (string.IsNullOrWhiteSpace(jsonContent)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpResponseMessage response = await client.SendAsync(request); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -197,7 +221,7 @@ public async Task<bool> UpdateUserSubscriberFcm(string userId, string code, stri | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task<bool> UpdateUserSubscriberApns(string userId, string code, string token) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await UpdateSubscriberApns($"{code}_User_{userId}", token, ChatConfig.NovuResponderApnsProviderId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await UpdateSubscriberApns($"{code}_User_{userId}", token, ChatConfig.NovuResponderApnsProviderId, null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task<bool> UpdateUnitSubscriberFcm(int unitId, string code, string token) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -207,7 +231,8 @@ public async Task<bool> UpdateUnitSubscriberFcm(int unitId, string code, string | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task<bool> UpdateUnitSubscriberApns(int unitId, string code, string token) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await UpdateSubscriberApns($"{code}_Unit_{unitId}", token, ChatConfig.NovuUnitApnsProviderId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //return await UpdateSubscriberApns($"{code}_Unit_{unitId}", token, ChatConfig.NovuUnitApnsProviderId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await UpdateSubscriberApns($"{code}_Unit_{unitId}", token, null, ChatConfig.NovuUnitFcmProviderId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private async Task<bool> SendNotification(string title, string body, string recipientId, string eventCode, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -259,6 +284,19 @@ private async Task<bool> SendNotification(string title, string body, string reci | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type = type, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apns = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| badge = count, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sound = new | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = sound, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| critical = channelName == "calls" ? 1 : 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| volume = 1.0f | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type = type, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category = channelName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eventCode = eventCode, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
288
to
316
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix the FCM APNS override payload structure The new - apns = new
- {
- badge = count,
- sound = new
- {
- name = sound,
- critical = channelName == "calls" ? 1 : 0,
- volume = 1.0f
- },
- type = type,
- category = channelName,
- eventCode = eventCode,
- },
+ apns = new
+ {
+ payload = new
+ {
+ aps = new
+ {
+ badge = count,
+ sound = new
+ {
+ name = sound,
+ critical = channelName == "calls" ? 1 : 0,
+ volume = 1.0f
+ },
+ category = channelName,
+ @event = eventCode,
+ customType = type
+ }
+ }
+ },(Adjust the exact keys you need under 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apns = new Dictionary<string, object> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iOS unit registrations are now pushed into the wrong provider
UpdateUnitSubscriberApnsno longer stores iOS tokens under the APNS integration and instead pushes them into the FCM provider. APNS device tokens are 64‑char hex strings that must be registered against an APNS integration; feeding them to FCM results inINVALID_ARGUMENT/UNREGISTEREDresponses because FCM expects its own registration tokens (longer base64 strings) and rejects APNS tokens outright. The net effect is that unit notifications on iOS will stop delivering. Please keep iOS registrations on the APNS integration (as before) or ensure the caller passes real FCM registration tokens before switching providers. (docs.novu.co)🤖 Prompt for AI Agents