An overview of the

Notifications in iOS include local push notifications and remote push notifications, both of which can be used to alert the user in the form of a pop-up banner that opens the app. After 10 and iOS version of the system, also support the notification extensions (UNNotificationServiceExtension, UNNotificationContentExtension), the following is to detail the iOS push notifications related functions and operations.


I. Local push notifications

Local push notification is a time-based notification triggered by a local application. It is generally used for alarm timing and to-do notification. The general procedure for sending local push notifications is as follows: (1) Register local notifications; (2) Create local notification related variables and initialize them; (3) Set the notification processing time fireDate; (4) Set notification content: notification title, notification sound, icon number, etc.; (5) Set the parameter userInfo for notification transmission. The dictionary content can be customized (optional); (6) Add this local notification to UNUserNotificationCenter.

1. Register local push notifications
- (void)sendLocalNotification {
    
    NSString *title = @"Notice - the title";
    NSString *subtitle = @"Notice - the subtitle";
    NSString *body = @"Notice - body";
    NSInteger badge = 1;
    NSInteger timeInteval = 5;
    NSDictionary *userInfo = @{@"id": @"LOCAL_NOTIFY_SCHEDULE_ID"};
    
    if(@available(iOS 10.0, *)) {// 1. Create notification content UNMutableNotificationContent * content = [[UNMutableNotificationContent alloc] init]; [contentsetValue:@(YES) forKeyPath:@"shouldAlwaysAlertWhileAppIsForeground"]; content.sound = [UNNotificationSound defaultSound]; content.title = title; content.subtitle = subtitle; content.body = body; content.badge = @(badge); content.userInfo = userInfo; // 2. Set notification attachment content NSError *error = nil; NSString *path = [[NSBundle mainBundle] pathForResource:@"logo_img_02@2x" ofType:@"png"];
        UNNotificationAttachment *att = [UNNotificationAttachment attachmentWithIdentifier:@"att1" URL:[NSURL fileURLWithPath:path] options:nil error:&error];
        if (error) {
            NSLog(@"attachment error %@", error);
        }
        content.attachments = @[att];
        content.launchImageName = @"icon_certification_status1@2x"; UNNotificationSound *sound = [UNNotificationSound soundNamed:@"sound01.wav"]; // [UNNotificationSound defaultSound]; content.sound = sound; / / 4. Trigger mode UNTimeIntervalNotificationTrigger * trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timeInteval repeats:NO]; UNNotificationRequest UNNotificationRequest * Request = [UNNotificationRequest requestWithIdentifier:LocalNotiReqIdentifer content:content trigger:trigger]; / / 6. Add the notification to the UNUserNotificationCenter, To specify the trigger point will be triggered the [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest: request withCompletionHandler:^(NSError * _Nullable error) { }]; }else {
    
        UILocalNotification *localNotification = [[UILocalNotification alloc] init]; // 1. Set the trigger time (if the trigger is triggered immediately, no need to set it)localNotification.timeZone = [NSTimeZone defaultTimeZone];
        localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:5]; // 2. Set the notification titlelocalNotification.alertBody = title; // 3. Set the title of the notification action buttonlocalNotification.alertAction = @"View"; // 4. Set the alarm soundlocalNotification.soundName = @"sound01.wav"; // UILocalNotificationDefaultSoundName; // 5. Set the userInfo for notification deliverylocalNotification.userInfo = userInfo; / / 6. The prescribed date trigger notifications [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; / / 7. Immediately trigger a notification / / [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification]; }}Copy the code
2. Disable the local push notification
- (void)cancelLocalNotificaitons {// cancelLocalNotificaitons = [UIApplication sharedApplication] scheduledLocalNotifications]; // Get all current local notificationsif(! notificaitons || notificaitons.count <= 0) {return; }
    for (UILocalNotification *notify in notificaitons) {
        if ([[notify.userInfo objectForKey:@"id"] isEqualToString:@"LOCAL_NOTIFY_SCHEDULE_ID"]) {
            if(@ the available (iOS 10.0, *)) { [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[LocalNotiReqIdentifer]]; }else {
                [[UIApplication sharedApplication] cancelLocalNotification:notify];
            }
            break; }} / / cancel all local notification / / [[UIApplication sharedApplication] cancelAllLocalNotifications]; }Copy the code
3. Callback methods in AppDelegate

In the code above we set userInfo, and when you receive and click on a notification in iOS, it will automatically open the app. However, the callback methods vary with iOS versions as follows:

  • System version < iOS 10
// If the App has completely exited:  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; // When the App has completely exited, the procedure for obtaining the userInfo parameter is as follows:  // NSDictionary *userInfoLocal = (NSDictionary *)[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; // NSDictionary *userInfoRemote = (NSDictionary *)[launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; / / if the App is still in operation (the foreground or background) - (void) application: (UIApplication *) application didReceiveLocalNotification: (UILocalNotification *)notification;Copy the code
  • OS version >= iOS 10
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#pragma mark - UNUserNotificationCenterDelegate- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification WithCompletionHandler (void (^) (UNNotificationPresentationOptions options)) completionHandler __IOS_AVAILABLE (10.0) __WATCHOS_AVAILABLE __TVOS_AVAILABLE (10.0) (3.0); - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *) response withCompletionHandler (void (^) (void)) completionHandler __IOS_AVAILABLE __WATCHOS_AVAILABLE (10.0) (3.0) __TVOS_PROHIBITED;#endif
Copy the code
4. Achieve results
  • Prompt popup window for app to request push notification permission to user:

  • Effect of notification pop-up when APP is in different states (foreground, background, lock screen) :

PS:

  • When the user refuses to authorize push notifications,appUnable to receive notifications; Users can go to Settings -> Notifications -> Correspondingapp, manually set notification options)
  • The sound of the notification is specified in the code, played by the system, and the duration must be within30sIn, otherwise will be replaced by the default sound, and custom sound files must be placedmain bundleIn the.
  • The number of local notifications is limited. If the number of local notifications exceeds 64, the system will ignore them. (Data is obtained from the network, and the specific interval needs to be verified.)




