Intercepting notifications

It is possible to get the raw payload of a notification (which includes your 'custom payload'), would you wish to do something with it. This is done using standard iOS APIs:

iOS 10

It's recommended to implement the UNUserNotificationCenterDelegate in a class.
It allows you to:

  • Unify local and remote notifications callbacks
  • Get the same callback for all user interactions with a push (open, dismiss and actions), even for a cold start
  • Get notified of notifications received while your app is in the foreground. This allows you to take immediate action or to tell iOS to display the push as if your app was opened in background.

You'll also need to call Batch in its two methods to make sure all of the SDK and dashboard's features work correctly.
Keep in mind that being a delegate, it will need to be retained by a variable, since iOS only weakly retains it.

Here's a sample implementation:

  • Swift
  • Objective-C
@objc
class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        [your code]
        BatchPush.handle(userNotificationCenter: center, didReceive: response)
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        [your code]
        BatchPush.handle(userNotificationCenter: center, willPresent: notification, willShowSystemForegroundAlert: true)
        
        // Since you set willShowSystemForegroundAlert to true, you should call completionHandler([.alert, .sound, .badge])
        // If set to false, you'd call completionHandler([])
    }
}

Note: willShowSystemForegroundAlert should reflect the arguments you call the completion handler with. Batch will use that to detect if it should perform foreground actions, or only perform them when the shown alert will be tapped

Finally, set this class as your default UNUserNotificationCenter delegate:

  • Swift
  • Objective-C
class AppDelegate: UIResponder, UIApplicationDelegate {
    let notificationDelegate = NotificationDelegate()
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        if #available(iOS 10, *) {
            UNUserNotificationCenter.current().delegate = notificationDelegate
        }
    }
}

Handling a custom payload

The custom payload is merged at the root of the userInfo you get when called back by iOS:

  • Swift
  • Objective-C
// Works with both methods
func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {

  let userInfo = response.notification.request.content.userInfo

  // When reading the custom payload, you should perform extensive type checking to prevent crashes if you
  // ever change a type, be it intentionally or accidentally.

  // Root keys will be of the type you used in your source JSON, unlike Android.
  // Please see NSJSONSerialization for more info about how the JSON will be interpreted by iOS
  // Here we'll read the "article_id" key of the following custom payload : {"article_id": 2}
  if let articleID = userInfo["article_id"] as? Int {
    // Handle your article ID
  }

  // If you have more complex objets, they also should be parsed correctly
  // Matching custom payload: {"user_data": {"id": 2}}
  if let userData = userInfo["user_data"] as? [AnyHashable : Any],
      let userID = userData["id"] as? Int {
      // Handle your user ID
  }
}

iOS 9 and lower

If your app supports background refresh, it's recommended to implement this method:

  • Swift
  • Objective-C
       func application(application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
       fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)

Don't forget to call the completionHandler with an appropriate value. Batch will only do so for you when it encounters a deeplink.

Otherwise, if you support iOS 6 devices or don't implement background refresh, please implement the older notification delegate method. Note that both can be implemented for retrocompatbility, you'll only be called on one of them.

  • Swift
  • Objective-C
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any])

Your custom payload will be in the userInfo dictionary.

You'll notice the presence of a com.batch key in the userInfo dictionary. This is Batch's internal payload: it is subject to change so you should not rely on parsing it for any of your features.

Handling a custom payload

The custom payload is merged at the root of the userInfo you get when called back by iOS:

  • Swift
  • Objective-C
// Works with both methods
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
  // When reading the custom payload, you should perform extensive type checking to prevent crashes if you
  // ever change a type, be it intentionally or accidentally.

  // Root keys will be of the type you used in your source JSON, unlike Android.
  // Please see NSJSONSerialization for more info about how the JSON will be interpreted by iOS
  // Here we'll read the "article_id" key of the following custom payload : {"article_id": 2}
  if let articleID = userInfo["article_id"] as? Int {
    // Handle your article ID
  }

  // If you have more complex objets, they also should be parsed correctly
  // Matching custom payload: {"user_data": {"id": 2}}
  if let userData = userInfo["user_data"] as? [AnyHashable : Any],
      let userID = userData["id"] as? Int {
      // Handle your user ID
  }
}

By default, Batch will automatically try to open the deeplink you've set in your push campaigns.

If you'd like to prevent Batch from doing that while still being able to use deeplinks in push campaigns, you can call the following method in applicationDidFinishLaunchingWithOptions:

  • Swift
  • Objective-C
BatchPush.enableAutomaticDeeplinkHandling(false)

Then, you can ask Batch to give you the deeplink from the notification when you get it:

  • Swift
  • Objective-C
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
    let deeplink = BatchPush.deeplink(fromUserInfo: userInfo)
}

Be careful, this method will return nil if a deeplink could not be found.