Parse.comからNIFTY Cloud mobile backendへプッシュ通知を移行する（iOS編）

[こちらの記事][link-1]の移行期間中のアプリの実装方法iOS編です。
Parse.comのSDKを組み込み済みのアプリに対して、追加でNIFTY Cloud mobile backendのSDKを組み込む方法を紹介します。移行期間が終わったら、Parse.comのSDKとコードを除去してください。

# 共通の作業（実施済みの場合はスキップ）

## (1) @niftyIDを取得する

　@niftyIDを持っていない方は[ここ](http://mb.cloud.nifty.com/signup.htm)から登録してください。
　　※既にお持ちの方は改めて登録する必要はありません。

## (2)mobile backendの利用登録をする

　[ここ](https://console.mb.cloud.nifty.com/)から先ほど取得した@niftyIDでmobile backendにサインアップしてください。
　　※既に利用登録済みの方は作業不要です。

## (3)mobile backendのアプリを作成する

　(2)でサインアップしたかたは利用規約の次の画面でアプリ作成画面が表示されます。任意のアプリ名でアプリを作成してください。
　既にサインアップ済みの方はダッシュボード右上の「+新しいアプリ」から新規のアプリを作ることができます。

## (4)アプリケーションキーとクライアントキーをコピーしておく

　２つのキーはアプリ実装時に使用しますのでどこかにコピーしておきましょう。後から確認する場合はダッシュボード左側のメニューで「アプリ設定」を選ぶと表示されます。

# iOSアプリ固有の手順

## (1) mobile backendのSDKを導入する

　[CocoaPods][link-2]で既存プロジェクトにSDKを導入します。
　CocoaPods未導入な方は以下のコマンドでインストールしてください。

```$ sudo gem install cocoapods```

　cocoapodsのインストールがうまく進まない方は[CocoaPodsの公式サイト][link-2]を参照してください。

　次にPodfileを作ります。既存プロジェクトの```プロジェクト名.xcodeproj```というファイルと同階層に移動して以下のコマンドを実行します。

```$ pod init```

　すると、Podfileというファイルが生成されますので以下のように編集します。```<プロジェクト名>```の部分は既存プロジェクトに合わせて適宜変更してください。

```rb:Podfile
platform :ios, '6.0'

target '<プロジェクト名>' do
  pod 'NCMB', :git => 'https://github.com/NIFTYCloud-mbaas/ncmb_ios.git'
end
```

　Podfileが置いてあるディレクトリで以下のコマンドを実行しSDKをインストールします。

```$ pod install```

　SDKがインストールされると同ディレクトリに```プロジェクト名.xcworkspace```というファイルが生成されるので以降の作業は```プロジェクト名.xcworkspace```を開いて進めてください。[^1]

## (2) mobile backendのSDKを読み込む

　AppDelegate.m の冒頭で Parse.h を読み込んでいるあたりに追記します。

```objc:AppDelegate.m
#import <Parse/Parse.h>
#import <NCMB/NCMB.h>  // ここを追記
```

## (3) mobile backendのSDKの初期化を行う

　AppDelegate.m の```- application:didFinishLaunchingWithOptions:```の中で、ParseのSDKの初期化をしている辺りに追記します。

```objc:AppDelegate.m
[Parse setApplicationId:@"PARSE_APPLICATION_ID" clientKey:@"PARSE_CLIENT_KEY"];
[NCMB setApplicationKey:@"NCMB_APPLICATION_KEY" clientKey:@"NCMB_CLIENT_KEY"];  // ここを追記
```

　PARSE_APPLICATION_IDとPARSE_CLIENT_KEYには既にParse.comのダッシュボードから取得したアプリケーションIDとクライアントキーが記載されているかと思います。
　NCMB_APPLICATION_KEYとNCMB_CLIENT_KEYはmobile backendのダッシュボードから取得したアプリケーションキーとクライアントキーをそれぞれ設定してください。

## (4) mobile backendへinstallationを登録する

　デバイストークンをAPNsから取得する処理はParse導入時に実装済みと思われますので改めて実装する必要はありません。
　APNsから取得したデバイストークンをmobile backendに保存する処理だけを実装します。AppDelegate.m の```- application:didRegisterForRemoteNotificationsWithDeviceToken:```の中で、Parseへinstallation登録している処理の後に追記します。
（Parseの実装の部分は例なのでアプリによって実装は異なります）

```objc:AppDelegate.m
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    PFInstallation *currentInstallation = [PFInstallation currentInstallation];
    [currentInstallation setDeviceTokenFromData:deviceToken];
    [currentInstallation saveInBackground];

    [PFPush subscribeToChannelInBackground:@"" block:^(BOOL succeeded, NSError *error) {
        if (succeeded) {
            NSLog(@"ParseStarterProject successfully subscribed to push notifications on the broadcast channel.");
        } else {
            NSLog(@"ParseStarterProject failed to subscribe to push notifications on the broadcast channel.");
        }
    }];
    
    // ここから下を追記
    NCMBInstallation *installation = [NCMBInstallation currentInstallation];
    [installation setDeviceTokenFromData:deviceToken];
    [installation saveInBackgroundWithBlock:^(NSError *error) {
        if (!error) {
            NSLog(@"NCMB installation: successfully saved.");
        } else {
            NSLog(@"NCMB installation: failed to save. %@", error);
            
            if (error.code == 409001) {
                // 登録済みinstallationのdeviceTokenと重複した新規登録の場合のエラー
                [self updateDuplicatedInstallation:installation];
            } else if (error.code == 404001) {
                // 更新リクエストを送ったがサーバ側のinstallationがコンパネ等から削除済みだった時のエラー
                [self reRegistInstallation:installation];
            }
        }
    }];
}
```

さらに、installationトークンの保存処理でエラーが発生した時のリカバリー用メソッドを追加します。アプリのアップデートとは別に、Parseからinstallationをインポートしている場合など、条件によってはエラーになってしまうので忘れずに追加しておきましょう。

```objc:AppDelegate.m
// 登録済みinstallationのdeviceTokenと重複した新規登録の場合のリカバリー用メソッド
- (void)updateDuplicatedInstallation:(NCMBInstallation *)installation {
    NCMBQuery *installationQuery = [NCMBInstallation query];
    [installationQuery whereKey:@"deviceToken" equalTo:installation.deviceToken];
    [installationQuery getFirstObjectInBackgroundWithBlock:^(NCMBObject *object, NSError *searchError) {
        if (!searchError) {
            installation.objectId = object.objectId;
            [installation saveInBackgroundWithBlock:^(NSError *saveError) {
                if (!saveError) {
                    NSLog(@"NCMB installation: successfully saved the duplicated installation.");
                } else {
                    NSLog(@"NCMB installation: failed to save of the duplicated installation. %@", saveError);
                }
            }];
        } else {
            NSLog(@"NCMB installation: failed to find of the duplicated installation. %@", searchError);
        }
    }];
}

// 更新リクエストを送ったがサーバ側のinstallationがコンパネ等から削除済みだった場合のリカバリー用メソッド
- (void)reRegistInstallation:(NCMBInstallation *)installation {
    installation.objectId = nil;
    [installation saveInBackgroundWithBlock:^(NSError *error) {
        if (!error) {
            NSLog(@"NCMB installation: successfully re-regist.");
        } else {
            NSLog(@"NCMB installation: failed to re-regist. %@", error);
        }
    }];
}
```

その他、Parse側で実装していた際にセグメント配信用のパラメータなどを追加していた場合は、必要に応じて追加フィールドを設定してから保存してください。

## (5) 動作試験

　ビルドして実機で動かしてみてください。
　正しく実装されていればmobile backendのダッシュボード上でデータストアのinstallationクラスを確認すると端末の情報が登録されているかと思います。

　また、APNs証明書を設定すればプッシュ通知を送ることもできます。証明書については[こちら](http://mb.cloud.nifty.com/doc/current/tutorial/push_setup_ios.html)をご覧ください。


# 関連リンク
* [Qiita : Parse.comからNIFTY Cloud mobile backendへプッシュ通知を移行する際の注意点][link-1]
* [Qiita : Parse.comからNIFTY Cloud mobile backendへプッシュ通知を移行する（Android編）][link-3]
* [cocoapods.org][link-2]

[link-1]:http://qiita.com/ndyuya/items/513e1713e4024f7a924a
[link-2]:https://cocoapods.org/
[link-3]:http://qiita.com/ndyuya/items/5e256deb548955d0790d

[^1]: .xcworkspaceではなく.xcodeprojを開いて作業するとSDKへの参照が正しく出来ずビルドに失敗します