无法在 iOS 上在 Azure NotificationHub 中注册设备,无回调

Cannot register device in Azure NotificationHub on iOS, no callbacks

我正在尝试通过 Azure NotificationHub 设置推送通知(使用 these guides)。 Android 进行得很好,但是 iOS...

无论我做什么,我都没有收到来自 RegisterNative / RegisterTemplate SBNotificationHub[ 方法的任何回调=71=],并且没有注册出现在集线器中。

我的代码(非常简单):

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}");
    }
}

始终获取此日志消息(未调用回调):

[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....

并且在中心没有 iOS 注册。任何地方都没有错误。

我尝试了证书和令牌身份验证模式,但没有成功。

我对所有证书、状态、密钥、ID 等进行了双重、三重和四重检查

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

=======

我被建议从 SBNotificationHub 移动到 MSNotificationHub.

得到完全相同的结果:无论是否出错都没有响应。并且中心没有注册。

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);
        }
    }
}

日志仅显示所有代码部分均已通过:

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

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

还尝试自动 swizzle disabling 记录每一步,结果相同。


更新

经过几天的努力,我发现如果执行从主线程滑落,iOS 会阻止请求并且 Xamarin.Azure.NotificationHubs.iOS 不会对此发表任何意见。 运行 它在主线程中强行推动了它。 可悲的是,它仍然不起作用。

使用 SBNotificationHub 的第一种方法无法注册模板。上面的代码执行 RegisterNative 并且我在通知中心获得本机条目。但是 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

使用 MSNotificatoinHub 的第二种方法无法从 MSNotificationHubMessage.UserInfo getter 获取 NSDictionary,并在此行中断:

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


有例外:

[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. 集线器注册必须在主线程中调用。否则 Xamarin.Azure.NotificationHubs.iOS 甚至不会给出出错的提示。

  2. 当实际类型为 NSDictionary 时,MSNotificationHub 的新方法在获取 UserInfo 并将其转换为 NSDictionary 时存在错误。 GitHub已经发布了一段时间了,但是还没有得到团队的任何回应,所以如果你通过推送通知传递消息以外的任何数据,抱歉,不行。

  3. 使用 SBNotificationHub 的旧方法具有严格的模板格式。首先,您应该使用 RegisterTemplate 方法来排除错误,而不是使用回调方法,因为前者是唯一出于某种原因给出错误描述的方法。 其次,你不能使用 {$(field)} 构造子定义模板,你需要指定属性的插入格式,如: "alert":"$( messageParam)","badge":"#(badge)","content-available":"#(contentAvailable)" 等。您还需要修改调度程序,以便它始终发送未加引号的参数。

IOS 实现非常原始,half-done 被遗忘了。我知道与 Apple 交互是完全地狱般的痛苦,但仍然...

希望它能为人们节省很多很多时间。

除了 Serg 的回答,您还需要使用 MainThread.BeginInvokeOnMainThread 进行 MSNotificationHub 注册。

不要使用Device.BeginInvokeOnMainThread,它不起作用。

除了我的回答。我现在有 azure pushes,但我的解决方案混合了新旧方法。他们每个人都不能单独工作。

对于android: 当我使用新方法时,会在 azure 通知中心进行注册,但不会收到通知。 当我使用旧方法时,没有来自 azure 通知中心的通知。

  1. 必须在 RunOnUiThread 中为新方法调用集线器注册:
    NotificationHub.Start(MainActivity.Instance.Application, NotificationHubName, ConnectionString);
    NotificationHub.SetListener(new AzureListener());
  1. AzureListener 的实现 class 是存根:
    /// <summary>
    /// It does nothing, but registrasion doesn't work without it.
    /// </summary>
    public class AzureListener : Java.Lang.Object, INotificationListener
    {
        /// <summary>
        /// Stub
        /// </summary>
        /// <param name="context"></param>
        /// <param name="message"></param>
        public void OnPushNotificationReceived(Context context, INotificationMessage message)
        {}
    }
  1. 对于旧方法,必须在非主线程中调用集线器注册:
    await Task.Run(async () =>
    {
        await Task.Delay(1);
        this.notificationHub = new WindowsAzure.Messaging.NotificationHub(NotificationHubName,ConnectionString, MainActivity);
        
        notificationHub.UnregisterAll(PnsHandle);
        notificationHub.Register(PnsHandle, new string[] { });
    }
  1. 接收推送需要实现FirebaseMessagingServiceclass。

对于iOS: 当我使用新方法时,天蓝色通知中心没有注册。 当我使用旧方法时,在 azure hub 进行了注册,但没有来自 azure 通知中心的通知。

  1. 必须在 MainThread 中为新方法调用集线器注册:
    MSNotificationHub.Start(ConnectionString, NotificationHubName);
    MSNotificationHub.SetDelegate(new AzureNotificationHubListener());
  1. 对于旧方法,必须在 xamarin 主线程中调用集线器注册:
    await Device.InvokeOnMainThreadAsync(async () =>
    {
        Hub = new SBNotificationHub(connectionParameters.ConnectionString, connectionParameters.NotificationHubName);
        await Hub.RegisterNativeAsync(AppDelegate.PnsHandle, null);
    });
  1. 接收推送需要实现AzureNotificationHubListenerclass

  2. 需要在Info.plist中添加key:

    NSAppTransportSecurity <字典> NSAllowsArbitraryLoads