Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
  1. In XCode, Go to File -> New -> Target -> Notification Service Extension

    Image Modified

  2. Create Notification Service Extension. Name your extension as NotificationService (You may choose a different name which will be referred to as Notification Service Target (name) in the subsequent sections).

    Image Modified

     

  3. Click Activate to finish.

  4. At the end of this step, three new files will be created under NotificationService directory named:

    1. NotificationService.h

    2. NotificationService.m

    3. info.plist

  5. Open this up and you’ll see a couple of delegate methods – one for receiving a notification request and one for handling the expiration of the service extension. We’ll be focusing on the first one, didReceiveRequestWithContentHandler.

  6. The code in this method should look like this:
     

    NotificationService.m

    Code Block
    languageobjective-c
    - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
           self.contentHandler = contentHandler;
           self.bestAttemptContent = [request.content mutableCopy];
           //categories
          [[UNUserNotificationCenter currentNotificationCenter] getNotificationCategoriesWithCompletionHandler:^(NSSet<UNNotificationCategory *> * _Nonnull categories) {
              NSString * categoryIdentifier =self.bestAttemptContent.categoryIdentifier;
              NSDictionary* lc = request.content.userInfo[@"aps"];
              if (categoryIdentifier && lc) {
                  self.bestAttemptContent.categoryIdentifier = [NSString stringWithFormat:@"%@_%@", categoryIdentifier, lc[@"lc"]];
              }
              NSMutableSet* set = [[categories objectsPassingTest:^BOOL(UNNotificationCategory * _Nonnull obj, BOOL * _Nonnull stop) {
                  return [obj.identifier isEqualToString:self.bestAttemptContent.categoryIdentifier];
              }] mutableCopy] ;
              if ([set count] == 0) {
                  self.bestAttemptContent.categoryIdentifier = [NSString stringWithFormat:@"%@_%@", categoryIdentifier, @"en"];
              }
          }];
           NSString *urlString = request.content.userInfo[@"ios_apx_media"];
           [self loadAttachmentForUrlString:urlString
                          completionHandler:^(UNNotificationAttachment *attachment) {
                              if (attachment) {
                                  self.bestAttemptContent.attachments = [NSArray arrayWithObject:attachment];
                              }
                              self.contentHandler(self.bestAttemptContent);
                          }];
    }
    - (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);
    }
    - (void)loadAttachmentForUrlString:(NSString *)urlString completionHandler:(void(^)(UNNotificationAttachment *))completionHandler  {
       __block UNNotificationAttachment *attachment = nil;
       NSURL *attachmentURL = [NSURL URLWithString:urlString];
      [[[NSURLSession sharedSession] downloadTaskWithURL:attachmentURL completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error != nil) {
            NSLog(@"%@", error.localizedDescription);
        } else {
          NSString *dir = NSTemporaryDirectory();
          NSString *tempFile = [NSString stringWithFormat:@"%@%@%@", @"file://", dir, [attachmentURL lastPathComponent]];
          NSURL *tmpUrl = [NSURL URLWithString:tempFile];
          NSFileManager *fileManager = [NSFileManager defaultManager];
          [fileManager moveItemAtURL:location toURL:tmpUrl error:&error];
          NSError *attachmentError = nil;
          attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:tmpUrl options:nil error:&attachmentError];
          if (attachmentError) {
            NSLog(@"%@", attachmentError.localizedDescription);
          }
        }
        completionHandler(attachment);
      }] resume];
    }



    NotificationService.swift

    Code Block
    languageswift
    var contentHandler: ((UNNotificationContent) -> Void)?
        var bestAttemptContent: UNMutableNotificationContent?
        
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
            self.contentHandler = contentHandler
            bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
            
            UNUserNotificationCenter.current().getNotificationCategories { (categories) in
                
                if let categoryIdentifier = self.bestAttemptContent?.categoryIdentifier, let lc = request.content.userInfo["aps"] {
                    self.bestAttemptContent?.categoryIdentifier = categoryIdentifier + "_" + ((lc as! NSDictionary)["lc"] as! String)
                    let categoryExistArray = categories.filter { (category) -> Bool in
                        category.identifier == self.bestAttemptContent?.categoryIdentifier
                    }
                    if categoryExistArray.isEmpty {
                        self.bestAttemptContent?.categoryIdentifier = categoryIdentifier + "_en"
                    }
                }
                
                if let urlString = request.content.userInfo["ios_apx_media"], let fileUrl = URL(string: urlString as? String ?? "") {
                    // Download the attachment
                    URLSession.shared.downloadTask(with: fileUrl ) { (location, response, error) in
                        if let location = location {
                            // Move temporary file to remove .tmp extension
                            let tmpDirectory = NSTemporaryDirectory()
                            let tmpFile = "file://".appending(tmpDirectory).appending(fileUrl.lastPathComponent)
                            let tmpUrl = URL(string: tmpFile)!
                            try! FileManager.default.moveItem(at: location, to: tmpUrl)
                            // Add the attachment to the notification content
                            if let attachment = try? UNNotificationAttachment(identifier: "", url: tmpUrl) {
                                self.bestAttemptContent?.attachments = [attachment]
                            }
                        }
                        
                        // Serve the notification content
                        self.contentHandler!(self.bestAttemptContent!)
                        }.resume()
                } else {
                    self.contentHandler!(self.bestAttemptContent!)
                }
            }
        }
        
        override func 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.
            if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
                contentHandler(bestAttemptContent)
            }
        }


    Note: The push payload has a field "ios_apx_media" which contains the url of the media and the URLSession downloads the media to temporary storage and appends a .tmp file extension, which we need to remove so that the application can infer the file type and display it. So, to do this we need to move the file to the application’s local File Manager and that’s it – our media is ready to be attached to the notification content, and served to the user.

    This is all the code needed in your Xcode project to display rich notifications in your application.

    Now, you just need to make a few adjustments to the server that triggers Push Notifications to your application using our API.

  7. To send the rich pushes we can use Appoxee front end and pass the link as a key to the notification.

    Image Modified

  8. Once notification is sent we will receive it like the example below 

    Image Modified

As shown in the figure above, you can now send images, videos, audio, and GIFs in your iOS 10 Push Notifications! Simply change the URL to point to another media file and the extension should then be able to handle other media types. 

...