xamarin / xamarin-macios

.NET for iOS, Mac Catalyst, macOS, and tvOS provide open-source bindings of the Apple SDKs for use with .NET managed languages such as C#
Other
2.45k stars 511 forks source link

Nested Register callback does not work when run on threadpool using Task.Run or Task.Factory.StartNew with any options combo #9213

Closed FrankSzendzielarz closed 4 years ago

FrankSzendzielarz commented 4 years ago

For the ios head of a Xamarin.Forms app, ios push notifications with the 2.04 library were not working for me.

After investigation I found that this was because the device was not registering. Even though the SBNotificationHub RegisterTemplate (callback overload) was being executed, no device was being registered with the hub.

Most of the samples and examples online use a RegisteredForRemoteNotifications override where the Hub.UnregisterAll passes a callback to code which then uses Hub.RegisterTemplate/Native , with a further callback to check for the error and log it.

In my implementation, that code is moved to a DependencyService , where the native implementation is wrapped in a Task.Run.

So like this:

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

            App.NotificationManager.SetRegistrationId(deviceToken);

            App.NotificationManager.RegisterDevice();

RegisterDevice contains the native implementation, but is wrapped in a Task.Run.

In this case, the nested callbacks do not work. They seem to execute without error, but no device registration occurs.

By switching to the overloads that return NSError , the implementation works.

This can be repro'd using the example below:

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

            App.NotificationManager.SetRegistrationId(deviceToken);

            Task.Run(() => { 
            var test = new ConcurrentDictionary<string, int>();
            test.AddOrUpdate("test", 0, (x, y) => y);

            Hub.UnregisterAll(deviceToken, (errorC) =>
            {
                if (errorC != null)
                {
                    Debug.WriteLine($"Unable to call unregister {errorC}");
                    return;
                }

                try
                {

                    var tagsetLoud = new NSSet(test.Keys.ToArray());
                    var tagsetSilent = new NSSet(test.Keys.Append("silent").ToArray());

                    Hub.RegisterNative(deviceToken, tagsetLoud, (errorCallback) =>
                    {
                        if (errorCallback != null)
                        {

                        }
                        else
                        {

                        }
                    });

                    var templateExpiration = DateTime.Now.AddDays(120).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
                    AppDelegate.Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tagsetLoud, (errorCallback) =>
                    {

                        if (errorCallback != null)
                        {

                        }

                    });

                }
                catch
                {
                    Debug.WriteLine("Failure registering");
                }
            });
        });

        }
ehuna commented 4 years ago

