Cannot register device in Azure NotificationHub on iOS, no callbacks

浪尽此生 提交于 2021-02-11 14:21:52

问题


I'm trying to set up push notifications via Azure NotificationHub (using these guides). Android went fine, but iOS...

No matter what I do, I do not receive any callbacks from RegisterNative / RegisterTemplate methods of SBNotificationHub, and no registrations appear in the hub.

My code (pretty straightforward):

public static void SubscribeToAzure(NSData deviceToken, string[] subscriptionTags = null, bool bUnsubscribe = false)
{
    try
    {
        var Hub = new SBNotificationHub(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);

        Logger.WriteLine($"Unsubscribing from AzureHub [{deviceToken}]....");

        Hub.UnregisterAll(deviceToken, (error) =>
        {
            if (error != null)
            {
                Logger.WriteLine($"SubscribeToAzure: Unable to call unregister, {error}");
                return;
            }
            RuntimeInfo.AzureSubscribed = false;

            if (bUnsubscribe)
                return;

            Logger.WriteLine($"Register native in AzureHub [{deviceToken}]....");

            var tags = subscriptionTags != null ? new NSSet(subscriptionTags.ToArray()) : new NSSet("default");
            Hub.RegisterNative(deviceToken, tags, errorCallback =>
            {
                // !!! never got here !!!

                if (errorCallback != null)
                    Logger.WriteLine($"RegisterNative error: {errorCallback}");
                else
                    Logger.WriteLine($"RegisterNative OK");
            });

            Logger.WriteLine("Register template in AzureHub....");

            var templateExpiration = DateTime.Now.AddDays(120).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));

            Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, errorCallback =>
            {
                // !!! never got here !!!

                if (errorCallback != null)
                {
                    Logger.WriteLine($"RegisterTemplateAsync error: {errorCallback}");
                }
                else
                {
                    Logger.WriteLine("Subscribed to Azure successfully.");
                    RuntimeInfo.AzureSubscribed = true;
                }
            });

            Logger.WriteLine("Registrations passed....");
        });
    }
    catch(Exception e)
    {
        Logger.WriteLine($"SubscribeToAzure: Whole deal failed, {e.Message}");
    }
}

Always get this log messages (no callbacks called):

[22.10.2020 18:13:43]: Unsubscribing from AzureHub [{length = 32, bytes = 0x342c9bc5 d75ffb0b d68078d0 47e94320 ... e08989c9 66a13a37}]....

[22.10.2020 18:13:44]: Register native in AzureHub [{length = 32, bytes = 0x342c9bc5 d75ffb0b d68078d0 47e94320 ... e08989c9 66a13a37 }]....

[22.10.2020 18:13:44]: Register template in AzureHub....

[22.10.2020 18:13:44]: Registrations passed....

And no iOS registrations in the hub. And no errors anywhere.

I tried both certificate and token authentication modes, with no luck.

I have double-, triple- and quadruple-checked all certificates, statuses, keys, ids, etc.

Using iOS SDK 14.0, iPhone X iOS 14.0.1, Xamarin Forms 4.8.0.1560, Xamarin.Azure.NotificationHubs.iOS 3.1.0.

=======

I was advised to move from SBNotificationHub to MSNotificationHub.

Got exactly the same result: no response if something went wrong or not. And no registrations in the hub.

public static void SubscribeToAzure(NSData deviceToken, string[] subscriptionTags = null, bool bUnsubscribe = false)
{
    RuntimeInfo.AzureSubscribed = false;

    if (bUnsubscribe)
    {
        // ??
    }
    else
    {
        try
        {

            Logger.WriteLine("Subscribing to Azure Hub....");

            MSNotificationHub.Start(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);

            MSNotificationHub.SetDelegate(new NotificationDelegate());

            MSNotificationHub.SetLifecycleDelegate(new InstallationLifecycleDelegate());

            MSNotificationHub.ClearTags();

            if (subscriptionTags != null)
                foreach (string tag in subscriptionTags)
                {
                    MSNotificationHub.AddTag(tag);
                }

            var template = new MSInstallationTemplate();
            template.Body = AppConstants.APNTemplateBody;

            if (subscriptionTags != null)
                foreach (string tag in subscriptionTags)
                {
                    template.AddTag(tag);
                }

            MSNotificationHub.SetTemplate(template, key: "defaultTemplate");


            Logger.WriteLine($"SubscribeToAzure: done subscribing routine");
        }
        catch (Exception e)
        {
            Logger.WriteLine($"SubscribeToAzure: Whole deal failed, {e.Message}");
        }
    }
}
public class InstallationLifecycleDelegate : MSInstallationLifecycleDelegate
{
    public override void DidFailToSaveInstallation(MSNotificationHub notificationHub, MSInstallation installation, NSError error)
    {
        Logger.WriteLine($"Subscribing to Azure failed with exception: {error.LocalizedDescription}");
    }

