Azure / azure-notificationhubs-dotnet

.NET SDK for Azure Notification Hubs
MIT License
70 stars 122 forks source link

Template Notifications Prevent Inclusion of `apns-push-type` Header #96

Closed marstr closed 4 years ago

marstr commented 4 years ago

Multiple customers are reporting that they are unable to include headers to indicate the apns-push-type when using templates.

More conversation can be found here: https://github.com/Azure/azure-notificationhubs-dotnet/issues/88#issuecomment-537047099

milettal commented 4 years ago

I am having this same issue. I am using the AppleTemplateRegistrationDescription to register my template with Azure. I set the ApnsHeaders for my silent/background push to the following per this article's recommendations:

template.ApnsHeaders.Add("apns-push-type","background");
template.ApnsHeaders.Add("apns-topic","com.company.AppNameHere");
template.ApnsHeaders.Add("apns-priority","5");

Even with registering with these settings, the background pushes do not get received by the device. If I include no ApnsHeaders, I get the same result. Alerts appear to be working just fine. Any help would be appreciated as this is breaking functionality of our application on iOS 13. Thanks!

marstr commented 4 years ago

Howdy folks, we've found some server side logic that was getting in the way of including these headers. We're working on a fix, and will update this thread when we have deployed the changes.

gertgjoka commented 4 years ago

From azure support, the headers don't need to be on the installation registration but on the actual sending of the push message: var backgroundHeaders = new Dictionary<string, string> { { "apns-push-type", "background" }, { "apns-priority", "5" } }; Dictionary<string, string> templateParams = new Dictionary<string, string>(); // populated templateParams according to our logic

var notification = new TemplateNotification(templateParams); notification.Headers = backgroundHeaders; // the second parameter is the tag name and the template name as we have it registered from the device. var resBack = await hubClient.SendNotificationAsync(notification, tags);

Also the push hub needs to be configured with a key not a certificate to support it. I have yet to test this, but thought I would share it.

Cheers

milettal commented 4 years ago

@gretgjoka Interesting... Mine started working today randomly. I figured the people at Azure had something to do with it. I included the headers on the template registration, not on the sending, and it still worked. Hope it's fixed for everyone. Thanks all!

AntRemo commented 4 years ago

As an update, I just tested and mine are still not working.

gertgjoka commented 4 years ago

I tested as well, not working on my side either with the changes I posted above

milettal commented 4 years ago

@AntRemo @gertgjoka Did you all try adding the APNS headers to the template registration as I did? It is worth a shot if you have not.

template.ApnsHeaders.Add("apns-push-type","background");
template.ApnsHeaders.Add("apns-topic","com.company.AppNameHere");
template.ApnsHeaders.Add("apns-priority","5");
gertgjoka commented 4 years ago

@milettal I am using the installation method with templates, in the API i get an Installation object from the device, and it contains a list of InstallationTemplate which only has a header property. Where would the ApnsHeaders be?

milettal commented 4 years ago

@gertgjoka Ah, I am probably using a different method than you. I am using the "Microsoft.Azure.NotificationHubs" nuget package for .NET (the GitHub we're on). With that, you can specify the Apns headers. My code looks like this:

AppleTemplateRegistrationDescription template = new AppleTemplateRegistrationDescription(deviceTokenStr);
template.Tags = new HashSet<string> { "Tag1","Tag2" };
template.ApnsHeaders=new ApnsHeaderCollection();
template.ApnsHeaders.Add("apns-push-type","background");
template.ApnsHeaders.Add("apns-topic","com.company.app");
template.ApnsHeaders.Add("apns-priority","5");
template.TemplateName = "templateName";
template.BodyTemplate = "Put JSON here with content-available: 1";
await client.CreateRegistrationAsync(template);
AntRemo commented 4 years ago

Hi @milettal

Thanks for your suggestion. You are correct, I at least, am using a different method.

I am using the InstallationTemplate class with the following APNS template

{ "aps": { "content-available": 1, "DataMessage": "$(DataMessage)" } } This is then assigned to the Installation class which has a Templates Dictionary for InstallationTemplates.

After that is setup I call hubClient.CreateOrUpdateInstallation

milettal commented 4 years ago

@AntRemo @gertgjoka Ah, I was unaware of the InstallationTemplate method of registering for templates. It's odd to me that this is the recommended method from Azure but you are not able to specify APNS headers... Would switching to the Registration method break your push infrastructure?

@marstr Is there any way for people using the InstallationTemplate method to set any APNS headers to be passed to Apple?

AntRemo commented 4 years ago

Hi @marstr

Just wanted to check-in and see if there was any time-frame when this issue may be resolved.

Thanks๐Ÿ™

marstr commented 4 years ago

@milettal says: @marstr Is there any way for people using the InstallationTemplate method to set any APNS headers to be passed to Apple?

Not as far as I'm aware, but I'm still fairly new to the team.

@AntRemo says: Just wanted to check-in and see if there was any time-frame when this issue may be resolved.

I'm afraid I don't have much status to share! We're still in the process of rolling out our fix.

AntRemo commented 4 years ago

@marstr I understand and thanks for the update :)

