如何在 Xamarin Forms iOS-App 中接收 ASPN 令牌
How to receive the ASPN Token in Xamarin Forms iOS-App
我按照 this 教程在我的 Xamarin-Forms 应用程序中实现推送通知(尤其是 iOS 部分)。现在我的问题是,当我按下注册按钮时,我收到错误消息“无法为 APNS 解析令牌”。
在调试模式下单步执行代码,我可以验证 DeviceInstallationService 中的 Token 属性 确实是 null。
所以我退后一步,发现 Token 仅通过 AppDelegate.cs 中的 RegisteredForRemoteNotification 设置,但是当我 运行 App.
时从未调用此方法
这是一些代码:App-Delegate
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Foundation;
using Notes.iOS.Extensions;
using Notes.iOS.Services;
using Notes.Services;
using UIKit;
using UserNotifications;
using Xamarin.Essentials;
using System.Collections.Generic;
using System.Linq;
using Syncfusion.SfCalendar.XForms.iOS;
namespace Notes.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
IPushDemoNotificationActionService _notificationActionService;
INotificationRegistrationService _notificationRegistrationService;
IDeviceInstallationService _deviceInstallationService;
IPushDemoNotificationActionService NotificationActionService
=> _notificationActionService ??
(_notificationActionService =
ServiceContainer.Resolve<IPushDemoNotificationActionService>());
INotificationRegistrationService NotificationRegistrationService
=> _notificationRegistrationService ??
(_notificationRegistrationService =
ServiceContainer.Resolve<INotificationRegistrationService>());
IDeviceInstallationService DeviceInstallationService
=> _deviceInstallationService ??
(_deviceInstallationService =
ServiceContainer.Resolve<IDeviceInstallationService>());
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
Bootstrap.Begin(() => new DeviceInstallationService());
if (DeviceInstallationService.NotificationsSupported)
{
UNUserNotificationCenter.Current.RequestAuthorization(
UNAuthorizationOptions.Alert |
UNAuthorizationOptions.Badge |
UNAuthorizationOptions.Sound,
(approvalGranted, error) =>
{
if (approvalGranted && error == null)
RegisterForRemoteNotifications();
});
}
LoadApplication(new App());
using (var userInfo = options?.ObjectForKey(
UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary)
ProcessNotificationActions(userInfo);
return base.FinishedLaunching(app, options);
}
void RegisterForRemoteNotifications()
{
MainThread.BeginInvokeOnMainThread(() =>
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert |
UIUserNotificationType.Badge |
UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
});
}
Task CompleteRegistrationAsync(NSData deviceToken)
{
DeviceInstallationService.Token = deviceToken.ToHexString();
return NotificationRegistrationService.RefreshRegistrationAsync();
}
void ProcessNotificationActions(NSDictionary userInfo)
{
if (userInfo == null)
return;
try
{
var actionValue = userInfo.ObjectForKey(new NSString("action")) as NSString;
if (!string.IsNullOrWhiteSpace(actionValue?.Description))
NotificationActionService.TriggerAction(actionValue.Description);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
=> CompleteRegistrationAsync(deviceToken).ContinueWith((task)
=> { if (task.IsFaulted) throw task.Exception; });
public override void ReceivedRemoteNotification(
UIApplication application,
NSDictionary userInfo)
=> ProcessNotificationActions(userInfo);
public override void FailedToRegisterForRemoteNotifications(
UIApplication application,
NSError error)
=> Debug.WriteLine(error.Description);
}
}
DeviceInstallationService:
using System;
using Notes.Models;
using Notes.Services;
using UIKit;
namespace Notes.iOS.Services
{
public class DeviceInstallationService : IDeviceInstallationService
{
const int SupportedVersionMajor = 13;
const int SupportedVersionMinor = 0;
public string Token { get; set; }
public bool NotificationsSupported
=> UIDevice.CurrentDevice.CheckSystemVersion(SupportedVersionMajor, SupportedVersionMinor);
public string GetDeviceId()
=> UIDevice.CurrentDevice.IdentifierForVendor.ToString();
public DeviceInstallation GetDeviceInstallation(params string[] tags)
{
if (!NotificationsSupported)
throw new Exception(GetNotificationsSupportError());
if (string.IsNullOrWhiteSpace(Token))
throw new Exception("Unable to resolve token for APNS");
var installation = new DeviceInstallation
{
InstallationId = GetDeviceId(),
Platform = "apns",
PushChannel = Token
};
installation.Tags.AddRange(tags);
return installation;
}
string GetNotificationsSupportError()
{
if (!NotificationsSupported)
return $"This app only supports notifications on iOS {SupportedVersionMajor}.{SupportedVersionMinor} and above. You are running {UIDevice.CurrentDevice.SystemVersion}.";
if (Token == null)
return $"This app can support notifications but you must enable this in your settings.";
return "An error occurred preventing the use of push notifications";
}
}
}
如您所见,这确实是 1:1 示例代码,唯一不同的是我的项目名为 Notes。
我跳过了 Firebase 和 Android-Part,因为到目前为止我只需要 iOS 的推送通知,据我所知,这些对于 iOS 不是必需的。
感谢您的帮助!
检查 RegisteredForRemoteNotification
是否未被调用的一些要点:
打开 Entitlements.plist
并确保在 Entitlements
选项卡中查看时选中 Enable Push Notifications
。然后,确保在源选项卡中查看时将 APS 环境设置设置为开发。
确保您在真实设备而不是模拟器中测试远程通知。模拟器不支持远程通知。
确保您同意接收通知权限。
确保您使用的证书已启用推送通知功能。
您可以在您的 App Delegate 中查看以下函数返回的消息 AppDelegate.cs
public override void FailedToRegisterForRemoteNotifications(
UIApplication application,
NSError error)
例如
no valid “aps-environment” entitlement string found for application
我按照 this 教程在我的 Xamarin-Forms 应用程序中实现推送通知(尤其是 iOS 部分)。现在我的问题是,当我按下注册按钮时,我收到错误消息“无法为 APNS 解析令牌”。 在调试模式下单步执行代码,我可以验证 DeviceInstallationService 中的 Token 属性 确实是 null。 所以我退后一步,发现 Token 仅通过 AppDelegate.cs 中的 RegisteredForRemoteNotification 设置,但是当我 运行 App.
时从未调用此方法这是一些代码:App-Delegate
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Foundation;
using Notes.iOS.Extensions;
using Notes.iOS.Services;
using Notes.Services;
using UIKit;
using UserNotifications;
using Xamarin.Essentials;
using System.Collections.Generic;
using System.Linq;
using Syncfusion.SfCalendar.XForms.iOS;
namespace Notes.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
IPushDemoNotificationActionService _notificationActionService;
INotificationRegistrationService _notificationRegistrationService;
IDeviceInstallationService _deviceInstallationService;
IPushDemoNotificationActionService NotificationActionService
=> _notificationActionService ??
(_notificationActionService =
ServiceContainer.Resolve<IPushDemoNotificationActionService>());
INotificationRegistrationService NotificationRegistrationService
=> _notificationRegistrationService ??
(_notificationRegistrationService =
ServiceContainer.Resolve<INotificationRegistrationService>());
IDeviceInstallationService DeviceInstallationService
=> _deviceInstallationService ??
(_deviceInstallationService =
ServiceContainer.Resolve<IDeviceInstallationService>());
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
Bootstrap.Begin(() => new DeviceInstallationService());
if (DeviceInstallationService.NotificationsSupported)
{
UNUserNotificationCenter.Current.RequestAuthorization(
UNAuthorizationOptions.Alert |
UNAuthorizationOptions.Badge |
UNAuthorizationOptions.Sound,
(approvalGranted, error) =>
{
if (approvalGranted && error == null)
RegisterForRemoteNotifications();
});
}
LoadApplication(new App());
using (var userInfo = options?.ObjectForKey(
UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary)
ProcessNotificationActions(userInfo);
return base.FinishedLaunching(app, options);
}
void RegisterForRemoteNotifications()
{
MainThread.BeginInvokeOnMainThread(() =>
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert |
UIUserNotificationType.Badge |
UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
});
}
Task CompleteRegistrationAsync(NSData deviceToken)
{
DeviceInstallationService.Token = deviceToken.ToHexString();
return NotificationRegistrationService.RefreshRegistrationAsync();
}
void ProcessNotificationActions(NSDictionary userInfo)
{
if (userInfo == null)
return;
try
{
var actionValue = userInfo.ObjectForKey(new NSString("action")) as NSString;
if (!string.IsNullOrWhiteSpace(actionValue?.Description))
NotificationActionService.TriggerAction(actionValue.Description);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
=> CompleteRegistrationAsync(deviceToken).ContinueWith((task)
=> { if (task.IsFaulted) throw task.Exception; });
public override void ReceivedRemoteNotification(
UIApplication application,
NSDictionary userInfo)
=> ProcessNotificationActions(userInfo);
public override void FailedToRegisterForRemoteNotifications(
UIApplication application,
NSError error)
=> Debug.WriteLine(error.Description);
}
}
DeviceInstallationService:
using System;
using Notes.Models;
using Notes.Services;
using UIKit;
namespace Notes.iOS.Services
{
public class DeviceInstallationService : IDeviceInstallationService
{
const int SupportedVersionMajor = 13;
const int SupportedVersionMinor = 0;
public string Token { get; set; }
public bool NotificationsSupported
=> UIDevice.CurrentDevice.CheckSystemVersion(SupportedVersionMajor, SupportedVersionMinor);
public string GetDeviceId()
=> UIDevice.CurrentDevice.IdentifierForVendor.ToString();
public DeviceInstallation GetDeviceInstallation(params string[] tags)
{
if (!NotificationsSupported)
throw new Exception(GetNotificationsSupportError());
if (string.IsNullOrWhiteSpace(Token))
throw new Exception("Unable to resolve token for APNS");
var installation = new DeviceInstallation
{
InstallationId = GetDeviceId(),
Platform = "apns",
PushChannel = Token
};
installation.Tags.AddRange(tags);
return installation;
}
string GetNotificationsSupportError()
{
if (!NotificationsSupported)
return $"This app only supports notifications on iOS {SupportedVersionMajor}.{SupportedVersionMinor} and above. You are running {UIDevice.CurrentDevice.SystemVersion}.";
if (Token == null)
return $"This app can support notifications but you must enable this in your settings.";
return "An error occurred preventing the use of push notifications";
}
}
}
如您所见,这确实是 1:1 示例代码,唯一不同的是我的项目名为 Notes。
我跳过了 Firebase 和 Android-Part,因为到目前为止我只需要 iOS 的推送通知,据我所知,这些对于 iOS 不是必需的。
感谢您的帮助!
检查 RegisteredForRemoteNotification
是否未被调用的一些要点:
打开
Entitlements.plist
并确保在Entitlements
选项卡中查看时选中Enable Push Notifications
。然后,确保在源选项卡中查看时将 APS 环境设置设置为开发。确保您在真实设备而不是模拟器中测试远程通知。模拟器不支持远程通知。
确保您同意接收通知权限。
确保您使用的证书已启用推送通知功能。
您可以在您的 App Delegate 中查看以下函数返回的消息 AppDelegate.cs
public override void FailedToRegisterForRemoteNotifications(
UIApplication application,
NSError error)
例如
no valid “aps-environment” entitlement string found for application