且构网

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

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

更新时间:2022-10-22 21:38:50

您已完成大部分工作.您发送附件的方式通常是作为有效负载中的 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!