2. Remote push notifications

Remote Push notifications are sent to apps through Apple Push Notification Service (APNs), and APNs must first know the device token of the user’s device. On startup, the App communicates with APNs and receives a Device token, which is then forwarded to the App Server, which sends the token and the notification message to be sent to APNs. PS: Apple official website APNs overview

The delivery of remote push notifications involves several key components:

  • App Server
  • Apple Push Notification Service (APNs)
  • User’s device (iPhone, iPad, iTouch, Mac, etc.)
  • The corresponding app

The official apple remote push notification delivery diagram is as follows:

Interaction details between key components:

  • In order to enable Push Notifications, it is necessary to configure the right Notifications certificate and permissions as follows: 1) Create the same App ID in Apple Developer platform according to the Bundle Identifier of the project, and check Push Notifications service. 2) Set Push Notifications to ON in the Capabilities TAB of the project; 3) Remote push must use real machine debugging, because emulator cannot obtain device token.

  • After setting certificates and permissions, follow the following steps to develop the remote push function:

1. Register remote notification
/ / version of the iOS 8 or more remote push notifications registered - (void) registerRemoteNotifications {if(@ the available (iOS 10.0. *)) {UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) {if(! error) { NSLog(@"request authorization succeeded!");
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            } else {
                NSLog(@"request authorization failed!"); }}]; }else{ UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; }}Copy the code
2. The App obtains the device token
  • After registering for remote notificationsdevice tokenThe callback method of
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
Copy the code
  • To obtaindevice tokenFailed callback methods:
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
Copy the code
3. The app sends the Device token to the App Server

Only Apple knows the generating algorithm of device Token, which is guaranteed to be unique. The Device Token will change after the APP is uninstalled and reinstalled. Therefore, in order to ensure that the APP can still normally receive notifications sent by the server after the change of Device Token, You are advised to send the obtained Device token to the App Server every time you start the application.

4. The App Server sends the Device token and the message to be pushed to APNs

When sending the specified device token and message content to APNs, the message content must be organized according to apple’s official message format. PS: remote notification message field, create remote notification message

Message format: {” aps “: {” alert” : {” title “:” notice the title “, “the subtitle” : “inform the subtitle”, “body” : “notice body”, “the title – loc – key” : “TITLE_LOC_KEY”, “the title – lo c-args”:[“t_01″,”t_02″],”loc-key”:”LOC_KEY”,”loc-args”:[“l_01″,”l_02″]},”sound”:”sound01.wav”,”badge”:1,”mutable-content “:1,”category”: “realtime”},”msgid”:”123″}

5. APNs searches for the corresponding device based on the device token and pushes the message

In general, APNs can successfully push the message to the corresponding device based on deviceToken. However, in some cases, the user uninstalls the program, causing the message push failure. In this case, the App Server will receive the error message returned by APNs.

