サーバー上変更のプッシュ通知(Push to App)

サーバー上変更のプッシュ通知(Push to App)は、購読中の Bucket の変更をプッシュ通知として受け取る機能です。機能概要については、サーバー上変更のプッシュ通知(Push to App) をご覧ください。

Bucket の購読

Bucket を購読して監視を開始する例を以下に挙げます。監視を開始すると、以後この Bucket 内の Object に変更が発生する度に、プッシュ通知がアプリに送信されます。

Objective-C:

  • // If the bucket is new, save it on Kii Cloud by saving a KiiObject in the bucket and then
    // subscribe to the bucket. You cannot subscribe to a bucket if it does not exist on Kii Cloud.
    
    NSError *error = nil;
    
    // Instantiate a bucket.
    KiiBucket *bucket = [Kii bucketWithName:@"_target_bucket_"];
    
    // Create and save a KiiObject in the bucket.
    KiiObject *obj1 = [bucket createObject];
    [obj1 saveSynchronous:&error];
    if (error != nil) {
      // Handle the error.
      return;
    }
    
    // Subscribe to the bucket.
    [[KiiUser currentUser].pushSubscription subscribeSynchronous:bucket
                                                           error:&error];
    if (error != nil) {
      // Handle the error.
      return;
    }
  • // If the bucket is new, save it on Kii Cloud by saving a KiiObject in the bucket and then
    // subscribe to the bucket. You cannot subscribe to a bucket if it does not exist on Kii Cloud.
    
    // Instantiate a bucket.
    KiiBucket *bucket = [Kii bucketWithName:@"_target_bucket_"];
    
    // Create and save a KiiObject in the bucket.
    KiiObject *obj1 = [bucket createObject];
    [obj1 saveWithBlock:^(KiiObject *object, NSError *error) {
      if (error != nil) {
        // Handle the error.
        return;
      }
    
      // Subscribe to the bucket.
      [[KiiUser currentUser].pushSubscription subscribe:bucket
                                                  block:^(KiiPushSubscription *subscription, NSError *error) {
        if (error != nil) {
          // Handle the error.
          return;
        }
      }];
    }];

Swift 2.3:

  • // If the bucket is new, save it on Kii Cloud by saving a KiiObject in the bucket and then
    // subscribe to the bucket. You cannot subscribe to a bucket if it does not exist on Kii Cloud.
    
    // Instantiate a bucket.
    let bucket = Kii.bucketWithName("_target_bucket_")
    
    // Create a KiiObject in the bucket.
    let obj1 = bucket.createObject()
    
    do{
      // Save the KiiObject.
      try obj1.saveSynchronous()
    
      // Subscribe to the bucket.
      try KiiUser.currentUser()!.pushSubscription().subscribeSynchronous(bucket)
    } catch let error as NSError {
      // Handle the error.
      return
    }
  • // If the bucket is new, save it on Kii Cloud by saving a KiiObject in the bucket and then
    // subscribe to the bucket. You cannot subscribe to a bucket if it does not exist on Kii Cloud.
    
    // Instantiate a bucket.
    let bucket = Kii.bucketWithName("_target_bucket_")
    
    // Create and save a KiiObject in the bucket.
    let obj1 = bucket.createObject()
    obj1.saveWithBlock { (retObject : KiiObject?, error : NSError?) -> Void in
      if error != nil {
        // Handle the error.
        return
      }
    
      // Subscribe to the bucket.
      KiiUser.currentUser()!.pushSubscription().subscribe(bucket, block: { (subscription : KiiPushSubscription, error : NSError?) -> Void in
        if error != nil {
          // Handle the error.
          return
        }
      })
    }

Swift 3:

  • // If the bucket is new, save it on Kii Cloud by saving a KiiObject in the bucket and then
    // subscribe to the bucket. You cannot subscribe to a bucket if it does not exist on Kii Cloud.
    
    // Instantiate a bucket.
    let bucket = Kii.bucket(withName: "_target_bucket_")
    
    // Create a KiiObject in the bucket.
    let obj1 = bucket.createObject()
    
    do{
      // Save the KiiObject.
      try obj1.saveSynchronous()
    
      // Subscribe to the bucket.
      try KiiUser.current()!.pushSubscription().subscribeSynchronous(bucket)
    } catch let error as NSError {
      // Handle the error.
      return
    }
  • // If the bucket is new, save it on Kii Cloud by saving a KiiObject in the bucket and then
    // subscribe to the bucket. You cannot subscribe to a bucket if it does not exist on Kii Cloud.
    
    // Instantiate a bucket.
    let bucket = Kii.bucket(withName: "_target_bucket_")
    
    // Create and save a KiiObject in the bucket.
    let obj1 = bucket.createObject()
    obj1.save { (retObject : KiiObject?, error : Error?) -> Void in
      if error != nil {
        // Handle the error.
        return
      }
    
      // Subscribe to the bucket.
      KiiUser.current()!.pushSubscription().subscribe(bucket, block: { (subscription : KiiPushSubscription, error : Error?) -> Void in
        if error != nil {
          // Handle the error.
          return
        }
      })
    }