We we are forced to migrate out of App Center Push Notifications (see https://devblogs.microsoft.com/appcenter/migrating-off-app-center-push/)

While migrating one of our Xamarin Form apps to Notification Hubs, I ran into the same issue on the iOS app.

What finally worked for us is to also switch to the overloads that return an NSError and also wrap this code in a method RegisterWithNotificationHub() - like this:

Task.Run(() => Device.BeginInvokeOnMainThread(() => RegisterWithNotificationHub())).Wait();

Spent a couple of days to get this working, here are a few documents that reference the callbacks on error, which do not work on with the latest VS, Xamarin iOS, Mono, Xcode, and iOS SDK -

FrankSzendzielarz commented 4 years ago

Can we get more eyes on this. It looks like this is a major bork in the platform lib . Eg discussion here. https://forums.xamarin.com/discussion/180027/xamarin-ios-azure-notification-hubs-with-xcode-11-3-and-ios-13-3-issue

Even better, can we get someone from the xamarin.ios team to shed some light on what the underlying issue is here? I'd really love to understand what the ios/task/thread relationship is and why this is so flaky.

chamons commented 4 years ago

Hey everyone - thanks for the report!

I'm not certain that it's an SDK issue yet, but there is enough possibly here for me to move the issue to xamarin-macios.

There are a lot of moving pieces here. We need a (small) project test case showing the exact problem you are seeing.

FrankSzendzielarz commented 4 years ago

Ok @chamons I will be able to do this literally either tonight or early next week. If it behaves differently in a minimal project though I will be heartbroken. So far it's looking take any notifications code sample with the callback Register method nested in the Unregister callack, wrap the whole thing in Task.Run and the register methods complete without doing anything

monahan7 commented 4 years ago

I am having a similar issue. I was registering in AppDelegate, and then registering again after login, using tags. I pull the tags during the login/authentication process. The code in AppDelegate attempts to pull tags from localstorage, and if found, the registration succeeds. I switched to use the overloads that return NSError - as per FrankSzendzielarz's suggestion.

NSSet tags = null;

string storage_TildeDelimitedUserTags = GetSecureStorage("TildeDelimitedUserTags");
if (!string.IsNullOrEmpty(storage_TildeDelimitedUserTags))
{
    string[] spl_TildeDelimitedUserTags = storage_TildeDelimitedUserTags.Split('~');
    tags = new NSSet(spl_TildeDelimitedUserTags);
}
App.RegisteredForRemoteNotifications = "Tags: " + storage_TildeDelimitedUserTags;

//update registration with Azure Notification Hub
Hub = new SBNotificationHub(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);
Hub.UnregisterAll(deviceToken, (error) =>
{
    if (error != null)
    {
        App.UnregisterAll = "Unable to call unregister: " + error;
        return;
    }
    else
    {
        App.UnregisterAll = "UnregisterAll Success!";
    }

    if (tags != null)
    {
        NSError ns_error = null;

        var templateExpiration = DateTime.Now.AddDays(365).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
        Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, out ns_error);
        if (ns_error != null)
        {
            App.RegisterTemplateAsync = "RegisterTemplateAsync error: " + ns_error;
        }
        else
        {
            App.RegisterTemplateAsync = "RegisterTemplateAsync Success!";
        }
        tags.Dispose();
    }

});

NOTE that my current implementation is registering ONLY if I have tags. This was not the way I originally had it, when I was running the registration after login...

Anyway, I was seeing some iphones register successfully, and others that refused to register. So I removed the code that runs registration after the login, and added a button in my app for testing. The button runs registration code in the iOS project. This code is pretty much identical to the code above. And here is the button click event code:

//use DependencyService to call andoid/iOS code that registers with azure notificationhub.
switch (Device.RuntimePlatform)
{
    case Device.iOS:
        //await Task.Run(() =>
        //{
            DependencyService.Get<SixTen.Interfaces.IRegisterTags>().RegTags(SixTenMemberApp.App.IosToken);
        //});
        break;
    case Device.Android:
        await Task.Run(() =>
        {
            DependencyService.Get<SixTen.Interfaces.IRegisterTags>().RegTags(SixTenMemberApp.App.AndroidToken);
        });
        break;
}

I log my results to my database, and I can see that unregister and register are a success. But, my registration that could be found in my azure notification hub after login, is now missing from the hub. So it seems unregister runs as expected, but register reports success, but actually failed.