6. Callback methods in AppDelegate
/ / iOS < 10, And the app is completely kill - (BOOL) application: (UIApplication *) application didFinishLaunchingWithOptions (launchOptions NSDictionary *); / / note: If you don't use UNUserNotificationCenter for iOS10 or higher, Will take the callback method - (void) application: (UIApplication *) application didReceiveRemoteNotification: (the userInfo NSDictionary *); / / support iOS7 and above system - (void) application: (UIApplication *) application didReceiveRemoteNotification: (the userInfo NSDictionary *) fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler; // iOS>=10: App gets notification in foreground - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler; // iOS>=10: Trigger (kill/cut to background arousal) - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler;Copy the code

The complete code to register a remote push notification in the AppDelegate and parse the notification data is as follows:

#import "AppDelegate.h"
#import "ViewController.h"

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#import <UserNotifications/UserNotifications.h>
#endif

@interface AppDelegate () <UNUserNotificationCenterDelegate>

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   
    ViewController *controller = [[ViewController alloc] init];
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:controller];
    _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    [_window setRootViewController:nav]; [_window makeKeyAndVisible]; / / / / registered local push notification (specific operation in the ViewController) / / [self registerLocalNotification]; / / registered remote push notification [self registerRemoteNotifications];return YES;
}

- (void)registerLocalNotification {

    if(@ the available (iOS 10.0. *)) {UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {if(! error) { NSLog(@"request authorization succeeded!"); }}]; }else {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    }
}


- (void)registerRemoteNotifications
{
    if(@ the available (iOS 10.0. *)) {UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) {if(! error) { NSLog(@"request authorization succeeded!");
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            } else {
                NSLog(@"request authorization failed!"); }}]; }else {
        UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    }
}


- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    
    NSLog(@"didRegisterUserNotificationSettings");
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    
    NSLog(@"App to receive push local (didReceiveLocalNotification:) : % @", notification.userInfo); } - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData NSString *token = [[deviceToken Description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"< >"]];
    token = [token stringByReplacingOccurrencesOfString:@"" withString:@""];
    NSLog(@"DeviceToken:%@\n", token);
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    
    NSLog(@"didFailToRegisterForRemoteNotificationsWithError: %@", error.description); } / / note: If you don't use UNUserNotificationCenter for iOS10 or higher, Will take the callback method - (void) application: (UIApplication *) application didReceiveRemoteNotification: (the userInfo NSDictionary *) {/ / IOS6 or the following operating systemsif (userInfo) {
        if([UIApplication sharedApplication]. ApplicationState == UIApplicationStateActive) {// App at the foreground notifies NSLog(@"App is located at the front desk to inform (didReceiveRemoteNotification:) : % @", userInfo);
        } else{// Cut to background to call up NSLog(@"App in background notice (didReceiveRemoteNotification:) : % @", userInfo); } } } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo FetchCompletionHandler :(void (^)(UIBackgroundFetchResult))completionHandler NS_AVAILABLE_IOS(7_0) {// iOS7 and laterif (userInfo) {
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
            NSLog(@"App is located at the front desk to inform (didReceiveRemoteNotification: fetchCompletionHandler:) : % @", userInfo);
        } else {
            NSLog(@"App in background notice (didReceiveRemoteNotification: fetchCompletionHandler:) : % @", userInfo);
        }
    }
    completionHandler(UIBackgroundFetchResultNewData);
}


Received a push message in #pragma mark - iOS>=10

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification WithCompletionHandler (void (^) (UNNotificationPresentationOptions)) completionHandler API_AVAILABLE (ios (10.0)) { NSDictionary * userInfo = notification.request.content.userInfo;if (userInfo) {
        NSLog(@"App at foreground (willPresentNotification:):%@", userInfo);
    }
    completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
API_AVAILABLE(ios(10.0)){
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    if (userInfo) {
        NSLog(@"Click on the notification into the App trigger (didReceiveNotificationResponse:) : % @", userInfo);
    }
    completionHandler();
}

#endif


@end
Copy the code
7. Use the Pusher tool to simulate App Server push notifications

Pusher, like SmartPush, is an excellent remote push test tool. Its interface is as follows:

  • Instructions for using Pusher:

    1) to selectp12Push certificate in format;

    2) Set whether to test environment (test environment is selected by default, because push certificate is divided into test certificate and production certificate, and Apple’sAPNsAlso divided into test and production two sets of environment, thereforePusherNeed to manually check push environment);

    3) inputdevice token;

    4) Enter the format required by AppleapsThe string;

    5) Perform push.

