nifty cloud mobile backendでPush通知を実装する


## nifty cloud mobile backendとは

[ニフティクラウドmobile backend](https://console.mb.cloud.nifty.com)

誠に勝手ながら `nifty cloud mobile backend` って毎回入力するのが面倒なので以降は「 __mBaaS__ 」とします。

> mBaaSとは
スマートフォンアプリのバックエンド開発が
開発不要になるクラウドサービス

![スクリーンショット 2016-08-02 午後7.17.30.png](https://qiita-image-store.s3.amazonaws.com/0/97280/2c8410ad-67db-5e7f-2d98-47acc91214a9.png "スクリーンショット 2016-08-02 午後7.17.30.png")

引用：http://mb.cloud.nifty.com/about.htm

## 準備

1. XCodeプロジェクトの新規作成
1. CocoaPodsでのSDK導入

   ```ruby:Podfile
pod 'NCMB', :git => 'https://github.com/NIFTYCloud-mbaas/ncmb_ios.git'
   ```
   ```bash
$ pod install
$ open PROJECT_NAME.xcworkspace
   ```

## iOSアプリ側実装

### プッシュ通知承諾アラート

ここのアラートを出すのはアプリによってマチマチだと思います。実際はどこでもいいです！
チャットアプリだったら初めてメッセージ画面に移動したときにアラートを表示させるようにしてもいいです。

```objective-c:AppDelegate.m
#import <NCMB/NCMB.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [NCMB setApplicationKey:@"アプリケーションキー" clientKey:@"クライアントキー"];
       
    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
        //iOS8以上
        UIUserNotificationType type = UIUserNotificationTypeAlert |
                                      UIUserNotificationTypeBadge |
                                      UIUserNotificationTypeSound;
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:type
                                                                                   categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:setting];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else {
        //iOS7以下
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeAlert |
                                                                                UIRemoteNotificationTypeBadge |
                                                                                UIRemoteNotificationTypeSound)];
    }
}
```

また、 `mBaaS` のリポジトリに適当すぎるほどのプルリクを出しているのでマージされればここが1行で済むようになります。

![スクリーンショット_2016-08-02_午後7_50_41.png](https://qiita-image-store.s3.amazonaws.com/0/97280/141fbbd6-aa7b-8b18-b674-d682909c6577.png "スクリーンショット_2016-08-02_午後7_50_41.png")


この設定を忘れずに！！画像ではオフになっていますが、オンにしてください！！

### デバイストークン取得後

```objective-c:AppDelegate.m
- (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NCMBInstallation *installation = [NCMBInstallation currentInstallation];
    //Device Tokenを設定
    [installation setDeviceTokenFromData:deviceToken];
    
    //端末情報をデータストアに登録
    __weak typeof (self) weakSelf = self;
    [installation saveInBackgroundWithBlock:^(NSError *error) {
        if(error){
            //端末情報の登録が失敗した場合の処理
            NSLog(@"Failed: %@", error);
            if (error.code == 409001) {
                //失敗した原因がdeviceTokenの重複だった場合、上書き処理を行う
                [weakSelf updateExistInstallation:installation];
            } else {
                //deviceTokenの重複以外のエラーが返ってきた場合
                NSLog(@"%@", error);
            }
            
        } else {
            //端末情報の登録が成功した場合の処理
            NSLog(@"Success");
        }
        
    }];
}

// deviceTokenの重複で端末情報の登録に失敗した場合に上書き処理を行う
- (void)updateExistInstallation:(NCMBInstallation*)currentInstallation{
    NCMBQuery *installationQuery = [NCMBInstallation query];
    [installationQuery whereKey:@"deviceToken" equalTo:currentInstallation.deviceToken];
    
    NSError *searchErr = nil;
    NCMBInstallation *searchDevice = [installationQuery getFirstObject:&searchErr];
    
    if (searchErr){
        //端末情報の検索に失敗した場合の処理
        NSLog(@"%@", searchErr);
    } else {
        //上書き保存する
        currentInstallation.objectId = searchDevice.objectId;
        [currentInstallation saveInBackgroundWithBlock:^(NSError *error) {
            if (error){
                //端末情報更新に失敗したときの処理
                NSLog(@"%@", error);
            } else {
                //端末情報更新に成功したときの処理
                NSLog(@"Rewrite Success");
            }
        }];
    }
}
```

`[installation setDeviceTokenFromData:deviceToken];`
ここはこれをするだけでいいのは結構嬉しいです！
`mBaaS` ライブラリのソースをみると `<` , `>` , ` ` が弾かれるようになっていました。

とりあえずここまででiOSアプリ側のプッシュ通知を受け取るための準備は完了！

## mBaaS側作業

[Apple Developer Member Center](https://developer.apple.com/account)

前提としてすでに上記サイトで `AppID` を取得してNotificationを設定しているとします。

![スクリーンショット_2016-08-02_午後7_40_28.png](https://qiita-image-store.s3.amazonaws.com/0/97280/b0b9b4e0-10a3-c6ad-de62-c833ca7c2cc8.png "スクリーンショット_2016-08-02_午後7_40_28.png")

![スクリーンショット_2016-08-02_午後7_42_38.png](https://qiita-image-store.s3.amazonaws.com/0/97280/358e47d1-4dda-6d57-9c66-388cfc507969.png "スクリーンショット_2016-08-02_午後7_42_38.png")

作成した `AppID` のものを選択する。

![スクリーンショット_2016-08-02_午後7_44_00.png](https://qiita-image-store.s3.amazonaws.com/0/97280/44529df3-8d2c-cee7-c8b8-80ac2629554c.png "スクリーンショット_2016-08-02_午後7_44_00.png")

上記画像のようなものがでてくるので `Edit` をクリック

![スクリーンショット_2016-08-02_午後7_45_22.png](https://qiita-image-store.s3.amazonaws.com/0/97280/b948cf28-b50c-8117-8824-27c3cfe5cd96.png "スクリーンショット_2016-08-02_午後7_45_22.png")

まだCertificateを作成していない場合は、KeyChainから証明書を要求しておく

### Certificate作成

![スクリーンショット 2016-08-02 午後7.47.56.png](https://qiita-image-store.s3.amazonaws.com/0/97280/52c0c988-b3b3-5e59-7cf3-5cea24c610cf.png "スクリーンショット 2016-08-02 午後7.47.56.png")

![スクリーンショット 2016-08-02 午後7.49.00.png](https://qiita-image-store.s3.amazonaws.com/0/97280/298035d0-b67b-351a-ce8b-f3f5f0a3ae44.png "スクリーンショット 2016-08-02 午後7.49.00.png")

`ユーザのメールアドレス` はApple Developerに登録しているメールアドレス。通称はなんでもいいのかな？(間違ってたら教えて下さい！！)

適当な場所に作成・保存したら `Create Certificate` をクリックして指示にしたがって `*.cer` ファイルをダウンロードする

### p12ファイル作成

ダウンロードした `aps_development.cer` または `aps.cer` を取得してKeyChainに登録

![スクリーンショット_2016-08-02_午後7_54_10.png](https://qiita-image-store.s3.amazonaws.com/0/97280/05e6ce30-aa14-43c3-90d3-5267d15edd36.png "スクリーンショット_2016-08-02_午後7_54_10.png")

こんな感じに追加されるので場合によって `p12` ファイルを副クリックから書き出してください。

### サーバに適用

[ニフティクラウドmobile backend](https://console.mb.cloud.nifty.com)

上記にログインをする。

![スクリーンショット_2016-08-02_午後7_58_07.png](https://qiita-image-store.s3.amazonaws.com/0/97280/4719ca47-f32b-357f-b978-ad31d3651212.png "スクリーンショット_2016-08-02_午後7_58_07.png")

![65f0dfc5-0d03-e204-860f-0935a2fcb836.png](https://qiita-image-store.s3.amazonaws.com/0/97280/e5654a0c-f2fc-f3e1-1a4f-79bed8f9287a.png "65f0dfc5-0d03-e204-860f-0935a2fcb836.png")



大体こんな感じに手順をすすめる。

あとは `プッシュ通知` タブを選んでそこら辺にある新しくプッシュ通知を作成できそうな以下みたいな画像を押下。
![スクリーンショット 2016-08-02 午後8.01.54.png](https://qiita-image-store.s3.amazonaws.com/0/97280/5bb2df3d-fc3b-46de-dae7-489e2943838f.png "スクリーンショット 2016-08-02 午後8.01.54.png")

iOSアプリはすでにプッシュ通知承諾アラートを表示し、OKが選択されてある状態ならば、そのままプッシュ通知を作成する！
あとは待つ！！

これでプッシュ通知が来たらとりあえずは成功！！

## プッシュ通知の開封をmBaaSに通知する

```objective-C:AppDelegate.m
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [NCMBAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
    // 処理
}
```

プッシュ通知については以前に記事を書いたので以下リンクを参照ください。

[アプリが起動されてない場合のPush通知からの起動動作について](http://qiita.com/nnsnodnb/items/fe5f9e82b2b5412ddaf0)

## おわりに

ざっと簡単な実装をしてみましたが、いかがだったでしょうか？
以前に[Pythonでプッシュ通知を実装する記事](http://qiita.com/nnsnodnb/items/ba415c2a56a037cce526)を書いたのですが、こちらも合わせてなんらかのテストができるとちょっといいかもですね！