Note that in the code above, uncommenting await Task.Run(() => doesn't help - I get the same results.

So. I suspect my registration that runs after login, fails for some users the same way I am seeing this button code fail. I would like to be able to add the code that runs after login back into the flow. The way I have it now, a user must login to set the tags in localstorage, then close and open the app to register the tags.

Perhaps someone can see something I am doing wrong in my pasted code? Or is the code correct, and we have an issue with the way registration happens?

chamons commented 4 years ago

I'm going to repeat my earlier earlier request:

We need a (small) project test case showing the exact problem you are seeing.

odinhaus commented 4 years ago

I have a "hello world" example for you.
Just create a default Xamarin Forms iOS project, and replace the AppDelegate with the code below, and then set the build options, entitlements, etc, to allow Push notifications as usual. No other code needs to be changed.

Neither the Sync or Async methods ever register the device.

The Sync methods complete, but the error callbacks are never called.

The Async methods will hang forever if you uncomment those lines (and add the async keyword to the method declaration, of course).

using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using UIKit;
using UserNotifications;
using WindowsAzure.Messaging;

namespace APNTest.Forms.iOS
{
    // The UIApplicationDelegate for the application. This class is responsible for launching the 
    // User Interface of the application, as well as listening (and optionally responding) to 
    // application events from iOS.
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public SBNotificationHub Hub { get; private set; }

        //
        // This method is invoked when the application has loaded and is ready to run. In this 
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());
            // Override point for customization after application launch.
            // If not required for your application you can safely delete this method

            if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
            {
                UNUserNotificationCenter.Current.RequestAuthorization(
                    UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
                    (granted, error) => InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications));
            }
            else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
            {
                var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
                    UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
                    new NSSet());
                UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
                UIApplication.SharedApplication.RegisterForRemoteNotifications();
            }
            else
            {
                var types = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
                UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(types);
            }

            return base.FinishedLaunching(app, options);
        }

        public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
        {
            this.Hub = new SBNotificationHub(Constants.ListenConnectionString, Constants.HubName);

            this.Hub.UnregisterAll(deviceToken, (error) =>
            {
                // the callback is never called...
                if (error != null)
                {
                    System.Diagnostics.Debug.WriteLine("Error calling unregister: {0}", error.ToString());
                    return;
                }
                NSSet tags = null;
                this.Hub.RegisterNative(deviceToken, tags, (e) =>
                {
                    if (e != null)
                    {
                        System.Diagnostics.Debug.WriteLine("Error calling unregister: {0}", e.ToString());
                    }
                });
            });

            //await this.Hub.UnregisterAllAsync(deviceToken);
            //await this.Hub.RegisterNativeAsync(deviceToken, null);
        }

        public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
        {
            System.Diagnostics.Debug.WriteLine("Message received: {0}", userInfo.ToString());
        }

        public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
        {
            base.FailedToRegisterForRemoteNotifications(application, error);
        }

    }

    public class Constants
    {
        public const string ListenConnectionString = "Endpoint=sb://tempotesting.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=KSyI/oqIRudG7tD8/z2vAda17PoRNDxA3J0bSWmuo10=";
        public const string HubName = "Push";
    }
}

I am compiling with XCode 11.6, on Catalina 10.15.6. My dev environment is Visual Studio 16.6.5. I have the same issue with either Xamarin.Azure.NotificationHubs.iOS v3.0.0-preview4 or 2.0.4. Azure is configured to use Sandbox Token APNS. My test device is an iPhone 8 Plus running iOS 13.5.1 connected to my Windows development machine via iTunes. I am using Xamarin Hot Reload for deployment to the device.

monahan7 commented 4 years ago

I have this sample app for you. I am running visual studio 2019, paired to a macbookpro.

When the app starts, it registers tags with the azure notification hub.

The app has 1 button on the main page. Click the button, it will register the tags again. You can see, using breakpoints, that unregister, and register are successful.

Look at the 2 attached screenshots. You can see that after the app starts, the tags are there, and we have 60 registrations in my hub. After the button is clicked, the tags are gone (note, it is sorted by tag), and we have 59 registrations. So it seems the unregister works, and the register fails, even though it says success?

TestNotificationApp.zip

hub_after_appstart

hub_after_button

I have removed my hub credentials, and bundle identifier from the code - email me if you need them. kevinmonahan@cylor.com

NOTE: I don't always have my tags when the app starts. I get the tags at login, and then I need to register again with the tags. So this button is mimicking the registration made after the login.

FrankSzendzielarz commented 4 years ago

Omg I am lagging behind. I will put a csproj together tomorrow too. I promised @chamons one early this week and it's already Tuesday!!! 😟

monahan7 commented 4 years ago

Found something that may be of use.

In my button code in my sample app, I have this:

Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, out ns_error);

ns_error comes back null, but the registration never happens.

