Push-уведомления с формами Xamarin: MobileServiceClient RegisterAsync завершается с ошибкой 401 в Xamarin.Android - PullRequest
0 голосов
/ 31 августа 2018

Я следую учебному пособию https://docs.microsoft.com/en-gb/azure/app-service-mobile/app-service-mobile-xamarin-forms-get-started-push, (добавление push-уведомлений в проект Android)

Вот метод, который связывается с сервером:

async Task SendRegistrationToServerAsync(string token)
    {
        try
        {
            // Formats: https://firebase.google.com/docs/cloud-messaging/concept-options
            // The "notification" format will automatically displayed in the notification center if the 
            // app is not in the foreground.
            const string templateBodyFCM =
                "{" +
                    "\"notification\" : {" +
                    "\"body\" : \"$(messageParam)\"," +
                      "\"title\" : \"Xamarin University\"," +
                    "\"icon\" : \"myicon\" }" +
                "}";

            var templates = new JObject();
            templates["genericMessage"] = new JObject
            {
                {"body", templateBodyFCM}
            };

            var client = new MobileServiceClient(Organizer.App.MobileServiceUrl);
            var push = client.GetPush();

            await push.RegisterAsync(token, templates); // CRASH!!!

            // Push object contains installation ID afterwards.
            Console.WriteLine(push.InstallationId.ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Debugger.Break();
        }
    }

Сбой при выполнении метода RegisterAsync:

{Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException: запрос не может быть выполнен. (Несанкционированное) в Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient + d__24.MoveNext () [0x001da] в <24dbefba60fd49f4b193cdf58abf3290>: 0 --- Конец стека трассировки от предыдущего местоположения, где было сгенерировано исключение --- в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (задача System.Threading.Tasks.Task) [0x0003e] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (задача System.Threading.Tasks.Task) [0x00008] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient + d__26.MoveNext () [0x000fc] в <24dbefba60fd49f4b193cdf58abf3290>: 0 --- Конец стека трассировки от предыдущего местоположения, где было сгенерировано исключение --- в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (задача System.Threading.Tasks.Task) [0x0003e] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (задача System.Threading.Tasks.Task) [0x00008] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 at System.Runtime.CompilerServices.TaskAwaiter`1 [TResult] .GetResult () [0x00000] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient + d__18.MoveNext () [0x000f0] в <24dbefba60fd49f4b193cdf58abf3290>: 0 --- Конец стека трассировки от предыдущего местоположения, где было сгенерировано исключение --- в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (задача System.Threading.Tasks.Task) [0x0003e] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (задача System.Threading.Tasks.Task) [0x00008] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] в <4d6eb5dfe2ab4eee884ef920069afd5f>: 0 в Organizer.Droid.MyFirebaseIIDService + d__1.MoveNext () [0x00095] в /Users/mirad/mobileDevGit/OrganizerApp/Organizer.Android/MainActivity.cs:159}

Ответ от сервера:

{StatusCode: 401, ReasonPhrase: «Unauthorized», версия: 1.1, содержимое: System.Net.Http.StreamContent, заголовки: { Передача-кодировка: чанки Сервер: Microsoft-HTTPAPI / 2.0 Дата: пт, 31 августа 2018 13:21:44 GMT Content-Type: application / xml; кодировка = UTF-8 }}

Что необходимо настроить на сервере, чтобы мы не получили ошибку 401?

Или что еще может быть не так?

Вот полная MainActivity:

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    private const string TAG = "ANDROID_PUSH_NOTIFICATION";
    protected override void OnCreate(Bundle bundle)
    {

        System.Diagnostics.Debug.WriteLine("In OnCreate");
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(bundle);

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

        if (Intent.Extras != null)
        {
            foreach (var key in Intent.Extras.KeySet())
            {
                var value = Intent.Extras.GetString(key);
                Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
            }
        }

        IsPlayServicesAvailable(); 

        CreateNotificationChannel();


#if DEBUG
        // Force refresh of the token. If we redeploy the app, no new token will be sent but the old one will
        // be invalid.
        Task.Run(() =>
        {
            // This may not be executed on the main thread.
            FirebaseInstanceId.Instance.DeleteInstanceId();
            Console.WriteLine("Forced token: " + FirebaseInstanceId.Instance.Token);
        });
#endif
    }

    public bool IsPlayServicesAvailable()
    {
        int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
        if (resultCode != ConnectionResult.Success)
        {
            if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
            {
                // In a real project you can give the user a chance to fix the issue.
                Console.WriteLine($"Error: {GoogleApiAvailability.Instance.GetErrorString(resultCode)}");
            }
            else
            {
                Console.WriteLine("Error: Play services not supported!");
                Finish();
            }
            return false;
        }
        else
        {
            Console.WriteLine("Play Services available.");
            return true;
        }
    }

    void CreateNotificationChannel()
    {
        if (Build.VERSION.SdkInt < BuildVersionCodes.O)
        {
            // Notification channels are new in API 26 (and not a part of the
            // support library). There is no need to create a notification
            // channel on older versions of Android.
            return;
        }

        var channel = new NotificationChannel(MyFirebaseMessagingService.CHANNEL_ID,
                                              "FCM Notifications",
                                              NotificationImportance.Default)
        {

            Description = "Firebase Cloud Messages appear in this channel"
        };

        var notificationManager = (NotificationManager)GetSystemService(Android.Content.Context.NotificationService);
        notificationManager.CreateNotificationChannel(channel);
    }
}


// This service handles the device's registration with FCM.
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class MyFirebaseIIDService : FirebaseInstanceIdService
{

    public override void OnTokenRefresh()
    {
        var refreshedToken = FirebaseInstanceId.Instance.Token;
        Console.WriteLine($"Token received: {refreshedToken}");
        SendRegistrationToServerAsync(refreshedToken);

        //SendRegistrationTokenToAzureNotificationHub(refreshedToken);
    }



    async Task SendRegistrationToServerAsync(string token)
    {
        try
        {
            // Formats: https://firebase.google.com/docs/cloud-messaging/concept-options
            // The "notification" format will automatically displayed in the notification center if the 
            // app is not in the foreground.
            const string templateBodyFCM =
                "{" +
                    "\"notification\" : {" +
                    "\"body\" : \"$(messageParam)\"," +
                      "\"title\" : \"Xamarin University\"," +
                    "\"icon\" : \"myicon\" }" +
                "}";

            var templates = new JObject();
            templates["genericMessage"] = new JObject
            {
                {"body", templateBodyFCM}
            };

            var client = new MobileServiceClient(Organizer.App.MobileServiceUrl);
            var push = client.GetPush();

            await push.RegisterAsync(token, templates);
            //await push.RegisterAsync(token);

            // Push object contains installation ID afterwards.
            Console.WriteLine(push.InstallationId.ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Debugger.Break();
        }
    }


}

// This service is used if app is in the foreground and a message is received.
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
    public const string CHANNEL_ID = "MY_CHANNEL_ID";

    public override void OnMessageReceived(RemoteMessage message)
    {
        base.OnMessageReceived(message);

        Console.WriteLine("Received: " + message);

        // Android supports different message payloads. To use the code below it must be something like this (you can paste this into Azure test send window):
        // {
        //   "notification" : {
        //      "body" : "The body",
        //                 "title" : "The title",
        //                 "icon" : "myicon
        //   }
        // }
        try
        {
            var msg = message.GetNotification().Body;
            MessagingCenter.Send<object, string>(this, Organizer.App.NotificationReceivedKey, msg);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error extracting message: " + ex);
        }
    }
}

Спасибо за помощь.

...