Receiving a Push Notification

The reception handler receives Push to App notifications.

The following sample code is for getting notification content with the application(_:didReceiveRemoteNotification:fetchCompletionHandler:) method of the AppDelegate class.

Swift 3:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
  print("Received notification : \(userInfo)")

  // Create a KiiReceivedMessage instance from userInfo.
  let message = KiiReceivedMessage(fromAPNS: userInfo)

  // Get the changed KiiObject.
  if (message.containsKiiObject()) {
    let anObject = message.eventSourceObject()
    // Do something.
  }

  // Get the subscribed bucket.
  if (message.containsKiiBucket()) {
    let aBucket = message.eventSourceBucket();
    // Do something.
  }

  // Get the sender of the push message.
  if (message.senderUser() != nil) {
    // If the sender of the message is a user, get the user.
    let aUser = message.senderUser()
    // Refresh the user and then access it.
  } else if (message.senderThing() != nil) {
    // If the sender of the message is a thing, get the thing.
    let aThing = message.senderThing()
    // Refresh the thing and then access it.
  } else {
    // The message has no sender information.
  }

  // Determine the scope.
  let scopeType = message.getValueOf(.SCOPE_TYPE)!
  switch(scopeType){
  case "APP_AND_GROUP" :
    // If the subscribed bucket is in a group scope, get the group.
    let aGroup = message.eventSourceGroup()
    // Refresh the group and then access it.
    break
  case "APP_AND_USER" :
    // If the subscribed bucket is in a user scope, get the user.
    let aUser = message.eventSourceUser()
    // Refresh the user and then access it.
    break
  case "APP_AND_THING" :
    // If the subscribed bucket is in a thing scope, get the thing.
    let aThing = message.eventSourceThing()
    // Refresh the thing and then access it.
    break

  default:
    // The subscribed bucket is in the application scope.
    break;
  }
  // Get the bucket name.
  // "KiiMessage_BUCKET_ID" is an enum that is defined in KiiMessageField.
  let bucketName = message.getValueOf(.BUCKET_ID)

  // Get the event type.
  // "KiiMessage_TYPE" is an enum that is defined in KiiMessageField.
  let type = message.getValueOf(.TYPE)

  completionHandler(.newData)
}

Objective-C:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result)) completionHandler {
  NSLog(@"Received notification: %@", userInfo);

  // Create a KiiReceivedMessage instance from userInfo.
  KiiReceivedMessage *message = [KiiReceivedMessage messageFromAPNS:userInfo];

  // Get the changed KiiObject.
  if (message.containsKiiObject) {
    KiiObject *anObject = message.eventSourceObject;
    // Do something.
  }

  // Get the subscribed bucket.
  if (message.containsKiiBucket) {
    KiiBucket *aBucket = message.eventSourceBucket;
    // Do something.
  }

  // Get the sender of the push message.
  if (message.senderUser != nil) {
    // If the sender of the message is a user, get the user.
    KiiUser *aUser = message.senderUser;
    // Refresh the user and then access it.
  } elseif (message.senderThing != nil) {
    // If the sender of the message is a thing, get the thing.
    KiiThing *aThing = message.senderThing;
    // Refresh the thing and then access it.
  } else {
    // The message has no sender information.
  }

  // Determine the scope.
  NSString *scopeType = [message getValueOfKiiMessageField:KiiMessage_SCOPE_TYPE];

  if ([@"APP_AND_GROUP" isEqualToString: scopeType]) {
    // If the subscribed bucket is in a group scope, get the group.
    KiiGroup *aGroup = message.eventSourceGroup;
    // Refresh the group and then access it.
  } else if ([@"APP_AND_USER" isEqualToString: scopeType]) {
    // If the subscribed bucket is in a user scope, get the user.
    KiiUser *aUser = message.eventSourceUser;
    // Refresh the user and then access it.
  } else if ([@"APP_AND_THING" isEqualToString: scopeType]) {
    // If the subscribed bucket is in a thing scope, get the thing.
    KiiThing *aThing = message.eventSourceThing;
    // Refresh the thing and then access it.
  } else {
    // The subscribed bucket is in the application scope.
  }

  // Get the bucket name.
  // "KiiMessage_BUCKET_ID" is an enum that is defined in KiiMessageField.
  NSString *bucketName = [message getValueOfKiiMessageField:KiiMessage_BUCKET_ID];

  // Get the event type.
  // "KiiMessage_TYPE" is an enum that is defined in KiiMessageField.
  NSString *type = [message getValueOfKiiMessageField:KiiMessage_TYPE];

  completionHandler(UIBackgroundFetchResultNewData);
}

This sample code gets information from the KiiReceivedMessage instance as follows:

  1. Extract data from the push notification. The containsKiiBucket() method checks if the payload contains bucket data and the eventSourceBucket() method gets the bucket. Then, the containsKiiObject() method checks if the payload contains KiiObject data and the eventSourceObject() method gets the KiiObject.

  2. Get the user or the thing that caused the push notification with the senderUser() method or the senderThing() method.

  3. Extract the following fields from the notification with the getValueOf(_:) method.

    • .SCOPE_TYPE: The scope of the bucket
    • .BUCKET_ID: The ID of the target bucket
    • .TYPE: The enumeration value for the event that occurred in the target bucket

For more information about interpreting push notifications and extracting field values, see the appledoc.

You need to address multiple handler calls according to the push notification feature of your choice. For understanding when and what methods are called, see Combinations of Reception Methods.

If you use only the Push to App notification feature, you do not need to use the user action handler. The Push to App notification feature does not allow customization of the notification payload and the handler is not called via Notification Center.

If you have issues in receiving push notifications, information in Troubleshooting might help you. You can also use the simple implementation illustrated in Push Notification Tutorials to investigate if the push notification is working properly.

Determining the type of push notification

The reception handler and the user action handler receive all push notifications to the mobile app.

You can determine which feature (Push to App, Push to User, or Direct Push) generated a push notification that was received on the mobile app by checking keys in the payload. For available fields by feature, see KiiReceivedMessage in the appledoc. Determine the type of push notification according to the information in the appledoc.

Push message example

The following is an example of the data you can get from userInfo. You can get various information from the push message, such as which bucket and object were modified and how they were modified (e.g., added, deleted and so on). For more information, see the appledoc.

{
    aps = {
    };
    bi = bucketName;
    bt = rw;
    oi = "fedcba09-8765-4321-fedc-ba0987654321"
    sa = 0123abcd;
    st = "APP_AND_USER";
    su = "01234567-89ab-cdef-0123-456789abcdef";
    t = "DATA_OBJECT_CREATED";
    w = 1403844866395;
}

You cannot customize push notifications generated from the Push to App feature. Push to App notifications are sent with the content-available key that has a value of 1. If you want to display push notifications in Notification Center, see Customizing a push message.

Preventing an infinite loop of push notifications

When designing and implementing the push notification feature, ensure that your mobile app does not cause an infinite loop of push notifications. If the notification reception process triggers another push notification, there is no way to stop the infinite loop.

Specifically for the Push to App notification feature, if the notification reception process updates the subscribed bucket, it will cause an infinite loop.

If your release module caused an infinite loop, it would be very difficult to solve the issue. To fix it fundamentally, your mobile app on every end-user's device must be updated to a fixed version. Until the update is complete, you would need to delete the key or the certificates in the developer portal or unsubscribe each user from the bucket by using the REST API.