Nifty Mobile Backendでプッシュ通知を実装してみた(Swift)

環境

  • Xcode: 7.1.1
  • NCMB: 2.2.3

背景

プッシュ通知にはfelloのサービスを利用していたが、Xcode7になってから実装方法がわからなくなってしまったのと、mBaaSに興味があったのでmobile backendの実装を試すことにした。

証明書準備

公式のチュートリアルがわかりやすく、そのまま進めたら準備が完了した。felloの場合、pemの作成が必要だったので、その手間がないのは楽だった。(pem作成自体は、ドキュメント通りすすめれば難しいことはないが)

SDKインストール

クイックスタートをみて、CocoaPodsでSDKをインストールするも、その後の説明Objective-Cでの例しか見つからなかった。検索してみるとSwiftを用いた記事があったので、こちらを参考にする。記事内にも説明があるが、CocoaPodsからのインストールだとエラーが出てしまったので、GitHubからSDKをダウンロードしてインストールした。(SDKのダウンロードはこちら参考にした。)

実装

Bridging-Header.hの追加

こちらの記事を参考にBridgingHeaderを追加した。Build Settings > Objective-C Bridging Headerには$(SRCROOT)/$(PRODUCT_NAME)/$(PRODUCT_NAME)-Bridging-Header.hと指定してみた。$(PRODUCT_NAME)-Bridging-Header.hの中身は以下の通り。

// for Nifty Mobile Backend
#import "NCMB/NCMB.h"

AppDelegate.swiftの更新

Swiftでの記述が調べられなかったが、こちらの記事通りに進めたら実装が完了しプッシュ通知が確認できた。

エラー(ワーニングだったかな?)対応

You've implemented -[ application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist.

といったエラーが出たので、こちらの記事を参考にTARGETS > Capabilities > Background Modes をオンにして、Remote notificationsにチェックを入れた。念のためPush Notificationsもオンにした。エラーも出なくなり、プッシュ通知の受け取りに成功した。

開封通知(正常に実装できていなそう)

プッシュ通知の開封通知の記述を追加しようとドキュメントを見るも、やはりObjective-Cでの説明のため、変換サービスなどを利用し、以下のように記述してみた。アプリ起動時の通知は取得できたが、アプリ終了時での開封通知が取得できない場合がある。どこか実装をミスっていそう。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // 省略
    NCMB.setApplicationKey(Const.NcmbApplicationKey, clientKey: Const.NcmbClientKey)
    
    // 以下の行を追加
    NCMBAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
    
    // 省略
}
    
    func application(application: UIApplication, didReceiveRemoteNotification userInfo:[NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void){
        
        // 以下の行を追加
        if application.applicationState == .Active {
            NCMBAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
        }
    }

バッジ表示のコントロール

このままだとバッジが消えないので、AppDelegate.swiftにバッジをクリアする処理を入れた。Felloの時のものをそのままだが以下の通り記述した。

func applicationWillEnterForeground(application: UIApplication) {
        
    UIApplication.sharedApplication().applicationIconBadgeNumber = -1

}

アプリ起動時にバッジを消すことは可能になったが、mobile backendにはバッジ件数に「インクリメントする」といった設定がある。こちらのissueを見ると「開封通知登録APIを実行する」ことで「データストア上の端末情報にあるバッジ数のみリセット」となっている。前述通り、開封通知の部分が正常に実装できていなそうなので、こちらの機能は使えていない。(数字がクリアされない。)

iOS7対応(保留)

このままで対応OSをiOS7とするとUIUserNotificationSettingsがiOS7に対応していないためエラーが出てしまう。公式ドキュメントでは以下のように説明がある。

if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1){

    //iOS8以上での、DeviceToken要求方法

    //通知のタイプを設定したsettingを用意
    UIUserNotificationType type = UIUserNotificationTypeAlert |
    UIUserNotificationTypeBadge |
    UIUserNotificationTypeSound;
    UIUserNotificationSettings *setting;
    setting = [UIUserNotificationSettings settingsForTypes:type
                                                categories:nil];

    //通知のタイプを設定
    [[UIApplication sharedApplication] registerUserNotificationSettings:setting];

    //DevoceTokenを要求
    [[UIApplication sharedApplication] registerForRemoteNotifications];
} else {

    //iOS8未満での、DeviceToken要求方法
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
     (UIRemoteNotificationTypeAlert |
      UIRemoteNotificationTypeBadge |
      UIRemoteNotificationTypeSound)];
}

こちらを参考に

if #available(iOS 8.0, *) {
    let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
    application.registerUserNotificationSettings(settings)
    application.registerForRemoteNotifications()
} else {
     UIApplication.sharedApplication().registerForRemoteNotificationTypes(.Alert | .Badge | .Sound);
}

このように記述してみるも、Type of expression is ambiguous without more contextとエラーが出てしまい。実装方法がわからなかった。

結果

  • Xcode: 7.1.1
  • NCMB: 2.2.3
  • iOS8以上は実装完了
  • iOS7以下は実装未完了
  • 開封通知の挙動が不安定(インクリメントがリセットできない)