[iOS]Push Notification on iOS(3)

本文详细介绍了在iOS上开发推送通知的过程,包括配置推送服务、支持静默模式、通知分发流程、payload处理、服务扩展及内容扩展。讨论了不同模式下应用如何处理通知,以及在遇到问题时的解决方案和FAQ。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Develop Push Notification on iOS

Configure Push Notification Service

Support Silent Mode

Xcode | Targets | Capabilities | Background Modes | Remote Notification turn on

Development

Notification dispatch flow

1.Silent Mode

Created with Raphaël 2.2.0 收到远程Silent通知{"content-available":1} App在前台? - (void)application:didReceiveRemoteNotification:fetchCompletionHandler: 获取远程数据 弹出通知或直接显示内容 用户点击通知 App在后台? - (void)userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: 结束 - (void)userNotificationCenter:willPresentNotification:withCompletionHandler: 唤醒App yes no yes no

2.Visible Mode

Created with Raphaël 2.2.0 收到远程通知 App在后台或被Killed? 系统弹出通知 用户点击通知 - (void)userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: 结束 - (void)userNotificationCenter:willPresentNotification:withCompletionHandler: 是否弹出通知? yes no yes no

Payload

Silent Mode

{"content-available":1}

It wakes your app in the background and gives it time to initiate downloads from your server and update its content.

Important

The system treats silent notifications as low-priority. You can use them to refresh your app’s content, but the system doesn’t guarantee their delivery. In addition, the delivery of silent notifications may be throttled if the total number becomes excessive. The actual number of silent notifications allowed by the system depends on current conditions, but don’t try to send more than two or three silent notifications per hour.

{
   "aps" : {
      "content-available" : 1
   },
   "acme1" : "bar",
   "acme2" : 42
}
  • App in Background - Wake up App
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
  NSLog(@"user info %@,%s",userInfo,__FUNCTION__);
  [self sendNotificationToUI:userInfo
                         tag:[NSString stringWithFormat:@"%s",__FUNCTION__]];
  if (completionHandler) {
      UIBackgroundFetchResult result = UIBackgroundFetchResultNewData;
      completionHandler(result);
  }
}

Your app has up to 30 seconds of wall-clock time to process the notification and call the specified completion handler block

  • App in Foreground
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
  NSLog(@"user info %@,%s",userInfo,__FUNCTION__);
  [self sendNotificationToUI:userInfo
                         tag:[NSString stringWithFormat:@"%s",__FUNCTION__]];
  if (completionHandler) {
      UIBackgroundFetchResult result = UIBackgroundFetchResultNewData;
      completionHandler(result);
  }
}

Your app has up to 30 seconds of wall-clock time to process the notification and call the specified completion handler block

  • App Killed

Not to relaunch APP.

Visible Mode

  • App in Background

    Displayed to users directly.

    When user clicked the notification,the following callback invoked. (open app/dismiss/UNNotificationAction)

	- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
    
    NSLog(@"didReceiveNotificationResponse user response %@",response);
}
  • App in Foreground

Not displayed to users directly.App can display it when needed(UNNotificationPresentationOptions).

 - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
  NSLog(@"willPresentNotification notification %@",notification);
  if (completionHandler) {
      UNNotificationPresentationOptions options = UNNotificationPresentationOptionAlert;
      completionHandler(options);
  }
}

Once user clicked notification, it will also call

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
NSLog(@"didReceiveNotificationResponse user response %@",response);
}
  • App in Killed

Display notification directly, will wake up App once user clicked the notification.

PushNotificationServiceExtension

Change Push Notification before displayed before Users.

Can App have a chance to handle the notification in different mode when notification arrived?

ModeBackgroundForeground
SlientYESYES
VisibleNOYES

PushNotificationContentExtension

Customized Notification View(TBD)

Declaring Your Actionable Notification Types

FAQ

1.Remote notification support is unavailable due to error: Error Domain=NSCocoaErrorDomain Code=3000 “未找到应用程序的“aps-environment”的授权字符串”

Add “APS Environment” in entitlements file and set value to “development”

2. How to view content of mobileprovision file?

security cms -D -i MM_iOS_Development.mobileprovision

More details:
Inside Code Signing

Reference

Sample Code

//
//  AppDelegate.h
//  PushNotificationDemo


#import <UIKit/UIKit.h>

#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>

@property (strong, nonatomic) UIWindow *window;


@end


//
//  AppDelegate.m
//  PushNotificationDemo
//

#import "AppDelegate.h"

#import "UserNotification/PushNotificationHandler.h"


@interface AppDelegate ()

@property (nonatomic,strong) PushNotificationHandler *pushNotificationHandler;

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    //Push Notification
    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
    self.pushNotificationHandler = [PushNotificationHandler handler];
    [self.pushNotificationHandler application:application didFinishLaunchingWithOptions:launchOptions];
    
    return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}


- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

#pragma mark Push Notification
// Handle remote notification registration.
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    [self.pushNotificationHandler application:app didRegisterForRemoteNotificationsWithDeviceToken:devToken];
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    // The token is not currently available.
    [self.pushNotificationHandler application:app didFailToRegisterForRemoteNotificationsWithError:err];
}
#pragma mark UNUserNotificationCenterDelegate

// The method will be called on the delegate only if the application is in the foreground. If the method is not implemented or the handler is not called in a timely manner then the notification will not be presented. The application can choose to have the notification presented as a sound, badge, alert and/or in the notification list. This decision should be based on whether the information in the notification is otherwise visible to the user.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    [self.pushNotificationHandler userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];
}

// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from application:didFinishLaunchingWithOptions:.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
    [self.pushNotificationHandler userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}

// The method will be called on the delegate when the application is launched in response to the user's request to view in-app notification settings. Add UNAuthorizationOptionProvidesAppNotificationSettings as an option in requestAuthorizationWithOptions:completionHandler: to add a button to inline notification settings view and the notification settings view in Settings. The notification will be nil when opened from Settings.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification {
    [self.pushNotificationHandler userNotificationCenter:center openSettingsForNotification:notification];
}

/*! This delegate method offers an opportunity for applications with the "remote-notification" background mode to fetch appropriate new data in response to an incoming remote notification. You should call the fetchCompletionHandler as soon as you're finished performing that operation, so the system can accurately estimate its power and data cost.
 
 This method will be invoked even if the application was launched or resumed because of the remote notification. The respective delegate methods will be invoked first. Note that this behavior is in contrast to application:didReceiveRemoteNotification:, which is not called in those cases, and which will not be invoked if this method is implemented. !*/

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    [self.pushNotificationHandler application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}


@end

//
//  ViewController.h
//  PushNotificationDemo

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *infoLabel;

@property (weak, nonatomic) IBOutlet UIButton *sendButton;


@end

//
//  ViewController.m
//  PushNotificationDemo
//

#import "ViewController.h"

#import "UserNotification/PushNotificationUtils.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSString *title = NSLocalizedStringFromTable(@"SENDLOCALNOTIFICATION", @"PushNotification", nil);
    [self.sendButton setTitle:title forState:UIControlStateNormal];
  
    [self registerObservers];
}
- (void) dealloc {
    [self removeObservers];
}
- (void) registerObservers {
    __weak typeof(self) weakSelf = self;
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc]init];
    [[NSNotificationCenter defaultCenter] addObserverForName:@"PushNotificationDemo" object:nil queue:operationQueue usingBlock:^(NSNotification *note) {
        NSLog(@"%@",note.name);
        NSString *tag = [note.userInfo objectForKey:@"tag"];
        NSString *objectDescription = [note.object description];
        NSString *text = [NSString stringWithFormat:@"1.Called\n %@\n\n2.Content:\n%@",tag,objectDescription];
        dispatch_async(dispatch_get_main_queue(), ^{
            weakSelf.infoLabel.text = text;
        });
    }];
}
- (void) removeObservers {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"PushNotificationDemo" object:nil];
}
- (void)sendLocalNotification {
    [PushNotificationUtils sendLocalNotification];
}

- (IBAction)onSendLocalNotificationClicked:(UIButton *)sender {
    [self sendLocalNotification];
}


@end

//
//  PushNotificationUtils.h
//  PushNotificationDemo
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface PushNotificationUtils : NSObject

+ (void)sendLocalNotification ;

@end

NS_ASSUME_NONNULL_END

//
//  PushNotificationUtils.m
//  PushNotificationDemo
//

#import "PushNotificationUtils.h"

#import <UserNotifications/UserNotifications.h>

@implementation PushNotificationUtils

+ (void)sendLocalNotification {
    // Configure the notification's payload.
    UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
    content.title = [NSString localizedUserNotificationStringForKey:@"PUSH_TITLE" arguments:nil];
    content.body = [NSString localizedUserNotificationStringForKey:@"PUSH_BODY"
                                                         arguments:nil];
    content.sound = [UNNotificationSound defaultSound];
    
    // Deliver the notification in five seconds.
    UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
                                                  triggerWithTimeInterval:1 repeats:NO];
    UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"YOURBUNDLEID"
                                                                          content:content trigger:trigger];
    
    // Schedule the notification.
    UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];
}
@end

//
//  PushNotificationHandler.h
//  PushNotificationDemo
//

#import <Foundation/Foundation.h>
#import "AppDelegate.h"

NS_ASSUME_NONNULL_BEGIN

@interface PushNotificationHandler : NSObject
+ (instancetype) handler ;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken ;

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err ;

#pragma mark UNUserNotificationCenterDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler ;

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler ;

- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification ;

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler ;

@end