Bucket 購読の確認

Bucket 購読の有無は次のように確認できます。

Objective-C:

  • NSError *error = nil;
    
    // Instantiate the target bucket.
    KiiBucket *bucket = [Kii bucketWithName:@"_target_bucket_"];
    
    // Check if the current user is subscribed to the bucket.
    BOOL subscribed = [[KiiUser currentUser].pushSubscription checkIsSubscribedSynchronous:bucket
                                                                                     error:&error];
    if (subscribed) {
      NSLog(@"The current user is subscribed to the bucket.");
    } else {
      if (error.kiiHttpStatus == 404) {
        NSLog(@"The current user is not subscribed to the bucket.");
      } else {
        // Handle the error.
        return;
      }
    }
  • // Instantiate the target bucket.
    KiiBucket *bucket = [Kii bucketWithName:@"_target_bucket_"];
    
    // Check if the current user is subscribed to the bucket.
    [[KiiUser currentUser].pushSubscription checkIsSubscribed:bucket
                                                        block:^(id<KiiSubscribable> subscribable, BOOL subscribed, NSError *error) {
      if (subscribed) {
        NSLog(@"The current user is subscribed to the bucket.");
      } else {
        if (error.kiiHttpStatus == 404) {
          NSLog(@"The current user is not subscribed to the bucket.");
        } else {
          // Handle the error.
          return;
        }
      }
    }];

Swift 2.3:

  • // Instantiate the target bucket.
    let bucket = Kii.bucketWithName("_target_bucket_")
    
    do{
      // Check if the current user is subscribed to the bucket.
      try KiiUser.currentUser()!.pushSubscription().checkIsSubscribedSynchronous(bucket)
    }catch(let error as NSError){
      print("The current user is not subscribed to the bucket.");
    }
    print("The current user is subscribed to the bucket.");
  • // Instantiate the target bucket.
    let bucket = Kii.bucketWithName("_target_bucket_")
    
    // Check if the current user is subscribed to the bucket.
    KiiUser.currentUser()!.pushSubscription().checkIsSubscribed(bucket) { (retBucket : KiiSubscribable , subscribed : Bool, error : NSError?) -> Void in
      if error != nil {
        // Handle the error.
        return
      }
    
      if (subscribed) {
        print("The current user is subscribed to the bucket.");
      } else {
        print("The current user is not subscribed to the bucket.");
      }
    }

Swift 3:

  • // Instantiate the target bucket.
    let bucket = Kii.bucket(withName: "_target_bucket_")
    
    do{
      // Check if the current user is subscribed to the bucket.
      try KiiUser.current()!.pushSubscription().checkIsSubscribedSynchronous(bucket)
    }catch(let error as NSError){
      print("The current user is not subscribed to the bucket.");
    }
    print("The current user is subscribed to the bucket.");
  • // Instantiate the target bucket.
    let bucket = Kii.bucket(withName: "_target_bucket_")
    
    // Check if the current user is subscribed to the bucket.
    KiiUser.current()!.pushSubscription().checkIsSubscribed(bucket) { (retBucket : KiiSubscribable , subscribed : Bool, error : Error?) -> Void in
      if error != nil {
        // Handle the error.
        return
      }
    
      if (subscribed) {
        print("The current user is subscribed to the bucket.");
      } else {
        print("The current user is not subscribed to the bucket.");
      }
    }

Bucket の購読解除

Bucket の購読を解除する例を以下に挙げます。

Objective-C:

  • NSError *error = nil;
    
    // Instantiate the target bucket.
    KiiBucket *bucket = [Kii bucketWithName:@"_target_bucket_"];
    
    // Unsubscribe from the bucket.
    [[KiiUser currentUser].pushSubscription unsubscribeSynchronous:bucket
                                                             error:&error];
    if (error != nil) {
      // Handle the error.
      return;
    }
  • // Instantiate the target bucket.
    KiiBucket *bucket = [Kii bucketWithName:@"_target_bucket_"];
    
    // Unsubscribe from the bucket.
    [[KiiUser currentUser].pushSubscription unsubscribe:bucket
                                                  block:^(KiiPushSubscription *subscription, NSError *error) {
      if (error != nil) {
        // Handle the error.
        return;
      }
    }];