JohnBergman commented 4 years ago

Updating our logic to match @milettal notes above did not change the behavior. We see the device notification, and even using the Azure Tool have been unable to get a successful background push received in the app. This was working prior to the change.

@marstr Any update on deploying a resolution to the issue?

anthonyplews commented 4 years ago

Also waiting for an update on this?

neil445 commented 4 years ago

seriously waiting for an update on this.

We have our two environments, having exactly the same code, but using their respective notifications hubs.

on environment A, the behaviour is not consistent. The devices (iPhone, iPad) don't receive push notifications all the time.

on environment B, it's a total outage. No push notifications are received.

marstr commented 4 years ago

Howdy folks, I've just confirmed that we've finished rolling out our changes to infer the apns-push-type header value globally. Furthermore, I can confirm that we're seeing the expected behavior on our side. Please confirm whether or not you are still impacted.

However, there are still issues at play that may be preventing your notifications from going through! For instance, make sure that you're setting the apns-priority header appropriately as documented by Apple: Sending Notification Requests to APNs

As I hear back from you on whether or not you're still impacted, I will split out any related issues into their own issues as appropriate.

@neil445 if you believe Notification Hubs isn't delivering your notifications, please reach-out to Azure Support to begin an investigation.

@anthonyplews @AntRemo @gertgjoka @JohnBergman @milettal @neil445

gertgjoka commented 4 years ago

@marstr Thanks for the great news. Would you mind telling us where specifically to set these headers?Azure support told us to set those when sending each push message, while here we saw users setting those during the device registration with Azure Hub. Thank you!

gertgjoka commented 4 years ago

I just tried now setting headers in both sending of the push and registration, none of the tests worked for background push...

ostastny commented 4 years ago

I still observe the issue as well. Tried to update my code last week to explicitly include apns-push-type but even with that, the background notifications do not seem to work.