The effect is as follows:

json

PS:

  • To use the remote push notification function, you need to launch the app at least once;
  • Remote push notifications cannot be registered if the device is not connected to the network.
  • Push the APS string in place during the processAdd a custom field, the message upper limit is4 KB.




3. IOS notification extension

Push notifications in iOS 10 and beyond are extended in two ways:

  • Notification service extension (UNNotificationServiceExtension), which is before the show and after receipt of the notice, notify allows developers to do some things, such as adding attachments, load network requests, etc. Click on the official documentation
  • Notice content extension (UNNotificationContentExtension), is shown in the notice of a custom user interface. Click on the official documentation
1. Create UNNotificationServiceExtension and UNNotificationContentExtension:

Note:

  • Target Supports iOS 10.0 or later, and the current system supports target.
2. UNNotificationServiceExtension notification service extension

In the notificationService. m file, there are two callback methods:

// When the system is notified, Here have up to 30 seconds to rewrite the notification content (e.g., download the attachment and update notification) - (void) didReceiveNotificationRequest (UNNotificationRequest *) request withContentHandler:(void (^)(UNNotificationContent *contentToDeliver))contentHandler; / / processing timeout, then receive notification directly display - (void) serviceExtensionTimeWillExpire;Copy the code

Load the network request in the notification service extension as follows:

#import "NotificationService.h"
#import <AVFoundation/AVFoundation.h>

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    //// Modify the notification content here...
    self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [ServiceExtension modified]", self.bestAttemptContent.title]; UNNotificationAction UNNotificationAction * actionA =[UNNotificationAction actionWithIdentifier:@"ActionA" title:@"A_Required" options:UNNotificationActionOptionAuthenticationRequired];
    UNNotificationAction * actionB = [UNNotificationAction actionWithIdentifier:@"ActionB" title:@"B_Destructive" options:UNNotificationActionOptionDestructive];
    UNNotificationAction * actionC = [UNNotificationAction actionWithIdentifier:@"ActionC" title:@"C_Foreground" options:UNNotificationActionOptionForeground];
    UNTextInputNotificationAction * actionD = [UNTextInputNotificationAction actionWithIdentifier:@"ActionD"
                                                                                            title:@"D_InputDestructive"
                                                                                          options:UNNotificationActionOptionDestructive
                                                                             textInputButtonTitle:@"Send"
                                                                             textInputPlaceholder:@"input some words here ..."];
    NSArray *actionArr = [[NSArray alloc] initWithObjects:actionA, actionB, actionC, actionD, nil];
    NSArray *identifierArr = [[NSArray alloc] initWithObjects:@"ActionA"The @"ActionB"The @"ActionC"The @"ActionD", nil];
    UNNotificationCategory * notficationCategory = [UNNotificationCategory categoryWithIdentifier:@"QiShareCategoryIdentifier"
                                                                                          actions:actionArr
                                                                                intentIdentifiers:identifierArr
                                                                                          options:UNNotificationCategoryOptionCustomDismissAction];
    [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:notficationCategory]]; / / set categoryIdentifier self. BestAttemptContent. CategoryIdentifier = @"QiShareCategoryIdentifier"; / / load network request NSDictionary. * the userInfo = self bestAttemptContent. The userInfo; NSString *mediaUrl = userInfo[@"media"] [@"url"];
    NSString *mediaType = userInfo[@"media"] [@"type"];
    if(! mediaUrl.length) { self.contentHandler(self.bestAttemptContent); }else {
        [self loadAttachmentForUrlString:mediaUrl withType:mediaType completionHandle:^(UNNotificationAttachment *attach) {
            
            if (attach) {
                self.bestAttemptContent.attachments = [NSArray arrayWithObject:attach];
            }
            self.contentHandler(self.bestAttemptContent);
        }];
    }
}