So I tried the old way:

Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, (errorCallback) =>
{
    if (errorCallback == null)
    {
        App.RegisterTemplateAsync = "RegisterTemplateAsync Success!";
    }
    else
    {
        System.Diagnostics.Debug.WriteLine($"RegisterTemplateAsync error: {errorCallback}");
        App.SendApiDebugLog("iOS RegisterTags", "RegTags", "errorCallback", $"{errorCallback}");
    }
});
tags.Dispose();

In this code, if (errorCallback == null) never gets hit. The execution goes straight to tags.Dispose() in debug. And of course the registration fails.

I believe this goes to FrankSzendzielarz's original post here.

monahan7 commented 4 years ago

After more testing - I find that this works - and will for now be the solution I go with. I removed the callback from Unregister. Doing it this way, I can see the registration removed from my hub after unregister, and it is added back after register.

NSError ns_error = null;

Hub = new SBNotificationHub(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);
Hub.UnregisterAll(deviceToken, out ns_error);
if (ns_error != null)
{
    App.UnregisterAll = "Unable to call unregister: " + ns_error;
    return;
}
else
{
    App.UnregisterAll = "UnregisterAll Success!";
}

var templateExpiration = DateTime.Now.AddDays(365).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, out ns_error);
if (ns_error == null)
{
    App.RegisterTemplateAsync = "RegisterTemplateAsync Success!";
}
else
{
    App.RegisterTemplateAsync = "RegisterTemplateAsync error: " + ns_error;
}

So the code in AppDelegate will remain the same, with the callback in place. But any call made to register after login, or with a button click, will have the callback removed.

I am worried that I may potentially have a timing issue, where unregister could happen after register - so i am going to look into adding async await code to make separate calls for unregister and register.

I really would like to know why the callback fails outside of AppDelegate??

odinhaus commented 4 years ago

My callbacks fail inside AppDelegate

monahan7 commented 4 years ago

odinhaus - In AppDelegate, I have a callback on UnregisterAll, but do not have a callback on RegisterTemplate. The callback assures me that the unregister is completed, before I register. I don't think I need the callback on register for reasons of timing.

NSError ns_error = null;
var templateExpiration = DateTime.Now.AddDays(365).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, out ns_error);

I have this code inside of the UnregisterAll callback. I check for null ns_error to determine failure or success.

Not sure if this will work for you?

odinhaus commented 4 years ago

Sadly, it does not help, as the callback for UnregisterAll never fires for me, so I don't make it to the RegiserXXX call.

monahan7 commented 4 years ago

Do you have a valid deviceToken? Other than that - your code is the same as mine, leading up the the UnregisterAll call.

I do notice one difference. I am calling base.FinishedLaunching(app, options); in FinishedLaunching, BEFORE I register with hub.

You are calling it afterwards. Perhaps this makes a difference??

Download my sample app above - if you don't have visual studio - you can just open AppDelegate with a text editor.

global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());

base.FinishedLaunching(app, options);

//push notifications
RegisterForRemoteNotifications();
return true;
odinhaus commented 4 years ago

Same issue, callback is never executed

chamons commented 4 years ago

Friendly reminder everyone - this is still marked need-info so no one will be able to make any major progress.

There are a lot of moving pieces here. We need a (small) project test case showing the exact problem you are seeing.

Bits of code are a good first step, but we need details like "debug or release", what versions of what nugets? Device or simulator?

A sample, with detailed instructions that allow us to reproduce it, is the best next step.

odinhaus commented 4 years ago

For me, just create a default Xamarin.Forms iOS project and replace AppDelegate.cs with the code I posted.

Jump thru the usual hoops to create an iOS provisioning profile, APN Token (or Cert, it fails either way), set your entitlements to enable push, etc. All the usual 10,000 steps to get an iOS project to build for push.

Create the Azure hub, and in my case name it "Push", and then copy the endpoint and hub name and replace in my sample AppDelegate.cs code as necessary.

Enable Tools > Options > Xamarin - Hot Reload. Connect iOS iPhone to Windows PC via USB cable, and run iTunes. Run MacOS on VirtualBox Catalina with lastest Catalina, XCode and Visual Studio for Mac. Pair Windows Visual Studio to MacOS.