NS_ASSUME_NONNULL_END

//
//  PushNotificationHandler.m
//  PushNotificationDemo

#import "PushNotificationHandler.h"
#import "PushNotificationUtils.h"

@implementation PushNotificationHandler

+ (instancetype) handler {
    static id instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
    });
    return instance;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Configure the user interactions first.
    
    UNAuthorizationOptions options = UNAuthorizationOptionBadge
    | UNAuthorizationOptionSound
    | UNAuthorizationOptionProvidesAppNotificationSettings
    | UNAuthorizationOptionAlert;
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {
        
    }];
    // Register for remote notifications.
    [[UIApplication sharedApplication] registerForRemoteNotifications];

    return YES;
}
#pragma mark Push Notification
// Handle remote notification registration.
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    // Forward the token to your provider, using a custom method.
    //    [self enableRemoteNotificationFeatures];
    //    [self forwardTokenToServer:devTokenBytes];
    NSString * token = [[[[devToken description]
                          stringByReplacingOccurrencesOfString: @"<" withString: @""]
                         stringByReplacingOccurrencesOfString: @">" withString: @""]
                        stringByReplacingOccurrencesOfString: @" " withString: @""];
    NSLog(@"device token is %@", token);
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    // The token is not currently available.
    NSLog(@"Remote notification support is unavailable due to error: %@", err);
    //    [self disableRemoteNotificationFeatures];
}


#pragma mark UNUserNotificationCenterDelegate

// The method will be called on the delegate only if the application is in the foreground. If the method is not implemented or the handler is not called in a timely manner then the notification will not be presented. The application can choose to have the notification presented as a sound, badge, alert and/or in the notification list. This decision should be based on whether the information in the notification is otherwise visible to the user.
//Foreground
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    NSLog(@"willPresentNotification notification %@,%s",notification,__FUNCTION__);
    [self sendNotificationToUI:notification.request.content.userInfo
                           tag:[NSString stringWithFormat:@"%s",__FUNCTION__]];
    if (completionHandler) {
        UNNotificationPresentationOptions options = UNNotificationPresentationOptionAlert;
        completionHandler(options);
    }
}

// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from application:didFinishLaunchingWithOptions:.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
    [self sendNotificationToUI:response.notification.request.content.userInfo
                           tag:[NSString stringWithFormat:@"%s",__FUNCTION__]];

    NSLog(@"didReceiveNotificationResponse user response %@,%s",response,__FUNCTION__);
    if (completionHandler) {
        completionHandler();
    }
    
//    if ([response.notification.request.content.categoryIdentifier isEqualToString:@"TIMER_EXPIRED"]) {
//        // Handle the actions for the expired timer.
//        if ([response.actionIdentifier isEqualToString:@"SNOOZE_ACTION"])
//        {
//            // Invalidate the old timer and create a new one. . .
//        }
//        else if ([response.actionIdentifier isEqualToString:@"STOP_ACTION"])
//        {
//            // Invalidate the timer. . .
//        }
//        
//    }
    
    // Else handle actions for other notification types. . .
}

// The method will be called on the delegate when the application is launched in response to the user's request to view in-app notification settings. Add UNAuthorizationOptionProvidesAppNotificationSettings as an option in requestAuthorizationWithOptions:completionHandler: to add a button to inline notification settings view and the notification settings view in Settings. The notification will be nil when opened from Settings.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification {
    [self sendNotificationToUI:notification
                           tag:[NSString stringWithFormat:@"%s",__FUNCTION__]];
    NSLog(@"openSettingsForNotification %@,%s",notification,__FUNCTION__);
}

/*! This delegate method offers an opportunity for applications with the "remote-notification" background mode to fetch appropriate new data in response to an incoming remote notification. You should call the fetchCompletionHandler as soon as you're finished performing that operation, so the system can accurately estimate its power and data cost.
 
 This method will be invoked even if the application was launched or resumed because of the remote notification. The respective delegate methods will be invoked first. Note that this behavior is in contrast to application:didReceiveRemoteNotification:, which is not called in those cases, and which will not be invoked if this method is implemented. !*/

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    NSLog(@"user info %@,%s",userInfo,__FUNCTION__);
    [self sendNotificationToUI:userInfo
                           tag:[NSString stringWithFormat:@"%s",__FUNCTION__]];
    if (completionHandler) {
        UIBackgroundFetchResult result = UIBackgroundFetchResultNewData;
        completionHandler(result);
    }
     [PushNotificationUtils sendLocalNotification];
}

- (void) sendNotificationToUI:(NSObject *)object
                          tag:(NSString *)tag
{
    NSNotification *notification = [[NSNotification alloc] initWithName:@"PushNotificationDemo" object:object userInfo:@{@"Status": @"Success",@"tag":tag}];
    [[NSNotificationCenter defaultCenter] postNotification:notification];
}
@end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值