- (void)loadAttachmentForUrlString:(NSString *)urlStr withType:(NSString *)type completionHandle:(void(^)(UNNotificationAttachment *attach))completionHandler
{
    __block UNNotificationAttachment *attachment = nil;
    NSURL *attachmentURL = [NSURL URLWithString:urlStr];
    NSString *fileExt = [self getfileExtWithMediaType:type]; NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];  [[session downloadTaskWithURL:attachmentURL completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {if (error) {
            NSLog(@"Failed to load multimedia %@", error.localizedDescription);
        } else {
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:fileExt]];
            [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error]; / / custom push UI need NSMutableDictionary * dict = [self. BestAttemptContent. The userInfo mutableCopy]; [dictsetObject:[NSData dataWithContentsOfURL:localURL] forKey:@"image"];
            self.bestAttemptContent.userInfo = dict;
            
            NSError *attachmentError = nil;
            attachment = [UNNotificationAttachment attachmentWithIdentifier:@"QiShareCategoryIdentifier" URL:localURL options:nil error:&attachmentError];
            if (attachmentError) {
                NSLog(@"% @", attachmentError.localizedDescription);
            }
        }
        completionHandler(attachment);
    }] resume];
}

- (NSString *)getfileExtWithMediaType:(NSString *)mediaType {
    NSString *fileExt = mediaType;
    if ([mediaType isEqualToString:@"image"]) {
        fileExt = @"jpg";
    }
    if ([mediaType isEqualToString:@"video"]) {
        fileExt = @"mp4";
    }
    if ([mediaType isEqualToString:@"audio"]) {
        fileExt = @"mp3";
    }
    return [@"." stringByAppendingString:fileExt];
}

- (void)serviceExtensionTimeWillExpire {
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    self.contentHandler(self.bestAttemptContent);
}

@end
Copy the code

Message format :{” aps”:{“alert”:{“title”:” title…” ,”subtitle”:”Subtitle…” ,”body”:”Body…” },”sound”:”default”,”badge”: 1,”mutable-content”: 1,”category”: “QiShareCategoryIdentifier,”}, “msgid” : “123”, “media” : {” type “:” image “, “url” : “www.fotor.com/images2/fea…” }}

PS:

  • The maximum time for loading and processing attachments is 30 seconds. Otherwise, the notification will be displayed in the default format.
  • The URL of the UNNotificationAttachment accepts the URL of the local file;
  • When the server processes the push content, it is better to add the media type field;
  • Set the mutable content field in the APS string to 1.
  • To debug NotificationService, select The target of compiling and running as NotificationService in the top bar of Xcode; otherwise, real-time debugging cannot be performed.
3. Inform UNNotificationContentExtension content extension

Inform the content extension interface NotificationViewController structure is as follows:

  • Set actions: inherited directly from NotificationViewController ViewController, so you can rewrite the relevant methods in this class, to modify the relevant layout and style of the interface. Before the interface is expanded, the user can interact with the corresponding push notification through the UNNotificationAction, but the user cannot interact directly with the notification content extension interface.
  • Set the category: The category field in the push notification content, and UNNotificationContentExtension info. In the plist UNNotificationExtensionCategory field values to match, system to find the custom UI.

Set the category field directly in the APS string, for example :{” APS “:{“alert”:”Testing… (0)”,”badge”:1,”sound”:”default”,”category”:”QiShareCategoryIdentifier”}}

Set the category value in notificationService.m as follows:

self.bestAttemptContent.categoryIdentifier = @"QiShareCategoryIdentifier";
Copy the code

The configuration of the category in info.plist is as follows:

  • UNNotificationContentExtension protocol: NotificationViewController generated in the default implementation.

The simple English notes are clear:

// This will be called to send the notification to be displayed by // the extension. If the extension is being displayed  and more related // notifications arrive (eg. more messagesfor the same conversation)
// the same method will be called forEach new notification. - (void)didReceiveNotification:(UNNotification *)notification; // If implemented, the method will be called when the user taps on one // of the notification actions. The completion handler can be called  // after handling the action to dismiss the notification and forward the // action to the appif necessary.
- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion

// Called when the user taps the play or pause button.
- (void)mediaPlay;
- (void)mediaPause;
Copy the code
  • UNNotificationAttachment: Attachment support audio 1) 5 m (kUTTypeWaveformAudio/kUTTypeMP3 / kUTTypeMPEG4Audio/kUTTypeAudioInterchangeFileFormat) 2) image 10 m (kUTTypeJPEG/kUTTypeGIF/kUTTypePNG) 3) video 50 m (kUTTypeMPEG/kUTTypeMPEG2Video/kUTTypeMPEG4 / kUTTypeAVIMovie)
4. When the user-defined content extension interface is used in combination with the content extension function, the code is as follows:
#import "NotificationViewController.h"
#import <UserNotifications/UserNotifications.h>
#import <UserNotificationsUI/UserNotificationsUI.h>