var notification = new AppleNotification(@"
    {
      ""aps"": {
        ""content-available"": 1
      }
    }")
    {
      Priority = 5
    };
    notification.Headers["apns-push-type"] = "background"; 
marstr commented 4 years ago

@milettal says: Is there any way for people using the InstallationTemplate method to set any APNS headers to be passed to Apple?

I've just verified that I'm receiving the expected Notifications on iOS 13 with the following code using Installation Templates and set headers:

private static async Task<string> SendAfterTemplateInstallation(NotificationHubClient nhClient, string deviceToken)
{
    var parity = Guid.NewGuid();
    var installTemplate = new InstallationTemplate()
    {
        Body = $"{{\"aps\":{{\"alert\":\"Notification Hub test notification with secret {parity.ToString()}\"}}}}",
        // Worth noting, I'm seeing success with and without the Headers being set below.
        Headers = new Dictionary<string, string>
        {
             {"apns-push-type", "alert"},
             {"apns-priority", "10"},
        }, 
    };

    var randomTag = Guid.NewGuid();
    var myTags = new[] { randomTag.ToString()};

    var installationId = Guid.NewGuid().ToString();

    var myInstallation = new Installation
    {
        InstallationId = installationId,
        Tags = myTags,
        Platform = NotificationPlatform.Apns,
        PushChannel = deviceToken,
        Templates = new Dictionary<string, InstallationTemplate>
        {
            {"myTemplate", installTemplate}
        }
    };

    await nhClient.CreateOrUpdateInstallationAsync(myInstallation);
    Console.WriteLine($"Installation Created with secret {parity}");

    // When I don't delay, this doesn't work. It does take some time for the system to complete 
    // an installation after it's been requested. I haven't tried pushing those limits
    for (var i = 15; i > 0; i--)
    {
        Console.WriteLine(i);
        await Task.Delay(TimeSpan.FromSeconds(1));
    }

    var result = await nhClient.SendTemplateNotificationAsync(new Dictionary<string, string>(), myTags);
    return result.TrackingId;
}

@gertgjoka, I think the above should work for you as well. @ostastny, I suspect your issue is unrelated. Make sure you have your hands on the correct Device Token, have configured your APNS credentials correctly.

gertgjoka commented 4 years ago

@marstr Your example refers to an alert notification, we are all instead saying that we don't receive background notifications, so with apns-push-type: "background", priority 5 and and content-available: 1. Can you please let us know?

AntRemo commented 4 years ago

@marstr

I too can confirm that setting the InstallationTemplate.Headers as follows does not appear to have any affect.

installationTemplate.Headers = new ApnsHeaderCollection()
                    {
                        {"apns-push-type", "background"},
                        {"apns-priority","5" }
                    };

I also reinstalled the app on my phone, just to be sure there was not an issue with the existing installation.

marstr commented 4 years ago

@AntRemo, in the other thread you were reporting that the you got the following error message when setting the Headers property of an InstallationTemplate:

Template 'hello is invalid: 'Headers' only acceptable for WNS and MPNS...

Are you still encountering that?

AntRemo commented 4 years ago

@marstr

Correct. However, now I do not receive an error message and it appears to upload properly.

Please let me know if you would like me to add some query logic to verify it is being uploaded properly to Notification Hubs.

ostastny commented 4 years ago

@marstr To answer your comment, I don't believe my issue is related Device Tokens. I can successfully receive alert notifications on my test devices, it's only background notifications that don't work. Actually, had some users report they saw some background notifications come through but even for those users the delivery success rate would be very low (one in ten or less...)

marstr commented 4 years ago

Howdy folks, we're still working on repro'ing this problem. To help us get to the bottom of it, would you mind confirming which version of iOS 13 you're using?

@AntRemo @gertgjoka @JohnBergman @neil445 @ostastny

AntRemo commented 4 years ago

13.1.2

anthonyplews commented 4 years ago

13.1.2

JohnBergman commented 4 years ago

13.1.2

gertgjoka commented 4 years ago

Was 13.1.2 now 13.1.3

gertgjoka commented 4 years ago

I was just wondering what is your app development platform guys? We are using cordova and phonegap-push-plugin. Thanks! @AntRemo @neil445 @ostastny @anthonyplews

anthonyplews commented 4 years ago

Okay so managed to get everything working:

Backend API (.net core 2.2):

Mobile App (Ionic 3 Cordova): update phonegap-plugin-push to latest version: 2.3.0.

Mobile App (Ionic 4 Capacitor) We didn't have to do anything it worked after the backend API was updated.

Hope this helps!

gertgjoka commented 4 years ago

@anthonyplews with the latest plugin, the handle is already in the right format. I had updated it already, and I am receiving alert push notifications, but not receiving the silent/background ones. Were you receiving anything prior to this change?

anthonyplews commented 4 years ago

@gertgjoka I wasn't receiving any backend notifications prior to this change, this is a snippet of the code we use for iOS backend notifications:

 var iMsg = JsonConvert.SerializeObject(iosMessage);
 outcome = await _Hub.SendAppleNativeNotificationAsync(iMsg, tags);
gertgjoka commented 4 years ago

@anthonyplews your issue was different from ours then. All of us have issues with background notifications (those with "content-available": 1). Can you receive those? How is your hub configured, with a certificate or a key?

anthonyplews commented 4 years ago

@gertgjoka we configured a certificate.

I see your issue now, as you can see from our code we pass through a json payload and don't specify the apns-priority so it defaults to 10:

image

We haven't tested with "content-available": 1

AntRemo commented 4 years ago

Hi @gertgjoka

I am using Xamarin.

gertgjoka commented 4 years ago

I was able to find a workaround for now, add the badge:0 to the apns payload for silent push and also make sure to remove the headers you may send from .net code during the push send (those were blocking the push for me). I can now finally receive a silent push @AntRemo @neil445 @ostastny @anthonyplews

gertgjoka commented 4 years ago

The side effect of it is that setting the badge to 0 will clear the visible/alert push messages that were there before it. Might not be an acceptable solution for everybody.

AntRemo commented 4 years ago

@gertgjoka Thanks for the update.

That will not be an option for our scenario.

Hope it has provided some relief for you.

AntRemo commented 4 years ago

Hi @marstr

Just wanted to check the status.

It is has been 8 weeks since the original issue was reported and this is beginning to be a real problem for us.

Many thanks ๐Ÿ™

marstr commented 4 years ago

Howdy @AntRemo,

Your frustration is understood! The original problem was that InstallationTemplates targeting APNs with any Headers were blocked by some of our server side validation. We've since deployed a fix for that, and have validated that we're passing the appropriate headers through our system.

Since that fix, we're still hearing from some folks on this thread that background notifications are not being delivered to their applications. We're taking that seriously, and have traced through our system to make sure that we're delivering notifications to Apple in the format we had expected. At the moment, we believe we are delivering notifications as appropriate. However, we're still in the process of doing due diligence before we can make any conclusions about the behavior reported here.

Sorry for the inconvenience!

AntRemo commented 4 years ago

@marstr

I have great news. I managed to get notifications to work without changing any server side code.

To be clear, I did not need to add the following to my server side.

installationTemplate.Headers = new ApnsHeaderCollection()
                    {
                        {"apns-push-type", "background"},
                        {"apns-priority","5" }
                    };

I stumbled across the following doc titled Azure Notification Hubs updates for iOS 13 which states

Developers must now set this header in applications that send notifications through Azure Notification Hubs. Due to a technical limitation, customers must use token-based authentication for APNS credentials with requests that include this attribute. If you are using certificate-based authentication for your APNS credentials, you must switch to using token-based authentication.

Because I have been using Notifications Hubs for years, I had it setup to use certificate-based authentication.

After changing it to token-based authentication following this document Token-based (HTTP/2) Authentication for APNS It worked! Also because no code changed, I was able to update and confirm production is working without doing a deployment.

Question Should I add the code above to set the headers or is that an optional step because I am setting "content-available": 1 in the payload?

Note for others attempting to switch from certificate to token: It took me a few mins to figure out what the token was obtained. I simply had to open the .p8 file I downloaded and extract the characters between the -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- and paste that into the Token field.

gertgjoka commented 4 years ago

@AntRemo I have mentioned on my October 3rd comment that you need a token according to what Azure support told me, but it didn't solve the issue for silent push notifications on my case. Can you please confirm if you are now receiving background/silent push notifications?

AntRemo commented 4 years ago

@gertgjoka I must have missed that. ๐Ÿ™„๐Ÿ˜‚

I can 100% confirm it is working for me now, with no changes to server code.

The only change I made to my app, a month ago, was updating the way that the device token is extracted for iOS 13

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
                ...

                if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
                {
                    // New for iOS 13
                    byte[] result = new byte[deviceToken.Length];
                    Marshal.Copy(deviceToken.Bytes, result, 0, (int)deviceToken.Length);
                    pushChannel = BitConverter.ToString(result).Replace("-", "");
                }
                else
                {
                    // Prior to iOS 13
                    pushChannel = deviceToken.Description.Trim('<').Trim('>').Replace(" ", "");
                }

                ...
}