Swift 2.3:

  • // Instantiate the target bucket.
    let bucket = Kii.bucketWithName("_target_bucket_")
    
    do{
      // Unsubscribe from the bucket.
      try KiiUser.currentUser()!.pushSubscription().unsubscribeSynchronous(bucket)
    } catch let error as NSError {
      // Handle the error.
      return
    }
  • // Instantiate the target bucket.
    let bucket = Kii.bucketWithName("_target_bucket_")
    
    // Unsubscribe from the bucket.
    KiiUser.currentUser()!.pushSubscription().unsubscribe(bucket, block: { (subscription : KiiPushSubscription, error : NSError?) -> Void in
      if error != nil {
        // Handle the error.
        return
      }
    })

Swift 3:

  • // Instantiate the target bucket.
    let bucket = Kii.bucket(withName: "_target_bucket_")
    
    do{
      // Unsubscribe from the bucket.
      try KiiUser.current()!.pushSubscription().unsubscribeSynchronous(bucket)
    } catch let error as NSError {
      // Handle the error.
      return
    }
  • // Instantiate the target bucket.
    let bucket = Kii.bucket(withName: "_target_bucket_")
    
    // Unsubscribe from the bucket.
    KiiUser.current()!.pushSubscription().unsubscribe(bucket, block: { (subscription : KiiPushSubscription, error : Error?) -> Void in
      if error != nil {
        // Handle the error.
        return
      }
    })

より詳しい説明は appledoc をご確認ください。

サーバー上の変更をプッシュ通知として受け取る

サーバー上変更のプッシュ通知によるメッセージは、プッシュ通知の受信ハンドラー に示すプッシュ通知のハンドラーで受け取ります。

以下のサンプルコードでは、AppDelegate クラスの application(_:didReceiveRemoteNotification:fetchCompletionHandler:) メソッドで、プッシュ通知の詳細を取得する例を示します。

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);
}

Swift 2.3:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], 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.getValueOfKiiMessageField(.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.getValueOfKiiMessageField(.BUCKET_ID)

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

  completionHandler(.NewData)
}

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)
}

このサンプルコードでは、KiiReceivedMessage インスタンスから以下の情報を取得しています。

  1. プッシュメッセージよりデータを抽出します。ペイロードに Bucket の情報が含まれるかどうかを containsKiiBucket() メソッドで確認し、Bucket を eventSourceBucket() メソッドで取得します。また、ペイロードに Object の情報が含まれるかどうかを containsKiiObject() メソッドで確認し、Object を eventSourceObject() メソッドで取得します。

  2. 通知を発生させたユーザーまたは Thing を、senderUser() メソッドまたは senderThing() メソッドで取得します。

  3. getValueOf(_:) メソッドを実行し、プッシュメッセージより以下のフィールドを抽出します。

    • .SCOPE_TYPE:Bucket のスコープ
    • .BUCKET_ID:監視対象 Bucket の ID
    • .TYPE:対象 Bucket にて発生したイベントを示す enum 値

プッシュメッセージの解釈の方法や、フィールド値の抽出方法の詳細については appledoc を参照してください。

実際のプログラムでは、実現したいプッシュ通知の機能に基づいて、複数回のハンドラーの呼び出しに対する対応が必要になります。呼び出されるメソッドの組み合わせ に示すメソッドの呼び出しタイミングに従って、必要な機能を作り込んでください。

サーバー上変更のプッシュ通知だけを使用する場合、ユーザーアクションのハンドラー を指定する必要がありません。サーバー上変更のプッシュ通知では APNs のペイロードのカスタマイズができないため、通知センター経由でハンドラーが呼び出されることはありません。

プッシュ通知を期待どおりに受け取れない場合、トラブルシューティング を参考に問題を解決してください。また、プッシュ通知設定チュートリアル にあるシンプルな実装によって、プッシュ通知の動作だけを検証することもできます。

プッシュ通知の種類の判定

プッシュ通知の受信ハンドラーと、ユーザーアクションのハンドラーでは、このモバイルアプリに対するすべてのプッシュ通知を受け取ります。

モバイルアプリに対して通知されたメッセージが、サーバー上変更のプッシュ通知、ユーザープッシュ通知、管理者メッセージのプッシュ通知のうちどの機能で生成されたかは、ペイロード内のキーを確認することで識別できます。appledoc の KiiReceivedMessage の説明には、機能ごとに参照可能なフィールドが記載されています。これを元に、プッシュ通知の機能の種類を判断してください。

プッシュメッセージの例

以下は、プッシュメッセージを受け取ったとき、userInfo によって取得できるデータのイメージです。サーバー上変更のプッシュ通知では、更新があった Bucket や Object、その更新の種類(追加された、削除されたなど)のような情報を上記のメソッドによって取得できます。これらのデータの詳細は 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;
}

サーバー上変更のプッシュ通知では、プッシュメッセージの内容をカスタマイズできません。content-available キーに 1 がセットされた状態でメッセージ送信されます。特に、通知センターにプッシュメッセージを表示したい場合、メッセージのカスタマイズ を参照してください。