Set build to Debug, iPhone, iPhone Xamarin Project, iOS iPhone device.

F5

Set break point on line 67 of my AppDelegate.cs code. It is never called.

monahan7 commented 4 years ago

I added a project as an attachment 2 days ago - do you need more information? Here is the link to the zip file.

https://github.com/xamarin/xamarin-macios/files/5018095/TestNotificationApp.zip

Running in VS2019 in debug to a paired macbookpro - to iphone7 device. (Not a simulator)

NUGET: Xamarin.Azure.NotificationHubs.iOS v2.0.4 Xamarin.Essentials v1.3.1 NETStandard.Library 2.0.3 Xamarin.Forms v4.5.0.495

STEPS: 1) Run app - tags are registered with the hub 2) click the button on main page - unregister from hub works. Then register fails. So no longer see tags in the hub

Note: I can get this to work in the button click code - by removing all callbacks, as noted in my comment above.

monahan7 commented 4 years ago

So I have my final solution for now - until maybe something is fixed with the callback in the Hub.UnregisterAll code.

I had a working solution without callbacks, but I wanted to ensure Hub.UnregisterAll was completed before Hub.RegisterTemplate was called.

I used TaskCompletionSource - and not sure if this is necessary, but leaving it because it is working. Also, my final code has overkill with error handling, and logging, but I was trying to pinpoint my issue. Again, it is working as is, so just leaving it.

Note that I left the callbacks in AppDelegate, because that code is working. I pull tags from localstorage before I register, and those tags may not be there when the app starts, and the register code in AppDelegate runs. So, I need to grab the tags at login, and register again. The following code is the code I am using after login.

//use DependencyService to call andoid/iOS code that registers with azure notificationhub.
switch (Device.RuntimePlatform)
{
    case Device.iOS:
        await Task.Run(() =>
        {
             DependencyService.Get<SixTen.Interfaces.IRegisterTags>().Unregister(SixTenMemberApp.App.IosToken, TildeDelimitedUserTags);
        });
        break;
    case Device.Android:
        await Task.Run(() =>
        {
             DependencyService.Get<SixTen.Interfaces.IRegisterTags>().RegTags(SixTenMemberApp.App.AndroidToken, TildeDelimitedUserTags);
        });
        break;
}

Here is the Unregister code in the ios project:

//register with Azure NotificationHub
public void Unregister(object PassedToken, string TildeDelimitedUserTags)
{
    try
    {
        if (PassedToken != null)
        {
            App.SendApiDebugLog("iOS RegisterTags", "Unregister", "token", PassedToken.ToString());

            NSData deviceToken = (NSData)PassedToken;
            IosUnRegister(deviceToken, TildeDelimitedUserTags);
        }
        else
        {
            App.SendApiDebugLog("iOS RegisterTags", "Unregister", "token", "null");
        }

    }
    catch (Exception ex)
    {
        App.SendApiDebugLog("iOS RegisterTags", "Unregister", "Catch: ex.Message", ex.Message);
    }
}

private async void IosUnRegister(NSData deviceToken, string TildeDelimitedUserTags)
{
    bool IsSuccess = await Task.Run(() => IosUnregisterCode(deviceToken));
    if (IsSuccess == true)
    {
        IosRegister(deviceToken, TildeDelimitedUserTags);
    }
    else
    {
        App.SendApiDebugLog("handle_login", "UnRegisterIos", "IsSuccess", "false");
    }
}

private Task<bool> IosUnregisterCode(NSData deviceToken)
{
    var tcs = new TaskCompletionSource<bool>();
    SBNotificationHub Hub = null;

    try
    {
        Hub = new SBNotificationHub(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);
        Hub.UnregisterAll(deviceToken, (error) =>
        {
            if (error != null)
            {
                App.UnregisterAll = "Unable to call unregister: " + error;
                tcs.TrySetResult(false);
            }
            else
            {
                App.UnregisterAll = "UnregisterAll Success!";
                tcs.TrySetResult(true);
            }
        });

    }
    catch (Exception ex)
    {
        App.SendApiDebugLog("iOS RegisterTags", "IosUnregisterCode", "Catch: ex.Message", ex.Message);
        tcs.TrySetResult(false);
    }
    finally
    {
        Hub.Dispose();
    }
    return tcs.Task;
}