It may be worth double checking the Notification Hub settings on the Azure portal.

Please let me know if you have any other questions.

Good Luck! Ant

RajGogri commented 4 years ago

Hi Guys! I am a Xamarin developer and following this thread for a while. I managed to receive silent push notifications on my ios app but I see some strange behavior as follows;

  1. Silent push works when the app is in the foreground and connected to wifi.
  2. Silent push works when the app is in the background and connected to wifi.
  3. Silent push works when the app is in the foreground and connected to a cellular network. But here's the real problem for me.
  4. Silent push Doesn't work when the app is in the background and connected to a cellular network.

I am not using any apns headers instead, I am just using payload for sending silent push.

@marstr @gertgjoka @AntRemo @anthonyplews @neil445 @ostastny can you pls confirm are you able to see this behavior on your side as well?

or is there anything that I am missing from my side?

AntRemo commented 4 years ago

Hi @RajGogri

I just tested scenario #4 by simply swiping home and it worked properly.

I then performed the same scenario, but then opened another app and it did not appear to immediately deliver the notification to the app.

Having said that, I'm not sure if this is the normal behavior for iOS. If an app is both in the background and another app is in the foreground, it may throttle the background notification delivery speed.

Hope that helps.

RajGogri commented 4 years ago

Thanks @AntRemo for quick response. I tested in the way u suggested by swiping home, but unfortunately no signs of receipt of silent push for me. Did you performed your test by connecting to cellular network ? I asked that because for me silent apns push works fine when phone is connected to wifi and app is in background.

Also now i have changed my backend code to send required apns headers along with payload in azure notification hub using AppleNotification class. But still no success. ๐Ÿ˜”

On my further testing what I found is; The issue mentioned in point 4 https://github.com/Azure/azure-notificationhubs-dotnet/issues/96#issuecomment-549255469 here doesnโ€™t occur on pre iOS 13 devices.

So basically, Silent Apns Push is not working for me when app is in background and connected to cellular network on iOS 13 devices.

Need assistance!!!