SDK

Remote Notifications

In this page you'll learn how notifications are handled in your app and what all the options at your disposal to create a great messaging experience for your users.

Notificare supports several types of interactive and actionable notifications that will be handled for you without any extra development. If you are going to prevent this default behaviour, please note that you will have to either handle all the functionality yourself (metrics logging, presenting UI or collect replies) or if you don't, you understand that some features will not work as advertised.

Receiving Notifications

In Notificare we will streamline how notifications are handled for iOS 9 and higher. This is automatically handled for you and there's only two major interactions your app needs to account for, namely your app needs to react when notifications are received in foreground (while in use) and in background (when your app not being used). The first thing you need, to handle all types of notifications, is to make sure your app is declaring the following permissions in your app's Info.plist file:

ios camera privacy plist

This will make sure your app can request access to the device's camera or photo library whenever it is needed.

If you are considering supporting non-HTTPS pages when using the Webpage notification type you will need to also declare a more permissive ATS policy as follows:

declare ats in plist

Then your AppDelegate.m or AppDelegate.swift you'll need to implement the following delegate method in order to get a notification whenever it arrives and the app is being used:

-(void)notificarePushLib:(NotificarePushLib *)library didReceiveRemoteNotificationInForeground:(nonnull NotificareNotification *)notification withController:(id _Nullable)controller {
 //Here you probably don't want to interrupt the user and simply show that a notification has arrive with an in-app badge
}
func notificarePushLib(_ library: NotificarePushLib, didReceiveRemoteNotificationInForeground notification: NotificareNotification, withController controller: Any?) {
    //Here you probably don't want to interrupt the user and simply show that a notification has arrive with an in-app badge
}

The best approach when the app is being used and a notification arrives, is to not interrupt the user, you can save this information and display some UI element that warns the user without interrupting whatever the user was doing.

But in most cases, notifications will arrive when the app is not being used. Users will click on it from the notification center or lock screen and you will want to show those immediately to the user. In those cases the following delegate method will be triggered:

-(void)notificarePushLib:(NotificarePushLib *)library didReceiveRemoteNotificationInBackground:(nonnull NotificareNotification *)notification withController:(id _Nullable)controller{
    //Notification arrive in background and user clicked on it from notfication center or lock screen, here you will want to present it to the user
}
func notificarePushLib(_ library: NotificarePushLib, didReceiveRemoteNotificationInBackground notification: NotificareNotification, withController controller: Any?) {
    //Notification arrive in background and user clicked on it from notfication center or lock screen, here you will want to present it to the user
}

Whenever this delegate is triggered you will need to handle it accordingly by presenting the notification in your own navigation stack or tabbed views using your own navigation controller. This is achieved by using the following method:

-(void)notificarePushLib:(NotificarePushLib *)library didReceiveRemoteNotificationInBackground:(nonnull NotificareNotification *)notification withController:(id _Nullable)controller{
    UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
    [[NotificarePushLib shared] presentNotification:notification inNavigationController:navController withController:controller];
}
func notificarePushLib(_ library: NotificarePushLib, didReceiveRemoteNotificationInBackground notification: NotificareNotification, withController controller: Any?) {
    let navController = window.rootViewController as? UINavigationController
    NotificarePushLib.shared().present(notification, in: navController, withController: controller)
}

This will enable you to control how a navigation bar looks like and seamlessly integrate a notification's UI into your own app.