private async void IosRegister(NSData deviceToken, string TildeDelimitedUserTags)
{
    bool IsSuccess = await Task.Run(() => IosRegisterCode(deviceToken, TildeDelimitedUserTags));
    if (IsSuccess == true)
    {
        App.SendApiDebugLog("handle_login", "RegisterIos", "IsSuccess", "true");
    }
    else
    {
        App.SendApiDebugLog("handle_login", "RegisterIos", "IsSuccess", "false");
    }
    WriteStartupLogs();
}

private Task<bool> IosRegisterCode(NSData deviceToken, string TildeDelimitedUserTags)
{
    var tcs = new TaskCompletionSource<bool>();
    SBNotificationHub Hub = null;

    try
    {
        NSSet tags = null;

        if (!string.IsNullOrEmpty(TildeDelimitedUserTags))
        {
            string[] spl_TildeDelimitedUserTags = TildeDelimitedUserTags.Split('~');
            tags = new NSSet(spl_TildeDelimitedUserTags);
        }
        App.SendApiDebugLog("iOS RegisterTags", "IosRegisterCode", "storage_TildeDelimitedUserTags", TildeDelimitedUserTags);

        if (tags != null)
        {
            NSError ns_error = null;
            Hub = new SBNotificationHub(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);

            var templateExpiration = DateTime.Now.AddDays(365).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
            Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, out ns_error);
            if (ns_error != null)
            {
                App.RegisterTemplateAsync = "RegisterTemplateAsync error: " + ns_error;
                tcs.TrySetResult(false);
            }
            else
            {
                App.RegisterTemplateAsync = "RegisterTemplateAsync Success!";
                tcs.TrySetResult(true);
            }
            tags.Dispose();
        }
        else
        {
            tcs.TrySetResult(false);
        }
    }
    catch (Exception ex)
    {
        App.SendApiDebugLog("iOS RegisterTags", "IosRegisterCode", "Catch: ex.Message", ex.Message);
        tcs.TrySetResult(false);
    }
    finally
    {
        Hub.Dispose();
    }
    return tcs.Task;
}

private void WriteStartupLogs()
{
    App.WriteStartupLogsToDb();
}
whitneyschmidt commented 4 years ago

@monahan7 Glad that you were able to find a workaround.

Based on the code that you posted, the issue seems to stem from the using mono with the library SBNotificationHub, which is not part of the Xamarin.iOS/Mac SDK.

Looking around seems to show that there's a history of similar issues with Azure notifications hub, like this one: https://github.com/Azure/azure-notificationhubs-ios/issues/15

Unfortunately, since we don't own or maintain that code, there's not much we can do to fix any any issues that arise from using that library with Xamarin.

FrankSzendzielarz commented 4 years ago

Not sure if I understand that. If this isn't a platform problem, where do we direct the issue to? Azure/Xamarin docs refer to implementations using these libs.

On 13 Aug 2020 23:51, Whitney Schmidt notifications@github.com wrote:

@monahan7https://github.com/monahan7 Glad that you were able to find a workaround.

Based on the code that you posted, the issue seems to stem from the using mono with the library SBNotificationHub, which is not part of the Xamarin.iOS/Mac SDK.

Looking around seems to show that there's a history of similar issues with Azure notifications hub, like this one: Azure/azure-notificationhubs-ios#15https://github.com/Azure/azure-notificationhubs-ios/issues/15

Unfortunately, since we don't own or maintain that code, there's not much we can do to fix any any issues that arise from using that library with Xamarin.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/xamarin/xamarin-macios/issues/9213#issuecomment-673728107, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AH7WPTSVBJOZRSWHYKX7IQ3SARN5ZANCNFSM4PKRV2UA.

