AppleWatchでPush通知はシュミレーターと実機でぜんぜん違うから気をつけろ！

AppleWatchのプッシュ通知を受信した際にボタンをつけられるんですが、その際の処理がシュミレーターと実機で全然違うことに衝撃を受けて、記事にしました。
皆様のAppleWatch実装の手助けになれば幸いです。


## シュミレーターでプッシュ通知
Apple WatchのExtensionを作成したさいに以下のグループにapnsファイルがあります。



<YOURAPPNAME> Extension > PushNotificationPayload.apns

```json:PushNotificationPayload.apns
{
    "aps": {
        "alert": {
            "body": "Test message",
            "title": "Optional title"
        },
        "category": "myCategory"
    },
    
    "WatchKit Simulator Actions": [
        {
            "title": "First Button",
            "identifier": "firstButtonAction"
        }
    ],
    
    "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App."
}


```

これをノーティフィケーションのスキーマでビルドすると以下の様なプッシュ通知画面が表示されます。

![Simulator Screen Shot 2016.08.29 23.34.47.png](https://qiita-image-store.s3.amazonaws.com/0/31587/f014c2c7-ea35-5d01-c4e9-a06d1d825fed.png "Simulator Screen Shot 2016.08.29 23.34.47.png")

```json
    "WatchKit Simulator Actions": [
        {
            "title": "First Button",
            "identifier": "firstButtonAction"
        }
    ],

```
のtitleがボタンの文字列になります。
ボタンを押すと`WKInterfaceControllerクラス`のサブクラス、デフォルトだと`InterfaceController`が立ち上がります。
そして、`- handleActionWithIdentifier:forRemoteNotification:`というメソッドが呼ばれます。

```swift:InterfaceController.swift
override func handleActionWithIdentifier(identifier: String?, forRemoteNotification remoteNotification: [NSObject : AnyObject]) {
    
    if let notificationIdentifier = identifier {
        if notificationIdentifier == "firstButtonAction" {
            NSLog("Apple Watch Notification Started")
        }
    }
}

```

このメソッドのidentifierにWatchKit Simulator Actionsのidentifierが渡されるので、それをif文で判別すれば、このidentifierにはこの処理というのを出し分けることができます。

シュミレーターは簡単。
実機がややこしい。

## AppleWatch実機でプッシュ通知

AppleWatchのプッシュ通知の受信タイミングはiPhoneがプッシュ通知を受信したけど、スリープなどで受け取れない場合です。
基本的にプッシュ通知はiPhoneもAppleWatchも仕組みは変わりません。


AppleWatch実機でプッシュ通知の受信の際に、ボタンをつけるにはiOS側でプッシュ通知を登録する際にカテゴリを作る必要があります。

私はよく、AppDelegate.swiftで登録をするのですが、こんな感じの実装になります。

```swift:AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    //push通知
    self.setupPushNotification(application)
return true
}

//MARK: Push通知のセットアップ
func setupPushNotification(application: UIApplication) {
    
    let firstAction = UIMutableUserNotificationAction()
    firstAction.title = "First Button"
    firstAction.identifier = "firstButtonAction"
    firstAction.activationMode = UIUserNotificationActivationMode.Foreground
    firstAction.authenticationRequired = false
    
    let myCategory = UIMutableUserNotificationCategory()
    myCategory.setActions([firstAction], forContext: UIUserNotificationActionContext.Default)
    myCategory.identifier = "myCategory"

    let categories = Set<UIUserNotificationCategory>([myCategory])
    
    application.registerForRemoteNotifications()
    let mySettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound],
                                              categories: categories)
    
    application.registerUserNotificationSettings(mySettings)
}

```

そして、プッシュ通知を送る際のjsonには以下のようにします。


```json
let payload = {
    APNS: {
        aps: {
            "alert": event.message,
            "sound": "default",
            "priority": 10,
            "category":"myCategory"
        }
    },
    APNS_SANDBOX: {
        aps: {
            "alert": event.message,
            "sound": "default",
            "priority": 10,
            "category":"myCategory"
        }
    }
};
```

カテゴリーにiOS側で設定したカテゴリー(myCategory)を指定してください。
これをしてようやく、実機のAppleWatchでボタンアクションを設定することができます。
ボタンを推した後の処理はシュミレーターと一緒です。

##　最後に
最初私勘違いしてたのです。
シュミレーターはPushNotificationPayload.apnsファイルをいじるだけで、簡単に設定できるので実機もapnのjsonファイルにそれらしい設定項目をいれればいけるだろうと思っていたのです。
jsonファイルをいじっても実機には反映されません。
実機はプッシュ通知にカテゴリを設定しないといけません。
気をつけましょう。