Our SDK also allows you to define which notification's authorization options you would like to request from your user. This is an optional step, if not defined we will register UNAuthorizationOptionAlert, UNAuthorizationOptionBadge and UNAuthorizationOptionSound by default. To define authorization options please add the following to your AppDelegate.m or AppDelegate.swift:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [[NotificarePushLib shared] initializeWithKey:nil andSecret:nil];
    [[NotificarePushLib shared] setDelegate:self];

    if (@available(iOS 13.0, *)) {
        [[NotificarePushLib shared] setAuthorizationOptions:UNAuthorizationOptionAlert + UNAuthorizationOptionBadge + UNAuthorizationOptionSound + UNAuthorizationOptionProvidesAppNotificationSettings + UNAuthorizationOptionProvisional + UNAuthorizationOptionAnnouncement];
    } else {
        if (@available(iOS 12.0, *)) {
            [[NotificarePushLib shared] setAuthorizationOptions:UNAuthorizationOptionAlert + UNAuthorizationOptionBadge + UNAuthorizationOptionSound + UNAuthorizationOptionProvidesAppNotificationSettings + UNAuthorizationOptionProvisional];
        } else {
            if (@available(iOS 10.0, *)) {
                [[NotificarePushLib shared] setAuthorizationOptions:UNAuthorizationOptionAlert + UNAuthorizationOptionBadge + UNAuthorizationOptionSound];
            }
        }
    }

    [[NotificarePushLib shared] launch];

    ...more code

}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

    NotificarePushLib.shared().initialize(withKey: nil, andSecret: nil)
    NotificarePushLib.shared().delegate = self

    if #available(iOS 13.0, *) {
        NotificarePushLib.shared().authorizationOptions = [.alert, .badge, .sound, .providesAppNotificationSettings, .provisional, .announcement]
    } else {
        if #available(iOS 12.0, *) {
            NotificarePushLib.shared().authorizationOptions = [.alert, .badge, .sound, .providesAppNotificationSettings, .provisional]
        } else {
            if #available(iOS 10.0, *) {
                NotificarePushLib.shared().authorizationOptions = .alert + .badge + .sound
            }
        }
    }


    NotificarePushLib.shared().launch()

    ...more code
}

Please note the following authorization options are available: UNAuthorizationOptionAnnouncement. first introduced in iOS 13, the options UNAuthorizationOptionProvidesAppNotificationSettings and UNAuthorizationOptionProvisional are available since iOS 12 and UNAuthorizationOptionCarPlay is available since iOS 10. The option UNAuthorizationOptionAnnouncement will allow Siri to automatically read out messages over AirPods, the UNAuthorizationOptionProvisional option will register for notifications with provisional authorization, this means that users will not be prompted to with the permission dialog to accept notifications. Although this might be a great way to opt-in users to remote notifications, any message you sent afterwards will be deliver quietly. Messages delivered quietly will not be shown in the lock screen or play a sound.

Also note that if you implement the UNAuthorizationOptionProvidesAppNotificationSettings option, notifications from your app will display a button in both the Instant Tuning menu and Notification Settings. The purpose of that button is to provide users a shortcut to your app settings where they can fine-tune which kind of notifications they would like to receive. Implementing such settings views is highly recommended as it could be the reason between allowing your app to keep display notifications or being mute completely. If you do implement this option it is mandatory that you implement the following delegate:

-(void)notificarePushLib:(NotificarePushLib *)library shouldOpenSettings:(NotificareNotification * _Nullable)notification {
    //Deep link to your settings view
}
func notificarePushLib(_ library: NotificarePushLib?, shouldOpenSettings notification: NotificareNotification?) {
    //Deep link to your settings view
}

This will give you the opportunity to present your users with the in-app settings view where you should allow them to customize what kind of notifications they should receive. If the user clicked the button from a specific notification you will receive that object too. If it came from the Notification Settings that object will be nil.

Optionally since iOS 10, you can enable presentation options when your app is in the foreground. This will allow you to show a small banner in the top of your app, play a sound or badge your app, whenever a notification arrives and your app is being used. By default our library will set this to UNNotificationPresentationOptionNone, but you can change this behaviour to match your needs:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [[NotificarePushLib shared] initializeWithKey:nil andSecret:nil];
    [[NotificarePushLib shared] setDelegate:self];

    if (@available(iOS 10.0, *)) {
        [[NotificarePushLib shared] setPresentationOptions:UNNotificationPresentationOptionAlert + UNNotificationPresentationOptionSound + UNNotificationPresentationOptionBadge];
    }

    [[NotificarePushLib shared] launch];

    ...more code

}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

    NotificarePushLib.shared().initialize(withKey: nil, andSecret: nil)
    NotificarePushLib.shared().delegate = self

    if #available(iOS 10.0, *) {
        NotificarePushLib.shared().presentationOptions = .alert + .sound + .badge
    }

    NotificarePushLib.shared().launch()

    ...more code
}

