且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在iOS 10应用程序的推送通知中添加媒体附件?

更新时间:2023-11-24 19:15:46

您已准备就绪.您发送附件的方式通常是在有效负载中作为URL.但是,如果您想像附件那样对附件进行硬编码,我认为它可以工作,但我认为您错过了一个关键组件.我认为服务扩展无法访问主捆绑包或其资源.如果您将资源添加到服务扩展中并尝试加载该资源(使用诸如[NSBundle bundleForClass:[NotificationService class]]之类的东西),我怀疑它会起作用.

但是,如果您将URL作为有效负载的一部分发送,那么您将从该URL而不是捆绑包中加载图像.在那种情况下,我很确定您还必须在NSURL上使用startAccessingSecurityScopedResource(以及stopAccessingSecurityScopedResource).

希望有帮助!

There are multiple examples how you should set up your project to add rich notifications which use 'media attachments' technology to show images. I've read most of them but something I missed, because my project does not display any rich notifications with this payload (tested with APNS-Tool and Boodle):

{
    "aps":{
        "alert":{
            "title": "Rich test",
            "body": "Dancing Banana"
        },
        "mutable-content": 1
    }
}

The notification is visible, but on 3D Touch, there are no additional infos displayed (like the image or the modified title). The notification extension breakpoints and NSLog messages are also not working.

Here is my demo project: https://github.com/gklka/RichTest

What I've done:

  1. Created a new project
  2. implemented iOS-style authorization:

    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {

        if (granted) {
            NSLog(@"Granted");

            [[UIApplication sharedApplication] registerForRemoteNotifications];

        } else {
            NSLog(@"Error registering: %@", error);
        }

    }];

  1. added debug to AppDelegate:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"Token: %@", deviceToken);
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Error: %@", error);
}

  1. Added a new target to the project: Notification Service Extension:

  1. Added banana.gif to the project

  2. Added code to add banana attachment into NotificationService.m

    self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];

    // Add image attachment
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"banana" withExtension:@"gif"];
    NSError *error;
    UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"banana" URL:fileURL options:nil error:&error];
    self.bestAttemptContent.attachments = @[attachment];

What did I miss?

Additional info: The same thing works when I use local notifications instead of remote notifications.

You're most of the way there. The way you're going to send the attachment is usually as a URL in your payload. However, if you wanted to hard-code the attachment, like your code does, I think it would work, but I think you missed one critical component. I think the service extension does not have access to the main bundle or its resources. If you added a resource to the service extension and tried to load that (using something like [NSBundle bundleForClass:[NotificationService class]]), I suspect it would work.

However, if you send the URL as part of the payload, then you're going to load the image from that URL and not the bundle anyway. In that case, I'm pretty sure you also have to use startAccessingSecurityScopedResource on NSURL (along with stopAccessingSecurityScopedResource).

Hope that helps!