在iOS 9.3中,didReceiveRemoteNotification
方法在以下两种情况下都会被调用。
1)当收到推送通知时2)当用户通过点击通知启动应用程序时。
但是在iOS 10上,我注意到当用户通过点击通知启动应用程序时,didReceiveRemoteNotification
方法不会触发。只有在收到通知时才会调用它。因此,在通知启动应用程序后,我无法执行任何进一步操作。
应该解决这个问题的原因是什么?任何的想法?
类型转换
对于Swift3
-
样本见this
导入
UserNotifications
框架并在Appdelegate中添加UNUserNotificationCenterDelegate
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//create the notificationCenter
let center = UNUserNotificationCenter.current()
center.delegate = self
// set the type as sound or badge
center.requestAuthorization(options: [.sound,.alert,.badge, .providesAppNotificationSettings]) { (granted, error) in
// Enable or disable features based on authorization
}
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// let chars = UnsafePointer<CChar>((deviceToken as NSData).bytes)
var token = ""
for i in 0..<deviceToken.count {
//token += String(format: "%02.2hhx", arguments: [chars[i]])
token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
print("Registration succeeded!")
print("Token: ", token)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("Registration failed!")
}
使用此代表接收通知
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (_ options: UNNotificationPresentationOptions) -> Void) {
print("Handle push from foreground")
// custom code to handle push while app is in the foreground
print("\(notification.request.content.userInfo)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print("Handle push from background or closed")
// if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background
print("\(response.notification.request.content.userInfo)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) {
let navController = self.window?.rootViewController as! UINavigationController
let notificationSettingsVC = NotificationSettingsViewController()
navController.pushViewController(notificationSettingsVC, animated: true)
}
有关Apple API Reference中可以看到的更多信息
AppDelegate.h有以下几行:
步骤1
//Add Framework in your project "UserNotifications"
#import <UserNotifications/UserNotifications.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>
第2步
AppDelegate.m
// define macro
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
步骤3
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
application.applicationIconBadgeNumber = 0;
if( SYSTEM_VERSION_LESS_THAN( @"10.0" ) ) {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeprovidesAppNotificationSettings) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
//if( option != nil )
//{
// NSLog( @"registerForPushWithOptions:" );
//}
} else {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if( !error ) {
// required to get the app to do anything at all about push notifications
[[UIApplication sharedApplication] registerForRemoteNotifications];
NSLog( @"Push registration success." );
} else {
NSLog( @"Push registration FAILED" );
NSLog( @"ERROR: %@ - %@", error.localizedFailureReason, error.localizedDescription );
NSLog( @"SUGGESTIONS: %@ - %@", error.localizedRecoveryOptions, error.localizedRecoverySuggestion );
}
}];
}
return YES;
}
这将因调用registerForRemoteNotifications而触发:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
// custom stuff we do to register the device with our AWS middleman
}
然后,当用户点击通知时,会触发:
当应用程序是前景或后台但未关闭时,这将在iOS 10中触发
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void
(^)(UIBackgroundFetchResult))completionHandler
{
// iOS 10 will handle notifications through other methods
if( SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO( @"10.0" ) )
{
NSLog( @"iOS version >= 10. Let NotificationCenter handle this one." );
// set a member variable to tell the new delegate that this is background
return;
}
NSLog( @"HANDLE PUSH, didReceiveRemoteNotification: %@", userInfo );
// custom code to handle notification content
if( [UIApplication sharedApplication].applicationState == UIApplicationStateInactive )
{
NSLog( @"INACTIVE" );
completionHandler( UIBackgroundFetchResultNewData );
}
else if( [UIApplication sharedApplication].applicationState == UIApplicationStateBackground )
{
NSLog( @"BACKGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
else
{
NSLog( @"FOREGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
}
或使用
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {
}];
}
那么对于iOS 10,这两种方法:
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
NSLog( @"Handle push from foreground" );
// custom code to handle push while app is in the foreground
NSLog(@"%@", notification.request.content.userInfo);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)())completionHandler
{
NSLog( @"Handle push from background or closed" );
// if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background
NSLog(@"%@", response.notification.request.content.userInfo);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
openSettingsForNotification:(UNNotification *)notification{
Open notification settings screen in app
}
我有同样的问题。出现了通知横幅,但没有调用-application:didReceiveRemoteNotification:fetchCompletionHandler:
方法。对我有用的解决方案是添加- application:didReceiveRemoteNotification:
方法的实现并向-application:didReceiveRemoteNotification:fetchCompletionHandler:
转发调用:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result){}];
}
这是一个iOS错误。它将在iOS 10.1中修复。但是等到10月份发布10.1版本而不是实现新库并在以后删除它。
SWIFT代码:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.currentNotificationCenter()
center.delegate = self
}
// ...
return true
}
@available(iOS 10.0, *)
public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print(response.notification.request.content.userInfo)
}
@available(iOS 10.0, *)
public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print(notification.request.content.userInfo)
}
工作版iOS 11,Swift 4,Xcode 9.只需在AppDelegate中复制粘贴以下代码即可。
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10, *)
{ // iOS 10 support
//create the notificationCenter
let center = UNUserNotificationCenter.current()
center.delegate = self
// set the type as sound or badge
center.requestAuthorization(options: [.sound,.alert,.badge]) { (granted, error) in
if granted {
print("Notification Enable Successfully")
}else{
print("Some Error Occure")
}
}
application.registerForRemoteNotifications()
}
else if #available(iOS 9, *)
{
// iOS 9 support
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
else if #available(iOS 8, *)
{
// iOS 8 support
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound,
.alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
else
{ // iOS 7 support
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
return true
}
//get device token here
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: Data)
{
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Registration succeeded!")
print("Token: ", token)
//send tokens to backend server
}
//get error here
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error:
Error) {
print("Registration failed!")
}
//get Notification Here below ios 10
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
// Print notification payload data
print("Push notification received: \(data)")
}
//This is the two delegate method to get the notification in iOS 10..
//First for foreground
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (_ options:UNNotificationPresentationOptions) -> Void)
{
print("Handle push from foreground")
// custom code to handle push while app is in the foreground
print("\(notification.request.content.userInfo)")
}
//Second for background and close
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response:UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
{
print("Handle push from background or closed")
// if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background
print("\(response.notification.request.content.userInfo)")
}
}
顺便说一句,这个问题似乎在iOS 10.1中得到修复。我在10.1上测试了我的应用程序,一切正常
Swift 4和IOS 12。
虽然可能有多种原因(已经在其他答案中提到)为什么会出现这个问题,但在我个人的情况下,解决方案与发送推送通知时的有效负载有关:
您需要将json有效内容上的“content-available”键设置为1。
e.g:
{“aps”:{“alert”:“测试”,“内容可用”:1,“徽章”:1,“声音”:“默认”}}
swift 4,如果您使用的是ios 11或大于9.0的xcode版本,则必须使用UNUserNotification委托方法来调用didReceiveRemoteNotification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
//Your code to handle events
}