    public override void DidSaveInstallation(MSNotificationHub notificationHub, MSInstallation installation)
    {
        RuntimeInfo.AzureSubscribed = true;
        Logger.WriteLine($"Subscribed to Azure successfully with Installation ID: {installation.InstallationId}");
    }
}
public class NotificationDelegate : MSNotificationHubDelegate
{
    public override void DidReceivePushNotification(MSNotificationHub notificationHub, MSNotificationHubMessage message)
    {
        NSDictionary userInfo = message.UserInfo;
        if (UIApplication.SharedApplication.ApplicationState == UIApplicationState.Background)
        {
            Logger.WriteLine($"Message received in the background with title {message.Title} and body {message.Body}");
            ProcessNotification(userInfo, true);
        }
        else
        {
            Logger.WriteLine($"Message received in the foreground with title {message.Title} and body {message.Body}");
            ProcessNotification(userInfo, true);
        }
    }
}

Log only shows that all parts of code were passed:

[23.10.2020 18:34:33]: Subscribing to Azure Hub....

[23.10.2020 18:34:33]: SubscribeToAzure: done subscribing routine

Also tried automatic swizzle disabling to log every step, same result.


UPDATE

After few days of struggling, I found out that if execution slips from main thread, iOS blocks requests and Xamarin.Azure.NotificationHubs.iOS wouldn't say anything about it. Running it forcibly in main thread gave it a nudge. Sadly, it still doesn't work.

The first approach with SBNotificationHub failed to register template. Code above do RegisterNative and I get native entry in notification hub. But RegisterTemplate return 'Bad Request'.

[28.10.2020 15:26:10]: RegisterTemplateAsync error: URLRequest failed for <NSMutableURLRequest: 0x282bac6e0> { URL: https://webtutormobile.servicebus.windows.net//Registrations/8635975298502840400-8846379580641729326-3?api-version=2013-04 } with status code: bad request

Second approach with MSNotificatoinHub fail to obtain NSDictionary from MSNotificationHubMessage.UserInfo getter, and breaks on this line:

public override void DidReceivePushNotification(MSNotificationHub notificationHub, MSNotificationHubMessage message)
{
        var userInfo = message.UserInfo; // MSNotificationHubMessage.UserInfo has type NSDictionary<NSString, NSString>


with exception:

[28.10.2020 16:22:58]: Received azure notification error: Unable to cast object of type 'Foundation.NSDictionary' to type 'Foundation.NSDictionary`2[[Foundation.NSString, Xamarin.iOS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065],[Foundation.NSString, Xamarin.iOS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]]'


回答1:


Finally it has been brought to conclusion. If anyone's interested:

  1. Hub Registrations must be called in main thread. Otherwise Xamarin.Azure.NotificationHubs.iOS wouldn't even give a hint that something went wrong.

  2. New approach with MSNotificationHub has a bug in getting UserInfo with casting it to NSDictionary<NSString, NSString> when actual type is NSDictionary. It is issued in GitHub for a while now, but still without any response from team, so if you pass any data besides message through push notification, sorry, it's no go.

  3. Old approach using SBNotificationHub has strict Template format. First of all, you shoud use RegisterTemplate method that outs error, not one that do callback, as the former one is the only that gives error description for some reason. Secondly, you can't define template using {$(field)} constructon, you need to specify insertion format for properties, like: "alert":"$(messageParam)","badge":"#(badge)","content-available":"#(contentAvailable)" etc. Also you need to modify dispatcher so it would always send unquoted parameters.

IOS implementation is extremely raw, half-done and forgotten. I understand that interacting with Apple is utter hell and pain in the rear, but still...

Hope it saves someone lots and lots of time.



来源:https://stackoverflow.com/questions/64513220/cannot-register-device-in-azure-notificationhub-on-ios-no-callbacks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!