IOS Rich notification didReceiveNotificationRequest is not fired
Asked Answered
R

2

0

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

Repent answered 20/5, 2018 at 16:6 Comment(0)
C
1

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);
}
Cannelloni answered 25/5, 2018 at 7:39 Comment(4)
Thanks for the reply, I'll try it and get back to you. However, I still wonder why NSLog(@"didReceiveNotificationRequest") does not log anything on the log window. At least it should log if didReceiveNotificationRequest is hit, am I right?Repent
NSLog doesn't works with Extensions. If you want to debug your extension code, attach pid to your app and you can test it with the help of breakpoints in Extension too.Cannelloni
I see, didn't know that thank you! I'll make it as answer once I test your code.Repent
Sure let me know, if you face any other issue.Cannelloni
N
2

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).

Nannie answered 29/6, 2018 at 14:24 Comment(0)
C
1

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);
}
Cannelloni answered 25/5, 2018 at 7:39 Comment(4)
Thanks for the reply, I'll try it and get back to you. However, I still wonder why NSLog(@"didReceiveNotificationRequest") does not log anything on the log window. At least it should log if didReceiveNotificationRequest is hit, am I right?Repent
NSLog doesn't works with Extensions. If you want to debug your extension code, attach pid to your app and you can test it with the help of breakpoints in Extension too.Cannelloni
I see, didn't know that thank you! I'll make it as answer once I test your code.Repent
Sure let me know, if you face any other issue.Cannelloni

© 2022 - 2024 — McMap. All rights reserved.