Also since iOS 10, if you are using Rich Push Templates you can define category options. These options can define how your notifications and actions will behave. The options UNNotificationCategoryOptionCustomDismissAction, UNNotificationCategoryOptionAllowInCarPlay and UNNotificationCategoryOptionNone were introduced in iOS 10, the options UNNotificationCategoryOptionHiddenPreviewsShowTitle and UNNotificationCategoryOptionHiddenPreviewsShowSubtitle were introduced in iOS 11 and the option UNNotificationCategoryOptionAllowAnnouncement was first introduced in iOS 13. By default, in iOS 10 we will use UNNotificationCategoryOptionCustomDismissAction and in iOS 11 or higher UNNotificationCategoryOptionCustomDismissAction and UNNotificationCategoryOptionHiddenPreviewsShowTitle, but you can change this behaviour to match your needs:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [[NotificarePushLib shared] initializeWithKey:nil andSecret:nil];
    [[NotificarePushLib shared] setDelegate:self];

    if (@available(iOS 10.0, *)) {
        [[NotificarePushLib shared] setCategoryOptions:UNNotificationCategoryOptionCustomDismissAction];
    }

    if (@available(iOS 11.0, *)) {
        [[NotificarePushLib shared] setCategoryOptions:UNNotificationCategoryOptionCustomDismissAction + UNNotificationCategoryOptionHiddenPreviewsShowTitle];
    }

    if (@available(iOS 13.0, *)) {
        [[NotificarePushLib shared] setCategoryOptions:UNNotificationCategoryOptionCustomDismissAction + UNNotificationCategoryOptionHiddenPreviewsShowTitle + UNNotificationCategoryOptionAllowAnnouncement];
    }

    [[NotificarePushLib shared] launch];

    ...more code

}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

    NotificarePushLib.shared().initialize(withKey: nil, andSecret: nil)
    NotificarePushLib.shared().delegate = self

    if #available(iOS 10.0, *) {
        NotificarePushLib.shared().categoryOptions = .customDismissAction
    }
    if #available(iOS 11.0, *) {
        NotificarePushLib.shared().categoryOptions = .customDismissAction + .hiddenPreviewsShowTitle
    }
    if #available(iOS 13.0, *) {
        NotificarePushLib.shared().categoryOptions = .customDismissAction + .hiddenPreviewsShowTitle + .allowAnnouncement
    }

    NotificarePushLib.shared().launch()
    ...more code
}

System Notifications

In Notificare you can send silent notifications that will wake up your app and can be used to download new data. These are called System Notifications and will not be added to the device's lock screen or notification center nor they will be added to the inbox (if implemented).

To be notified whenever those notifications are received, add the following to your AppDelegate.m or AppDelegate.swift:

-(void)notificarePushLib:(NotificarePushLib *)library didReceiveSystemNotificationInForeground:(nonnull NotificareSystemNotification *)notification{
    //System notification received while app was in the foreground
}

-(void)notificarePushLib:(NotificarePushLib *)library didReceiveSystemNotificationInBackground:(nonnull NotificareSystemNotification *)notification{
    //System notification received while app was in the background
}
func notificarePushLib(_ library: NotificarePushLib?, didReceiveSystemNotificationInForeground notification: NotificareSystemNotification) {
    //System notification received while app was in the foreground
}

func notificarePushLib(_ library: NotificarePushLib?, didReceiveSystemNotificationInBackground notification: NotificareSystemNotification) {
    //System notification received while app was in the background
}

Notifications from Unknown Sources

In some apps it possible you're also using other providers to send remote notifications, when that is the case Notificare will recognize an unknown notification and trigger a delegate method that you can use to further handle that notification. To be notified whenever that happens, add the following to your AppDelegate.m or AppDelegate.swift:

-(void)notificarePushLib:(NotificarePushLib *)library didReceiveUnknownNotification:(nonnull NSDictionary *)notification{
    //Handle notification from a different source
}
func notificarePushLib(_ library: NotificarePushLib?, didReceiveUnknownNotification notification: [AnyHashable : Any]) {
    //Handle notification from a different source
}

It is also possible that notifications from unknown sources handle actions or text input from users, when that is the case the following delegate is triggered:

- (void)notificarePushLib:(NotificarePushLib *)library didReceiveUnknownAction:(NSDictionary *)action forNotification:(NSDictionary *)notification{
    //Handle action from a different source
}
func notificarePushLib(_ library: NotificarePushLib?, didReceiveUnknownAction action: [AnyHashable : Any]?, forNotification notification: [AnyHashable : Any]?) {
    //Handle action from a different source
}

Deep Links

In modern apps, this is a great way of creating interactions between notifications and your own app content, allowing you to send messages that can eventually drive the user to open content hidden deeper in your app.

To prepare your app to handle deep links is not complicated and will allow you to handle not only Deep Link notification types, but also any link made from an web page. In order to indicate your app that you will handle a custom URL scheme you simply have to declare the following in your app's .plist file:

ios url schemes

Because these deep links can also be called from links in HTML content or actions in your notifications, you must also declare any URL Scheme you considering to use in the Launch Services Queries Schemes in your app's .plist file as shown below:

ios launch services url schemes

Then in your AppDelegate.m or AppDelegate.swift make sure your implement the following methods:

//For iOS 9
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    //Handle your deep linking
    return YES;
}

//Deep Link was executed when your app was inactive
- (void)notificarePushLib:(NotificarePushLib *)library didReceiveLaunchURL:(NSURL *)launchURL {
    //Handle your deep linking
}


//For iOS 10 and higher when app is in background, foreground or inactive
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    //Handle your deep linking
    return YES;
}
//For iOS 9 and lower when app is in background or foreground
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
    //Handle your deep linking
    return true
}

//Link was executed when your app was inactive
func notificarePushLib(_ library: NotificarePushLib, didReceiveLaunch launchURL: URL) {
    //Handle your deep linking
}

//For iOS 10 and higher when app is in background, foreground or inactive
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
    //Handle your deep linking
    return true
}

Another situation where you will also want to handle deep links is when users click in a link in a HTML or Web Page notification. If that link should open a view in your app you will want to intercept those clicks and handle it the same way you handle deep links.

First make sure you declare those URL Schemes in the Notificare.plist file as follows:

ios notificare plist url schemes

Our library will then intercept all the links using those URL Schemes and trigger the following delegate method:

- (void)notificarePushLib:(NotificarePushLib *)library didClickURL:(NSURL *)url inNotification:(NotificareNotification *)notification{
    //Handle Deep Link
}
func notificarePushLib(_ library: NotificarePushLib, didClick url: URL, in notification: NotificareNotification) {
    //Handle Deep Link
}

Inbox

With our library it's extremely easy to implement an in-app inbox. Implementing an inbox increases considerably the engagement rates of your notifications simply because messages will always be available inside your app. To activate the inbox functionality, please follow the instructions described here.

After activating this functionality, implement the following delegate method in your AppDelegate.m or AppDelegate.swif that is triggered whenever the inbox initializes or reloads its data:

-(void)notificarePushLib:(NotificarePushLib *)library didLoadInbox:(nonnull NSArray<NotificareDeviceInbox *> *)items{
    //Inbox did load, it is now safe to show UI
}
func notificarePushLib(_ library: NotificarePushLib, didLoadInbox items: [NotificareDeviceInbox]) {
    //Inbox did load, it is now safe to show UI
}

Use this delegate method to signal your UI that the inbox can be used or that it needs to be reloaded.

Once inbox is ready to be used you can then use the InboxManager to handle it. To get all the items in the inbox you would basically invoke the following:

[[[NotificarePushLib shared] inboxManager] fetchInbox:^(id  _Nullable response, NSError * _Nullable error) {
    if (!error) {
        for (NotificareDeviceInbox * item in response) {
            NSLog(@"%@", [item message]);
        }
    }
}];
NotificarePushLib.shared().inboxManager().fetchInbox({(_ response: Any?, _ error: Error?) -> Void in
    if error == nil {
        for item in (response as! [NotificareDeviceInbox]) {
            print("\(item.message)")
        }
    }
})

To present a message from the inbox, you will need your own navigation controller where we will push the notification's UI. This will allow you to control how this UI looks like. To do that, please use the following method:

[[[NotificarePushLib shared] inboxManager] openInboxItem:item completionHandler:^(id  _Nullable response, NSError * _Nullable error) {
    if (!error) {
        [[NotificarePushLib shared] presentInboxItem:(NotificareDeviceInbox *)item inNavigationController:[self navigationController] withController:response];
    }
}];
NotificarePushLib.shared().inboxManager().openInboxItem(item, completionHandler: {(_ response: Any?, _ error: Error?) -> Void in
    if error == nil {
        NotificarePushLib.shared().presentInboxItem((item as? NotificareDeviceInbox), in: self.navigationController, withController: response)
    }
})

At anytime you can also delete a notification from the inbox:

[[[NotificarePushLib shared] inboxManager] removeFromInbox:(NotificareDeviceInbox *)item completionHandler:^(id  _Nullable response, NSError * _Nullable error) {
    if (!error) {
        //Inbox item removed
    }
}];
NotificarePushLib.shared().inboxManager().remove(from: (item as? NotificareDeviceInbox), completionHandler: {(_ response: Any?, _ error: Error?) -> Void in
    if error == nil {
        //Inbox item removed
    }
})

Additionally you can also mark a message as read by invoking the following method:

[[[NotificarePushLib shared] inboxManager] markAsRead:(NotificareDeviceInbox *)item completionHandler:^(id  _Nullable response, NSError * _Nullable error) {
    if (!error) {
        //Inbox item marked as read
    }
}];
NotificarePushLib.shared().inboxManager().mark(asRead: item, completionHandler: {(_ response: Any?, _ error: Error?) -> Void in
    if error == nil {
        //Inbox item marked as read
    }
})

Finally you can also delete all items in the inbox by invoking the following method:

[[[NotificarePushLib shared] inboxManager] clearInbox:^(id  _Nullable response, NSError * _Nullable error) {
    if (!error) {
       //Inbox cleared
    }
}];
NotificarePushLib.shared().inboxManager().clearInbox({(_ response: Any?, _ error: Error?) -> Void in
    if error == nil {
        //Inbox cleared
    }
})

If you've configured your inbox functionality to use the AutoBadge feature, then you can implement the following delegate in your AppDelegate.m or AppDelegate.swift. This will be triggered whenever there's changes to the inbox items and can help you manage your UI:

- (void)notificarePushLib:(NotificarePushLib *)library didUpdateBadge:(int)badge{
    //Update in-app badge
}
func notificarePushLib(_ library: NotificarePushLib, didUpdateBadge badge: Int) {
    //Update in-app badge
}

If you using AutoBadge, you can also access your badge count of unread messages at any time by doing the following:

int badge = [[[NotificarePushLib shared] inboxManager] myBadge];
var badge: Int = NotificarePushLib.shared().inboxManager().myBadge()

It is also possible to force the inboxManager to synchronise at any moment. This might be particularly useful if you did not implement remote notifications, when that is the case the inbox manager will not be updated while the app is in use. To do so simply invoke the following method:

[[[NotificarePushLib shared] inboxManager] refresh];
NotificarePushLib.shared().inboxManager().refresh()

Invoking this will trigger the didLoadInbox and didUpdateBadge (if applicable) delegates.

Notification Delegates

Optionally, you can implement delegate methods which can inform your app when certain operations are done or failed, so you can show more UX/UI elements, perform other operations, etc. In your AppDelegate.m or AppDelegate.swift you can add the following delegate methods:

- (void)notificarePushLib:(NotificarePushLib *)library willOpenNotification:(NotificareNotification *)notification{
    //Triggered whenever notification is about to be opened
}

- (void)notificarePushLib:(NotificarePushLib *)library didOpenNotification:(NotificareNotification *)notification{
    //Triggered when the notification does open
}

- (void)notificarePushLib:(NotificarePushLib *)library didClickURL:(NSURL *)url inNotification:(NotificareNotification *)notification{
    //Triggered whenever user clicks a link with a url scheme in the URL_SCHEMES array under OPTIONS in Notificare.plist
    //This only applies for notifications of type HTML or Web Page
}

- (void)notificarePushLib:(NotificarePushLib *)library didCloseNotification:(NotificareNotification *)notification{
    //Triggered when the user closes the notification or completes an action
}

- (void)notificarePushLib:(NotificarePushLib *)library didFailToOpenNotification:(NotificareNotification *)notification{
    //Triggered when notification failed to open
}
func notificarePushLib(_ library: NotificarePushLib, willOpen notification: NotificareNotification) {
    //Triggered whenever notification is about to be opened
}

func notificarePushLib(_ library: NotificarePushLib, didOpen notification: NotificareNotification) {
    //Triggered when the notification does open
}

func notificarePushLib(_ library: NotificarePushLib, didClick url: URL, in notification: NotificareNotification) {
    //Triggered whenever user clicks a link with a url scheme in the URL_SCHEMES array under OPTIONS in Notificare.plist
    //This only applies for notifications of type HTML or Web Page
}

func notificarePushLib(_ library: NotificarePushLib, didClose notification: NotificareNotification) {
    //Triggered when the user closes the notification or completes an action
}

func notificarePushLib(_ library: NotificarePushLib, didFailToOpen notification: NotificareNotification) {
    //Triggered when notification failed to open
}

Actions Delegates

The same can be achieved for actions. In your AppDelegate.m or AppDelegate.swift you can add the following delegate methods:

- (void)notificarePushLib:(NotificarePushLib *)library willExecuteAction:(NotificareAction *)action {
    //Triggered just before the action is going to be executed
}

- (void)notificarePushLib:(NotificarePushLib *)library didExecuteAction:(NotificareAction *)action {
    //Triggered when the action is executed
}

- (void)notificarePushLib:(NotificarePushLib *)library shouldPerformSelectorWithURL:(NSURL *)url inAction:(NotificareAction *)action {
    //Required if you are going to use actions of type "Call a method in your app"
    //Handle it pretty much the same way you would handle a deep link
}

- (void)notificarePushLib:(NotificarePushLib *)library didNotExecuteAction:(NotificareAction *)action {
    //Triggered when the action sheet is cancelled
}

- (void)notificarePushLib:(NotificarePushLib *)library didFailToExecuteAction:(NotificareAction *)action withError:(NSError *)error{
    //Triggered when an action failed to be executed
}
func notificarePushLib(_ library: NotificarePushLib, willExecute action: NotificareAction) {
    //Triggered just before the action is going to be executed
}

func notificarePushLib(_ library: NotificarePushLib, didExecute action: NotificareAction) {
    //Triggered when the action is executed
}

func notificarePushLib(_ library: NotificarePushLib, shouldPerformSelectorWith url: URL, in action: NotificareAction) {
    //Required if you are going to use actions of type "Call a method in your app"
    //Handle it pretty much the same way you would handle a deep link
}

func notificarePushLib(_ library: NotificarePushLib, didNotExecute action: NotificareAction) {
    //Triggered when the action sheet is cancelled
}

func notificarePushLib(_ library: NotificarePushLib, didFailToExecute action: NotificareAction) throws {
    //Triggered when an action failed to be executed
}

Notification Service Extension

In iOS 10, Apple introduced a new extension that enables your apps to process notifications before they are displayed to the users. This can be used to provide users with rich content in the lock screen or simply change the content of your messages in the client side of things.

To make use of this new feature you need to add a new target to your application:

xcode service extensions new target