whitneyschmidt commented 4 years ago

@FrankSzendzielarz This repo looks like it's actively maintained by the Azure Notifications Hub team: https://github.com/Azure/azure-notificationhubs-ios

They also indicate that they proactively monitor their developer forum here: http://social.msdn.microsoft.com/Forums/en-US/notificationhubs/

This deprecated repo might contain some useful starting points as well: https://github.com/Azure/azure-notificationhubs

FrankSzendzielarz commented 4 years ago

I can't transfer to the azure-notifications-ios so here's a new issue: https://github.com/Azure/azure-notificationhubs-ios/issues/95

whitneyschmidt commented 4 years ago

Hi folks,

Thank you for your patience. I'm closing this issue as there's little indicate that issue lies with Xamarin or the SDK team. If further info emerges that points back to us or you need support using the SDK iOS/Mac library, feel free to re-open this issue or open a new one as appropriate.

FrankSzendzielarz commented 4 years ago

Someone is having fun with us. Look at the response we've got after moving the issue to your recommended place. https://github.com/Azure/azure-notificationhubs-ios/issues/95

For crying out loud. Can someone get their act together and sort this out?

odinhaus commented 4 years ago

I gave up on this. The code isnt production ready and the support is non-existent. Wasted two weeks of my life on this, and I’m not looking back.

Sent from my iPhone

On Sep 3, 2020, at 12:22 PM, Frank Szendzielarz notifications@github.com wrote:



Someone is having fun with us. Look at the response we've got after moving the issue to your recommended place. Azure/azure-notificationhubs-ios#95https://github.com/Azure/azure-notificationhubs-ios/issues/95

For crying out loud. Can someone get their act together and sort this out?

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/xamarin/xamarin-macios/issues/9213#issuecomment-686637053, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ACG5JWFNOHNJUZQ2X2L5LOLSD7GD5ANCNFSM4PKRV2UA.

FrankSzendzielarz commented 4 years ago

@whitneyschmidt the guys on the Azure Notification Hub team closed it saying it's a Xamarin issue. Could you please liaise directly with the commenter in the issue here? https://github.com/Azure/azure-notificationhubs-ios/issues/95

chamons commented 4 years ago

I've reached out to see if I can bring some clarity to the situation.

mpodwysocki commented 4 years ago

@FrankSzendzielarz For clarity sake, the issue was closed prematurely from our side. We'll work with you on the other repo for the issue. Please engage with us there.

Also for others on this thread, we have a new API that is actively being developed using MSNotificationHub instead of SBNotificationHub as the latter is legacy, using the installation APIs instead of the registration APIs.

mpodwysocki commented 4 years ago

As noted in the other thread and looping back here, it is an issue with our library.

@FrankSzendzielarz can reproduce the issue as well even with the latest version and will sync with the results. Got around the issue with invoking on the main thread for the registration call. The issue is with our dispatching as the UnregisterAll behind the scenes uses the main thread by default for scheduling, however, for the legacy system, no other calls do. We will need to address this in the library, or you can get around it immediately by invoking those on the main thread as well.

        [Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")]
        public void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
        {
            Task.Run(() =>
            {
                _hub.UnregisterAll(deviceToken, (error) =>
                {
                    if (error != null)
                    {
                        System.Diagnostics.Debug.WriteLine("Error calling Unregister: {0}", error.ToString());
                        return;
                    }

                    NSSet tags = null; // create tags if you want

                    InvokeOnMainThread(() =>
                    {
                        _hub.RegisterNative(deviceToken, tags, err =>
                        {
                            if (err != null)
                            {
                                Console.WriteLine(err.ToString());
                            }

                            Console.WriteLine("Registered");
                        });
                    });

                });
            });
        }
rolfbjarne commented 4 years ago

@mpodwysocki thanks for following up here!

Since this is not a bug Xamarin.iOS, I'm closing this issue (for the record, it's this: https://github.com/Azure/azure-notificationhubs-ios/issues/95)