IOS Rich notification didReceiveNotificationRequest is not fired

3.7k views Asked by At

I'm developing an iPhone application using objective-c. The basic push notification is working properly. Now I want to add rich notification in my app but I cannot get the didReceiveNotificationRequest fired in the NotificationService.

Here is the notification payload I receive on Appdelegate:

Notification Payload(see mutable-content is set to 1)

https://image.ibb.co/ndA2Qo/grab.png

Here is the NotificationService.m file;

#import "NotificationService.h"
#import "Common.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];
NSLog(@"didReceiveNotificationRequest");
// Modify the notification content here...
// load the attachment
NSDictionary *userInfo = request.content.userInfo;
NSString *imageURL = [userInfo valueForKey:@"thumbnail_image"];
NSArray *parts = [imageURL componentsSeparatedByString:@"."];
NSString *extension = [parts lastObject];
[self loadAttachmentForUrlString:imageURL
                        withExtension:extension
               completionHandler:^(UNNotificationAttachment *attachment) {
                   if (attachment) {
                       self.bestAttemptContent.attachments = [NSArray arrayWithObject:attachment];
                   }
                   //self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];

                   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 withExtension:(NSString *)extension completionHandler:(void(^)(UNNotificationAttachment *))completionHandler  {

__block UNNotificationAttachment *attachment = nil;
NSURL *attachmentURL = [NSURL URLWithString:urlString];

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session downloadTaskWithURL:attachmentURL
            completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
                if (error != nil) {
                    NSLog(@"%@", error.localizedDescription);
                } else {
                    NSFileManager *fileManager = [NSFileManager defaultManager];
                    NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:extension]];
                    [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];

                    NSError *attachmentError = nil;
                    attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:localURL options:nil error:&attachmentError];
                    if (attachmentError) {
                        NSLog(@"%@", attachmentError.localizedDescription);
                    }
                }
                completionHandler(attachment);
            }] resume];
}

@end

What am I missing?

Please advice,

Semih

2

There are 2 answers

4
manishsharma93 On BEST ANSWER

You are downloading the image in background thread which is causing the issue in Rich Push Notification case. If you want you can try with this framework

Also Add "content-available":1 in your aps

OR you can try downloading like this,

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent *))contentHandler {

    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];

    self.bestAttemptContent.title = [NSString stringWithFormat:@"%@",request.content.title];
    self.bestAttemptContent.body = [NSString stringWithFormat:@"%@",request.content.body];

    NSString *attachmentUrlString = [NSString stringWithFormat:@"%@",[request.content.userInfo valueForKey:@"thumbnail_image"]];

    if (![attachmentUrlString isKindOfClass:[NSString class]]) {
        [self failEarly];
        return;
    }

    NSURL *url = [NSURL URLWithString:attachmentUrlString];
    if (!url) {
        [self failEarly];
        return;
    }

    NSData *data = [NSData dataWithContentsOfURL:url];
    if (!data) {
        [self failEarly];
        return;
    }

    NSString *identifierName = [self getIdentifierName:attachmentUrlString];
    NSString *tmpSubFolderName = [[NSProcessInfo processInfo] globallyUniqueString];

    self.bestAttemptContent.attachments = [NSArray arrayWithObject:[self create:identifierName andData:data withOptions:nil andTmpFolderName:tmpSubFolderName]] ;
    self.contentHandler(self.bestAttemptContent);

}

-(void)failEarly {
    self.contentHandler(self.bestAttemptContent);
}

-(NSString *)getIdentifierName:(NSString *)fileURL
{
    NSString *identifierName = @"image.jpg";

    if (fileURL) {
        identifierName = [NSString stringWithFormat:@"file.%@",fileURL.lastPathComponent];
    }

    return identifierName;
}

-(UNNotificationAttachment *)create:(NSString *)identifier andData:(NSData *)data withOptions:(NSDictionary *)options andTmpFolderName:(NSString *)tmpSubFolderName {

    NSString *fileURLPath = NSTemporaryDirectory();
    NSString *tmpSubFolderURL = [fileURLPath stringByAppendingPathComponent:tmpSubFolderName];
    NSError *error;
    [[NSFileManager defaultManager] createDirectoryAtPath:tmpSubFolderURL withIntermediateDirectories:TRUE attributes:nil error:&error];
    if(!error) {
        NSString *fileURL = [tmpSubFolderURL stringByAppendingPathComponent:identifier];
        [data writeToFile:fileURL atomically:YES];
        UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:identifier URL:[NSURL fileURLWithPath:fileURL] options:options error:&error];
        return attachment;
    }
    return nil;
}

- (void)serviceExtensionTimeWillExpire {
    self.contentHandler(self.bestAttemptContent);
}
0
ihux On

The existing answer states that you should set content-available to 1, that NSLog does not work in extensions and the background thread is an issue. These are not right.

  1. content-available:1 has no relevance to a notification service extension, for that to be fired up you need mutable-content:1.

  2. NSLog works fine in extensions, it is handy to use the OS console when troubleshooting.

  3. There is no problem with downloading an image in a background thread.

Try looking in the OS Console to see what might be happening (launch console.app on your Mac, plug in your device and select it on the left, and see what goes by when you send a push. Even without your NSLog you should see the OS trying to find and launch an extension like:

default 10:38:53.925889 -0400   SpringBoard [com.you.whatever] Remote 
notification request 386D-4968 can be modified: 1
default 10:38:53.926227 -0400   SpringBoard [com.you.whatever] Trying to find extension for bundle
info    10:38:53.942366 -0400   pkd Candidate plugin count: 1, info: (
"com.you.whatever.NotificationServiceExtension(1.0.0) 2765CB-8244DD--B83D-20CB148BCEF6")
default 10:38:53.945090 -0400   SpringBoard [com.you.whatever] Extension can modify push notification request 386D-4968? YES

If you don't see success there maybe something is wrong with your project setup, maybe try recreating the target in XCode (do via File -> New -> Target, select Notification Service Extension).