プッシュ通知周りのおさらい

#バッジ表示の改修が必要だったのでプッシュ通知周りのおさらいをした
Objective-Cで書かれたアプリのプッシュ通知周りで改修を行ったのだが、結構忘れていることが多かったのでおさらいをしてみた。
今更感はタップりあるが、古いコードは残っているので、おさらいかつ自分メモとして残すことにした。
初期設定もいろいろあるが今回はコード部分だけ抜粋。

##DeviceToken取得

iOS8以降では以下記述方法で行う。

```objc:AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;UIUserNotificationSettings *notifiSettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
    [application registerUserNotificationSettings:notifiSettings];
}
```

```objc:AppDelegate.m
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    [application registerForRemoteNotifications];
}
```
```objc:AppDelegate.m
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
     取得した"deviceToken"をごにょごにょ・・・
}
```
ここまでは実装済みなのだが、なぜかDeviceTokeの取得がうまく行かず、これでエラーを確認

```objc:AppDelegate.m
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
```
エラーの内容はこんな感じ。

```
Domain=NSCocoaErrorDomain Code=3000 "Appの有効な“aps-environment”エンタイトルメント文字列が見つかりません" UserInfo={NSLocalizedDescription=Appの有効な“aps-environment”エンタイトルメント文字列が見つかりません}
```
エンタイトルメント文字列ってなんだ・・・
散々改修してきたのに今更なんでできないのかと悩んでいたところ、しょうもないところで設定漏れがあった。

![スクリーンショット 2017-05-23 18.59.52.png](https://qiita-image-store.s3.amazonaws.com/0/178502/d1334ef3-3643-630d-b8e2-05d9e4cdf07f.png)

ここの「Push Notifications」がなぜか「OFF」に。。。
ここが「ON」じゃないとdeviceTokenが取れないので修正。

![スクリーンショット 2017-05-23 19.02.22.png](https://qiita-image-store.s3.amazonaws.com/0/178502/51235712-76e6-4aba-cd70-076078f9c5d5.png)

これでDeviceToken取得OK。



#受信時の動作
こちらに受信後の処理を記述。
ちなみにアプリがActiveの場合は呼び出されるが、InActive、Backgroundの場合は通知をタップしないと呼び出されない。

```objc:AppDelegate.m
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {}
```
この中でアプリケーションの状態を確認して処理を分岐させた。
Activeでない場合は特定のViewに遷移させることにした。

```objc
        UIApplicationState appState = application.applicationState;
        NSString *appStateString = @"unknown";
        if (appState == UIApplicationStateActive) {
            appStateString = @"active";
        } else if (appState == UIApplicationStateInactive) {
            appStateString = @"inactive";
        } else if (appState == UIApplicationStateBackground) {
            appStateString = @"background";
        }
```

通知内容を表示するViewで実行しているメソッドを呼び出したかったので「NSNotificationCenter」を使って通知することにした。
受け側の実装と終わった後の削除も忘れずに。

```objc
[[NSNotificationCenter defaultCenter] postNotificationName:PUSH_NOTIFICATIONS object:nil userInfo:dict]
```

プッシュ通知の処理ではないが、古いソースでUIAlertViewが残っていたのでついでにUIAlertControllerに改修

```objc
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"新しいメッセージ" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}]];
[self.window.rootViewController presentViewController:alertController animated:YES completion:^{
    NSLog(@"おわり");
}];
```
ここのポイントはUIAlertController呼び出しの部分。AppDelegate.mで書く場合は[self.window.rootViewController ・・・]になる。

```objc
// AppDelegate内での記述方法
[self.window.rootViewController presentViewController:alertController animated:YES completion:^{
    NSLog(@"おわり");
}];

// ViewController内での記述方法
[self presentViewController:alertController animated:YES completion:nil];
```

今回は通知でアイコンにバッジを「１」つけるだけの改修だったので、通知内に「"badge": 1」と設定して完了。
LINEなどのようにアイコンのバッジ数を加算する場合はサイレント通知を利用する。
サイレント通知はアプリを起動させることができるので、受信後の処理を書くことができる。
この辺は別アプリで実装済みだが、今回は簡単な改修なので利用しなかったので割愛。

お粗末でした。