#define Margin 15

@interface NotificationViewController () <UNNotificationContentExtension>

@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UILabel *subLabel;
@property (nonatomic, strong) UIImageView *imageView;

@property (nonatomic, strong) UILabel *hintLabel;

@end

@implementation NotificationViewController

- (void)viewDidLoad {

    [super viewDidLoad];
    
    CGPoint origin = self.view.frame.origin;
    CGSize size = self.view.frame.size;
    
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(Margin, Margin, size.width-Margin*2, 30)];
    self.label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [self.view addSubview:self.label];
    
    self.subLabel = [[UILabel alloc] initWithFrame:CGRectMake(Margin, CGRectGetMaxY(self.label.frame)+10, size.width-Margin*2, 30)];
    self.subLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [self.view addSubview:self.subLabel];
    
    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(Margin, CGRectGetMaxY(self.subLabel.frame)+10, 100, 100)];
    [self.view addSubview:self.imageView];
    
    self.hintLabel = [[UILabel alloc] initWithFrame:CGRectMake(Margin, CGRectGetMaxY(self.imageView.frame)+10, size.width-Margin*2, 20)];
    [self.hintLabel setText:@"I am hintLabel"];
    [self.hintLabel setFont:[UIFont systemFontOfSize:14]];
    [self.hintLabel setTextAlignment:NSTextAlignmentLeft]; [self.view addSubview:self.hintLabel]; self.view.frame = CGRectMake(origin.x, origin.y, size.width, CGRectGetMaxY(self.imageView.frame)+Margin); // Sets the border color of the control [self.label.layer]setBorderColor:[UIColor redColor].CGColor];
    [self.label.layer setBorderWidth: 1.0]; [self.subLabel.layersetBorderColor:[UIColor greenColor].CGColor];
    [self.subLabel.layer setBorderWidth: 1.0]; [self.imageView.layersetBorderWidth: 2.0]; [self.imageView.layersetBorderColor:[UIColor blueColor].CGColor];
    [self.view.layer setBorderWidth: 2.0]; [self.view.layersetBorderColor:[UIColor cyanColor].CGColor];
}

- (void)didReceiveNotification:(UNNotification *)notification {
    
    self.label.text = notification.request.content.title;
    self.subLabel.text = [NSString stringWithFormat:@"%@ [ContentExtension modified]", notification.request.content.subtitle];
    
    NSData *data = notification.request.content.userInfo[@"image"];
    UIImage *image = [UIImage imageWithData:data];
    [self.imageView setImage:image];
}

- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion {
    
    [self.hintLabel setText:[NSString stringWithFormat:@"Triggered %@", response.actionIdentifier]];
    if ([response.actionIdentifier isEqualToString:@"ActionA"]) {dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ completion(UNNotificationContentExtensionResponseOptionDismiss); }); }else if ([response.actionIdentifier isEqualToString:@"ActionB"]) {}else if ([response.actionIdentifier isEqualToString:@"ActionC"]) {}else if ([response.actionIdentifier isEqualToString:@"ActionD"]) {}else {
        completion(UNNotificationContentExtensionResponseOptionDismiss);
    }
    completion(UNNotificationContentExtensionResponseOptionDoNotDismiss);
}

@end
Copy the code





Description:

  • The system version supported by the service extension target and content extension target must be iOS10 or later.
  • Custom views can be set through the size of the NotificationViewController preferredContentSize size to control, but the user experience is somewhat abrupt, Can be set through the info. In the plist UNNotificationExtensionInitialContentSizeRatio attribute’s value to optimize;
  • ContentExtension info. In the plist NSExtension NSExtensionAttributes under field can be configured in the following attribute’s value, UNNotificationExtensionCategory: Represents a category that can be recognized by a custom content mask. It can be an array or you can bind multiple notifications to the content. UNNotificationExtensionInitialContentSizeRatio: ratio of high to width of the default UI interface; UNNotificationExtensionDefaultContentHidden: whether the default title bar display system and content, optional parameters; UNNotificationExtensionOverridesDefaultTitle: whether to let the system USES the title of the message as the title of the notification, optional parameters.
  • There are five Settings for identifiers when handling notification content extensions (UNNotificationAction, UNNotificationCategory, bestAttemptContent, info.pl in contentExtension) Ist, APS string), please distinguish the functions of different identifiers.
  • The two extensions are used together. Select the current target in XCode to see the corresponding log information at the break point.

Project source: github.com/QiShare/QiN…