This will prompt you to the extensions window where you should pick the Notification Service Extension:

ios service extension select extension

To complete adding the new target you must provide a product name and click finish:

ios service extension create target

This is going to add a new folder to your project with the new extension files.

Then if you are using Cocoapods, add the following to your Podfile:

target 'notification' do # use the name of the target you created previously
    pod 'notificare-push-lib', '~> 2.3' # make sure you use the same version as your main target
end

After that make sure you run (in the terminal):

pod install

You can proceed to implement your Notification Service Extension.

If you are not using Cocoapods, before you can start implementing your new extension you must also include all the necessary frameworks in this new target.

This new target will be work as a separated embed app inside your app. You need to add the libNotificarePushLib.a file and all its frameworks in order to add implement this extension correctly. Go ahead and open this new target's Build Phases tab:

ios service extension build phases

Expand the Link Binary with Libraries section and click in the plus button to start adding the necessary frameworks:

xcode add frameworks

One by one add the following frameworks to your project:

  • AVFoundation.framework
  • CoreLocation.framework
  • CoreData.framework
  • UserNotifications.framework
  • MobileCoreServices.framework
  • MessageUI.framework
  • libicucore.dylib
  • UIKit.framework
  • Foundation.framework
  • CoreGraphics.framework
  • MapKit.framework
  • SystemConfiguration.framework
  • Security.framework
  • CFNetwork.framework
  • ImageIO.framework
  • StoreKit.framework
  • WebKit.framework

Once you've successfully, If you choose to create your extension in Swift, you will need to add a bridging header to this target. In Xcode you do this by simply adding a new Cocoa Touch class (in Object-C) like shown below:

xcode add cocoa in swift

This will trigger a Xcode dialog like the one below:

xcode bridging header

By clicking Yes, Xcode will create a new file with a called TargetName-Bridging-Header.h, where TargetName corresponds to your own app’s target. You can now delete the Cocoa Touch file you've created.

Finally, in your TargetName-Bridging-Header.h add the following line:

#import "NotificarePushLib.h"
Please note that this extension is a different target and has its own Info.plist. This means that after iOS 9, Apple will not load non-secure content by default. To make it possible for apps to load content served over HTTP you will need to add a new entry in the extension Info.plist. If you're only going to our dashboard to create lock screen images then this step is not necessary.

If you are using our API to send lock screen media images that are hosted in another location and served over a non-secure protocol (http://) then declare the following in your extension's Info.plist:

declare ats in plist

After you've added the libNotificarePushLib.a and all these frameworks your Link Binary with Libraries will look like this:

xcode added frameworks

After this you are ready to start implementing the extension. In your newly created implementation file, in the didReceiveNotificationRequest method, you must add the following in order to display whatever you end as the lock screen media of your messages:

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];

    [[NotificarePushLib shared] fetchAttachment:request.content.userInfo completionHandler:^(id  _Nullable response, NSError * _Nullable error) {
        if (!error) {
            self.bestAttemptContent.attachments = response;
            self.contentHandler(self.bestAttemptContent);
        } else {
            self.contentHandler(self.bestAttemptContent);
        }
    }];

}
func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    self.contentHandler = contentHandler
    bestAttemptContent = request.content

    NotificarePushLib.shared().fetchAttachment(request.content.userInfo, completionHandler: {(_ response: Any?, _ error: Error?) -> Void in
        if error == nil {
            self.bestAttemptContent.attachments = response
            self.contentHandler(self.bestAttemptContent)
        }
        else {
            self.contentHandler(self.bestAttemptContent)
        }
    })
}

Once your app implementation is complete you can send images via our dashboard by uploading an image in the Lock Screen Media field of the message composer or by using the property attachments of the notification payload of the REST API.

One thing to take in account, is that iOS will limit the amount of time it will allow your app to download a lock screen image. If the user’s network speed is slow, big images will probably not have enough time to download during the allowed execution period and be discarded, resulting in a message being presented without the lock screen media. To optimize this, make sure you do not upload images bigger than 300KB so you can cater to any network conditions users might have.