我还没有找到任何苹果官方文档讨论如何正确地同时为旧版 iOS 版本以及 iOS 10 实现推送通知。而且我见过的独立教程同样涵盖了单个 iOS 版本。
我看到这个iOS 10的官方文档: Local and Remote Notifications Overview但它没有评论支持早期的 iOS 版本。
还有 iOS 9 的教程: Push Notifications Tutorial - Ray Wenderlich
我看到各种 stackoverflow 线程,内容涉及人们必须做出哪些更改才能让旧解决方案在新版本上运行:
Push notifications are not working in iOS 9 其中确实显示了处理 6 - 9 的代码。
didReceiveRemoteNotification not called , iOS 10
但我没有看到的是,从今天开始(iOS 10),什么是正确的做法,但也支持旧设备。 ** 更新 ** App Store 表示,下载应用程序的设备中只有 6% 的版本早于 iOS 9,因此如果只支持 9 + 10 更容易,我就会这么做。
(我尝试从 iOS 10 示例开始,但它在 iOS 9.3 模拟设备上立即崩溃,尽管它在 iOS 10 中运行良好。因此我得出的结论是,我应该从有关正确设置不同版本的信息开始。我可以发布该代码,但我认为这会将这个线程引向错误的方向。我宁愿从“应该”在多个版本的 iOS 上工作的内容开始,包括 10。)
如果我找不到解决方案,我将开始组合来自不同 stackoverflow 代码片段的代码......但是认真的吗?我一定错过了一些东西,因为想必每个 iOS 开发者都会遇到这个问题。
相反,我可以从较旧的示例开始,然后按照更改使其适用于 iOS 10 - 但这会充分利用 iOS 10 吗?>
注意:我正在使用 Xamarin C# 进行编程,但 Objective-C 或 Swift 答案同样有用。
最佳答案
这是 Xamarin C# 代码(语法和大小写与 Objective-C 不同,但我认为它可以逐行翻译为 Objective-C)。
在 iOS 9.3 和 iOS 10.2 上进行了测试。
初始化“本地”和“远程”通知:
// "UIApplicationDelegate" is for "local" notifications,
// "IUNUserNotificationCenterDelegate, IMessagingDelegate" for "remote" notifications.
public class AppDelegate : UIApplicationDelegate,
IUNUserNotificationCenterDelegate, IMessagingDelegate
{
...
public override bool FinishedLaunching( UIApplication application, NSDictionary launchOptions )
{
...
RegisterForOurRemoteNotifications( this );
RegisterForOurLocalNotifications();
...
}
...
// --- Comment out if not using Google FCM. ---
public override void RegisteredForRemoteNotifications( UIApplication application, NSData deviceToken )
{
//base.RegisteredForRemoteNotifications( application, deviceToken );
Firebase.InstanceID.InstanceId.SharedInstance.SetApnsToken( deviceToken,
Firebase.InstanceID.ApnsTokenType.Sandbox );
}
...
// ----- "static"; Could be in another class. -----
// These flags are for our convenience, so we know initialization was done.
static bool IsRegisteredForNotifications;
static bool IsRegisteredForRemoteNotifications;
// Optional - true when we are using Google "Firebase Cloud Messaging".
static bool HasFCM;
public static void RegisterForOurRemoteNotifications( AppDelegate del )
{
// Google "Firebase Cloud Messaging" (FCM) Monitor token generation
// (Uncomment, if you are using FCM for notifications.)
//InstanceId.Notifications.ObserveTokenRefresh( TokenRefreshNotification );
if (UIDevice.CurrentDevice.CheckSystemVersion( 10, 0 )) {
// iOS 10 or later
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization( authOptions, ( granted, error ) => {
Console.WriteLine( granted );
} );
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = del;
// For iOS 10 data message (sent via Google FCM).
// (Uncomment, if you are using FCM for notifications.)
// TBD: If NOT using FCM, you may need some other lines of code here.
//Messaging.SharedInstance.RemoteMessageDelegate = del;
} else {
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes( allNotificationTypes, null );
UIApplication.SharedApplication.RegisterUserNotificationSettings( settings );
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
IsRegisteredForRemoteNotifications = true;
// Uncomment if using Google "Firebase Cloud Messaging" (FCM).
//TokenRefreshNotification( null, null );
//if (UIDevice.CurrentDevice.CheckSystemVersion( 9, 0 )) // Needed to call this twice on iOS 9 for some reason.
// TokenRefreshNotification( null, null );
UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval( UIApplication.BackgroundFetchIntervalMinimum );
}
public static void RegisterForOurLocalNotifications()
{
// --- Our app's notification actions. ---
UNNotificationAction followAction = UNNotificationAction.FromIdentifier( "follow", PS.LocalizedString( "Follow" ), UNNotificationActionOptions.None );
UNNotificationAction likeAction = UNNotificationAction.FromIdentifier( "like", PS.LocalizedString( "Like" ), UNNotificationActionOptions.None );
// ...
// --- Our app's notification categories ---
UNNotificationCategory followCategory = UNNotificationCategory.FromIdentifier( "followCategory", new UNNotificationAction[] { followAction, likeAction },
new string[] { }, UNNotificationCategoryOptions.None );
// ...
// --- All of the app's categories from above ---
var categories = new UNNotificationCategory[] { followCategory /*, ...*/ };
// --- Same for all apps ---
UIUserNotificationSettings settings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert |
UIUserNotificationType.Badge |
UIUserNotificationType.Sound
, new NSSet( categories ) );
UIApplication.SharedApplication.RegisterUserNotificationSettings( settings );
if (UIDevice.CurrentDevice.CheckSystemVersion( 10, 0 )) {
UNUserNotificationCenter.Current.SetNotificationCategories( new NSSet<UNNotificationCategory>( categories ) );
UNUserNotificationCenter.Current.RequestAuthorization( UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound | UNAuthorizationOptions.Badge,
( result, err ) => {
Console.WriteLine( result.ToString() );
} );
}
IsRegisteredForNotifications = true;
}
}
// -------------------------------------------------------
// --- These are for Google "Firebase Cloud Messaging" ---
// (Comment out if not using FCM.)
public static string Token;
static void TokenRefreshNotification( object sender, NSNotificationEventArgs e )
{
// This method will be fired every time a new token is generated, including the first
// time. So if you need to retrieve the token as soon as it is available this is where that
// should be done.
//var refreshedToken = InstanceId.SharedInstance.Token;
ConnectToFCM( UIApplication.SharedApplication.KeyWindow.RootViewController );
// TODO: If necessary send token to application server.
}
public static void ConnectToFCM( UIViewController fromViewController )
{
Messaging.SharedInstance.Connect( error => {
if (error != null) {
Helper.logD( "Unable to connect to FCM", error.LocalizedDescription );
} else {
//var options = new NSDictionary();
//options.SetValueForKey( DeviceToken, Constants.RegisterAPNSOption );
//options.SetValueForKey( new NSNumber( true ), Constants.APNSServerTypeSandboxOption );
//InstanceId.SharedInstance.GetToken("", InstanceId.ScopeFirebaseMessaging
Token = InstanceId.SharedInstance.Token;
Console.WriteLine( $"Token: {InstanceId.SharedInstance.Token}" );
HasFCM = true;
}
} );
}
// ------------------ End Google FCM ---------------------
// -------------------------------------------------------
}
上面的代码初始化您的应用程序,以便它可以接收通知。
重要提示:您还需要在您的应用上设置适当的权限;请参阅 Apple 文档或问题中提到的链接。您需要这个文件:
权利.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>
<string>
上面必须包含“开发”或“生产”。 (我不知道我们的应用程序在这里仍然说“开发”的意义;我还没有检查构建的内容,看看在提交给 Apple 之前它是否会被 Xcode 自动更改为“生产”。根据 https://stackoverflow.com/a/40857877/199364 它确实如此。)
然后您需要代码来发送 [例如您的应用程序告诉您的服务器通知您 friend 的设备您现在正在做什么]并接收本地或远程通知。在我们的应用程序中,该代码与我们特定的通知操作和类别相结合;我没有时间提取简洁的版本发布在这里。有关完整详细信息,请参阅 Apple 文档或原始问题中提到的链接。
以下是接收通知的基本方法(添加到上面的class AppDelegate
):
public override void ReceivedLocalNotification( UIApplication application, UILocalNotification notification )
{
...
}
public override void DidReceiveRemoteNotification( UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler )
{
...
}
[Export( "userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:" )]
public void DidReceiveNotificationResponse( UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler )
{
...
}
您可能想要/需要覆盖或实现的其他方法(另请参阅上面 class AppDelegate
上声明的接口(interface));其中一些可能特定于 FCM:
ApplicationReceivedRemoteMessage
ReceivedRemoteNotification
WillPresentNotification
PerformFetch (for background notifications)
HandleAction
关于ios - 如何为 iOS 版本 9 + 10(或许还有 8)实现 Apple 推送通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41798124/