mBaas (nifty) + Swift3でPush通知をお試し

Swift3に慣れてなかったので少々時間をかけてしまったため、
掲載しておきます。

手間取ったこと

1. p12証明書にパスワードを設定してしまったために、通知がエラーになってた
2. swift3向けのサンプルコードが見当たらなくてリファレンスみたりで時間をしまった

###1.実装手順 CocoapodsでNCMBをインストール

```
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'push_sample' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!
  pod 'NCMB', :git => 'https://github.com/NIFTYCloud-mbaas/ncmb_ios.git'
end

post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['SWIFT_VERSION'] = "3.0"
        end
    end
end
```

----

###2.ライブラリの追加とCapabilityの設定
![ライブラリ.png](https://qiita-image-store.s3.amazonaws.com/0/57579/0eafce85-eae5-9383-144e-68da7c438e18.png)

![Push通知利用.png](https://qiita-image-store.s3.amazonaws.com/0/57579/cc8311e2-42ca-f84d-a5b2-078eb7529d23.png)

![バックエンドでのリモート通知許可.png](https://qiita-image-store.s3.amazonaws.com/0/57579/52a3b77e-cf85-6ef0-80a8-08a77bc867de.png)

ビルドしておかないとApple Developerの
Select an App ID for your Apple Push Notification service SSL Certificate (Sandbox)
で選択できないと思います。

----

###3.[デベロッパーセンター](https://developer.apple.com/account/#/welcome)で通知用の証明書作成と、通知利用設定

![通知許可の証明書作成1.png](https://qiita-image-store.s3.amazonaws.com/0/57579/dfb96c58-fa1a-ca8e-1853-663ad908b629.png)

![対象アプリ選択.png](https://qiita-image-store.s3.amazonaws.com/0/57579/74da6a89-fc3c-2db7-7fd8-3ddd263b777a.png)

----
鍵のダウンロードを行い、ダウンロードした鍵ファイルをダブルクリックして、キーチェーンに登録する

----

対象アプリでプッシュ通知を利用するため、Activeに設定
![PushNotificationを有効に.png](https://qiita-image-store.s3.amazonaws.com/0/57579/5e72a97b-92bd-87a8-edb5-ef63fdc7c357.png)

----

**4.Niftyクラウドのmobile Backendで、push通知利用のための鍵作成準備**

MacのFinder -> アプリケーション -> ユーティリティ -> キーチェーンアクセスを起動
![鍵の選択.png](https://qiita-image-store.s3.amazonaws.com/0/57579/24e908b8-5666-5323-e25d-e29d05ad4c8a.png)

![書き出し1.png](https://qiita-image-store.s3.amazonaws.com/0/57579/89293202-0b5a-3977-eacc-27b794d3cfb8.png)

**ここはブランクでないと通知時にエラーになります。**
![鍵のパスワード.png](https://qiita-image-store.s3.amazonaws.com/0/57579/f2938f79-1a69-4e61-66d9-77f4ac8f4f7e.png)

作成したp12ファイルを適当な場所へ保存します。

----

**5.Niftyクラウドのmobile Backendで、push通知設定**

![プッシュ通知の許可.png](https://qiita-image-store.s3.amazonaws.com/0/57579/fc088076-126c-69a2-68c1-45f0fa8e9bdf.png)

![鍵のアップロード.png](https://qiita-image-store.s3.amazonaws.com/0/57579/7504c64e-99f7-46ee-350d-66a740e45218.png)

----

**6.AppDelegate.swiftに通知受け入れの実装**

``` AppDelegate.swift
import UIKit
import NCMB
import UserNotificationsUI
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    let applicationkey = "ニフティクラウドのmbile backendで生成したキー"
    let clientkey      = "ニフティクラウドのmbile backendで生成したキー"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        NCMB.setApplicationKey(applicationkey, clientKey: clientkey)
        // デバイストークンの要求
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
            // Enable or disable features based on authorization.
        }
        application.registerForRemoteNotifications()

        return true
    }

    // UIApplication.shared.registerForRemoteNotifications()によって呼び出される
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data){
        // 端末情報を扱うNCMBInstallationのインスタンスを作成
        let installation = NCMBInstallation.current()
        // デバイストークンの設定
        installation?.setDeviceTokenFrom(deviceToken as Data!)
        // 端末情報をデータストアに登録
        installation?.saveInBackground { (error) -> Void in
            if (error != nil){
                // 端末情報の登録に失敗した時の処理
                if ((error as! NSError).code == 409001){
                    // 失敗した原因がデバイストークンの重複だった場合
                    // 端末情報を上書き保存する
                    self.updateExistInstallation(currentInstallation: installation!)
                }else{
                    // デバイストークンの重複以外のエラーが返ってきた場合
                }
            }else{
                // 端末情報の登録に成功した時の処理
            }
        }
    }
    

    // 端末情報を上書き保存するupdateExistInstallationメソッドを用意
    func updateExistInstallation(currentInstallation : NCMBInstallation){
        let installationQuery: NCMBQuery = NCMBInstallation.query()
        installationQuery.whereKey("deviceToken", equalTo:currentInstallation.deviceToken)
        do {
            let searchDevice = try installationQuery.getFirstObject()
            // 端末情報の検索に成功した場合
            // 上書き保存する
            currentInstallation.objectId = (searchDevice as AnyObject).objectId
            currentInstallation.saveInBackground { (error) -> Void in
                if (error != nil){
                    // 端末情報の登録に失敗した時の処理
                }else{
                    // 端末情報の登録に成功した時の処理
                }
            }
        } catch _ as NSError {
            // 端末情報の検索に失敗した場合の処理
        }
    }
```

----

**7.通知受信確認**
![プッシュ通知の作成.png](https://qiita-image-store.s3.amazonaws.com/0/57579/94e5070c-b951-e9ca-236e-16f800b4fd7b.png)

アプリをバックグラウンドにするか、終了して待ちます。
<img width="375" alt="IMG_1684.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/57579/36a4894d-b339-f485-3ab7-e81ca08511e6.png">

無事着信したら最初の一歩は完了です。

----

**この実装でできていないこと**

できてないことだらけですが、
1. アプリ終了時に通知メッセージをタップしてもアプリが起動しない
2. 通知からアプリに遷移した時に特定の動作をさせる実装ができていない
3. リリース環境時の課題の検証ができていない。

など、たくさんありますので、まずどんなものか試したいという方のお役に立てればと思います。