Notification Extension(Legacy)
To serve better user experience for our push notification, you can optionally add Notification service extension
in your application to display manager's avatar on push notification.
Extension Setup
In the Xcode menu bar, go to File > New > Target... and select the Notification Service Extension template from the menu that appears:
Once your extension has been created, you will see two files (or three if you're using Objective-C) within the extension folder in the Xcode Project navigator:
- NotificationService.swift, which will contain all the code and logic for your extension.
- Info.plist, which contains configuration details for your extension.
The Info.plist file contains all the information required for your extension, so the only file you should need to change is the NotificationService.swift file.
Extension Lifecycle
Once you have configured your app with a notification service extension, the following process will take place for each notification:
- App receives notification.
- System creates an instance of your extension class and launches it in the background.
- Your extension performs content edits and/or downloads some content.
- If your extension takes too long to perform its work, it will be notified and immediately terminated.
- Notification is displayed to the user.
As you can see, when using a notification service extension, you only have a limited amount of time to perform the necessary work.
Additinal Code On Podfile
Before add Extension Code, you need to add ChannelIO in Podfile
target 'your-notification-extention-target-name' do
pod 'ChannelIO'
end
Extension Code
In your NotificationService implementation file (NotificationService.m in objective-c, NotificationService.swift in Swift), you literally need to copy the code below based on your base language.
import UserNotifications
import ChannelIO
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var content: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
self.content = (request.content.mutableCopy() as? UNMutableNotificationContent)
// this line need to combine sms feature during app terminated
ChannelIO.handlePushNotification(request.content.userInfo)
if let bca = self.content {
func save(_ identifier: String, data: Data, options: [AnyHashable: Any]?) -> UNNotificationAttachment? {
let directory = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString, isDirectory: true)
do {
try FileManager.default.createDirectory(
at: directory, withIntermediateDirectories: true, attributes: nil
)
let fileURL = directory.appendingPathComponent(identifier)
try data.write(to: fileURL, options: [])
return try UNNotificationAttachment.init(
identifier: identifier, url: fileURL, options: options
)
} catch {
}
return nil
}
func exitGracefully(_ reason: String = "") {
let bca = request.content.mutableCopy() as? UNMutableNotificationContent
contentHandler(bca!)
}
guard let content = (request.content.mutableCopy() as? UNMutableNotificationContent) else {
return exitGracefully()
}
let userInfo : [AnyHashable: Any] = request.content.userInfo
guard let attachmentURL = userInfo["avatarUrl"] as? String else {
return exitGracefully()
}
guard let imageData = try? Data(contentsOf: URL(string: attachmentURL)!) else {
return exitGracefully()
}
guard let attachment = save("\(attachmentURL.hashValue).png", data: imageData, options: nil) else {
return exitGracefully()
}
content.attachments = [attachment]
contentHandler(content.copy() as! UNNotificationContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bac = self.content {
contentHandler(bac)
}
}
}
@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];
if (self.bestAttemptContent != nil) {
UNMutableNotificationContent *content = request.content.mutableCopy;
NSDictionary *userInfo = request.content.userInfo;
NSString *attachmentURL = userInfo[@"avatarUrl"];
if (attachmentURL == nil) {
return [self exitGracefully:request withContentHandler:contentHandler];
}
NSURL *url = [[NSURL alloc] initWithString:attachmentURL];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:url];
if (imageData == nil) {
return [self exitGracefully:request withContentHandler:contentHandler];
}
UNNotificationAttachment *attachment = [self save:[NSString stringWithFormat:@"%ld.png", attachmentURL.hash] data:imageData options:nil];
if (attachmentURL == nil) {
return [self exitGracefully:request withContentHandler:contentHandler];
}
content.attachments = @[attachment];
self.contentHandler(content.copy);
}
}
- (void)exitGracefully:(UNNotificationRequest* )request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
UNMutableNotificationContent *bca = request.content.mutableCopy;
contentHandler(bca);
}
- (UNNotificationAttachment *)save:(NSString *)identifier data:(NSData *)data options:(NSDictionary *)options {
NSURL *directory = [[[NSURL alloc] initFileURLWithPath:NSTemporaryDirectory() isDirectory:YES]
URLByAppendingPathComponent:NSProcessInfo.processInfo.globallyUniqueString];
NSError *error = [[NSError alloc] init];
[[NSFileManager defaultManager] createDirectoryAtURL:directory withIntermediateDirectories:YES attributes:nil error:&error];
if (error != nil) {
return nil;
}
NSURL *fileURL = [directory URLByAppendingPathComponent:identifier];
[data writeToURL:fileURL atomically:YES];
UNNotificationAttachment *ret = [UNNotificationAttachment attachmentWithIdentifier:identifier URL:fileURL options:options error:&error];
if (error != nil) {
return nil;
}
return ret;
}
- (void)serviceExtensionTimeWillExpire {
self.contentHandler(self.bestAttemptContent);
}
@end
That's it . Now when you send a message to your customers via Channel
, they will see your avatar on push notification.
Updated 4 months ago