我一直在关注https://docs.microsoft.com/en-gb/azure/app-service-mobile/app-service-mobile-xamarin-forms-get-started-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:无法完成请求。 (未经授权) 在<24dbefba60fd49f4b193cdf58abf3290>:0中的Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient + d__24.MoveNext()[0x001da]中 ---从之前引发异常的位置开始的堆栈结束跟踪--- 在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task任务)[0x0003e]中位于<4d6eb5dfe2ab4eee884ef920069afd5f>:0中 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task任务)中的[0x00028]在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中 在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中的System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(System.Threading.Tasks.Task任务)[0x00008]处 在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中的System.Runtime.CompilerServices.TaskAwaiter.GetResult()[0x00000]处 在<24dbefba60fd49f4b193cdf58abf3290>:0中的Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient + d__26.MoveNext()[0x000fc]中 ---从之前引发异常的位置开始的堆栈结束跟踪--- 在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task任务)[0x0003e]中位于<4d6eb5dfe2ab4eee884ef920069afd5f>:0中 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task任务)中的[0x00028]在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中 在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中的System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(System.Threading.Tasks.Task任务)[0x00008]处 在System.Runtime.CompilerServices.TaskAwaiter`1 [TResult] .GetResult()[0x00000]在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中 在<24dbefba60fd49f4b193cdf58abf3290>:0中的Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient + d__18.MoveNext()[0x000f0]中 ---从之前引发异常的位置开始的堆栈结束跟踪--- 在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task任务)[0x0003e]中位于<4d6eb5dfe2ab4eee884ef920069afd5f>:0中 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task任务)中的[0x00028]在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中 在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中的System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(System.Threading.Tasks.Task任务)[0x00008]处 在<4d6eb5dfe2ab4eee884ef920069afd5f>:0中的System.Runtime.CompilerServices.TaskAwaiter.GetResult()[0x00000]处 在/Users/mirad/mobileDevGit/OrganizerApp/Organizer.Android/MainActivity.cs:159}中的Organizer.Droid.MyFirebaseIIDService + d__1.MoveNext()[0x00095]
服务器的响应是:
{StatusCode:401,ReasonPhrase:“未经授权”,版本:1.1,内容:System.Net.Http.StreamContent,标头: { 传输编码:分块 伺服器:Microsoft-HTTPAPI / 2.0 日期:2018年8月31日星期五13:21:44 GMT 内容类型: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);
}
}
}
感谢所有帮助。