iOS 10 now allows Developers to modify the push payload before it is presented. To do that you need to create an new Application Extension called "Notification Service Extension".
1. Application Extension - Notification Service Extension
To create a new application extension select in xCode File -> New -> Target... and select Notification Service Extension.
The App Extension must have it's own App ID and Provisioning Profile set up in the Apple Developer Center.
2. Configuring the Notification Service Extension
After creating the new App Extension you should have a new header file, objective-c file and plist. This is the default code that will work with Pulsate.
#import "NotificationService.h"
static NSString* const PulsateAttachmentUrl = @"au";
static NSString* const PulsateAttachmentType = @"at";
@interface NotificationService ()
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@property (nonatomic, strong) UNMutableNotificationContent *notificationContent;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
self.notificationContent = [request.content mutableCopy];
if (request.content.userInfo == nil) {
[self defaultPushHandler];
return;
}
if (request.content.userInfo[PulsateAttachmentType] == nil || request.content.userInfo[PulsateAttachmentUrl] == nil) {
[self defaultPushHandler];
return;
}
NSString* pulsateAttachment = request.content.userInfo[PulsateAttachmentUrl];
NSString* pulsateAttachmentType = request.content.userInfo[PulsateAttachmentType];
NSString *suffix = [@"." stringByAppendingString:pulsateAttachmentType];
NSURL *pulsateAttachmentUrl = [NSURL URLWithString:pulsateAttachment];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session downloadTaskWithURL:pulsateAttachmentUrl
completionHandler:^(NSURL *url, NSURLResponse *response, NSError *error) {
if (error != nil) {
[self defaultPushHandler];
return;
} else {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *typedUrl = [NSURL fileURLWithPath:[url.path stringByAppendingString:suffix]];
[fileManager moveItemAtURL:url toURL:typedUrl error:&error];
NSError *error = nil;
UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:typedUrl options:nil error:&error];
if (attachment == nil) {
[self defaultPushHandler];
return;
}
self.bestAttemptContent.attachments = [NSArray arrayWithObjects:attachment, nil] ;
self.contentHandler(self.bestAttemptContent);
}
}] resume];
}
- (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)defaultPushHandler {
self.contentHandler(self.bestAttemptContent);
}
@end
import UserNotifications
private let PulsateAttachmentUrl = "au"
private let PulsateAttachmentType = "at"
class NotificationService: UNNotificationServiceExtension {
private var contentHandler: ((UNNotificationContent) -> Void)?
private var bestAttemptContent: UNMutableNotificationContent?
private var notificationContent: UNMutableNotificationContent?
func defaultPushHandler() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
notificationContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if request.content.userInfo[PulsateAttachmentType] == nil || request.content.userInfo[PulsateAttachmentUrl] == nil {
defaultPushHandler()
return
}
let pulsateAttachment = request.content.userInfo[PulsateAttachmentUrl] as? String
let pulsateAttachmentType = request.content.userInfo[PulsateAttachmentType] as? String
let suffix = "." + (pulsateAttachmentType ?? "")
let pulsateAttachmentUrl = URL(string: pulsateAttachment ?? "")
do {
let session = URLSession(configuration: URLSessionConfiguration.default)
session.downloadTask(with: pulsateAttachmentUrl!, completionHandler: { location, response, error in
if error != nil {
self.defaultPushHandler()
return
} else {
let fileManager = FileManager.default
let typedUrl = URL(fileURLWithPath: location!.path + (suffix))
try? fileManager.moveItem(at: location!, to: typedUrl)
let attachment = try? UNNotificationAttachment(identifier: "", url: typedUrl, options: nil)
if attachment == nil {
self.defaultPushHandler()
return
}
self.bestAttemptContent!.attachments = [attachment] as! [UNNotificationAttachment]
self.contentHandler!(self.bestAttemptContent!)
}
}).resume()
}
}
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)
}
}
}