Android O(APIバージョン26)のPush通知

<img width="231" alt="*" src="https://qiita-image-store.s3.amazonaws.com/0/9104/2684d5a7-a676-d9e4-3f08-c963983a6688.png">

Android O(APIバージョン26)からPush通知の「通知チャンネル」登録が必須になる。
つまりtargetSdkVersionが26以上の場合が対象になる。

※本記事にはPush通知の実装全体は掲載していません。

## 通知チャンネルとは
「通知チャンネル」は、例えば「お得情報」と「ポイント期限通知」を分けたり、ニュースのカテゴリ別で分けたり等、通知内容によって通知のON/OFFができる機能がOSレベルで搭載される。

targetSdkVersionを25以下から26以上に上げても、Android Studioで特に警告の類は表示されない。
されないが、ビルドして通知すると以下のように「チャンネルが無い」とエラーが表示される。

```
E/NotificationService: No Channel found for pkg=com.example.app, channelId=null, id=1234567890, tag=null, opPkg=com.example.app, callingUid=12345, userId=0, incomingUserId=0, notificationUid=12345, notification=Notification(channel=null pri=0 contentView=null vibrate=null sound=content://settings/system/notification_sound defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
```

また、当然ではあるがアプリ側から通知設定を書き換えたりはできないので、アプリ側でAndroid O以前の設定とアプリ側の設定画面と同期を取ったりといった事はできない。

## 通知チャンネルの登録
以下のようにしてチャンネルを登録する。

```java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

    NotificationChannel channel = new NotificationChannel(
        // 一意のチャンネルID
        // ここはどこかで定数にしておくのが良さそう
        "channel_id_sample",

        // 設定に表示されるチャンネル名
        // ここは実際にはリソースを指定するのが良さそう
        "プッシュ通知",

        // チャンネルの重要度
        // 重要度によって表示箇所が異なる
        NotificationManager.IMPORTANCE_DEFAULT
    );

    // 通知時にライトを有効にする
    channel.enableLights(true);
    // 通知時のライトの色
    channel.setLightColor(Color.WHITE);
    // ロック画面での表示レベル
    channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);

    // チャンネルの登録
    manager.createNotificationChannel(channel);
}
```
また、`NotificationChannelGroup`や`setGroup`を用いてグルーピングも可能だ。

## 通知チャンネルに通知する
ここは変更点は少なく、`setChannelId`でチャンネルを指定するだけだ。

```java
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);

Resources res = getResources();
int icon = res.getIdentifier("app_icon", "drawable", this.getPackageName());
int titleId = res.getIdentifier("app_name", "string", this.getPackageName());
String applicationName = this.getString(titleId);
String message = "何かテスト";

Notification.Builder mBuilder = new Notification.Builder(this)
        .setSmallIcon(icon)
        .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), icon))
        .setContentTitle(applicationName)
        .setContentText(message)
        .setContentIntent(pendingIntent);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    mBuilder.setChannelId("channel_id_sample");
}
```

## なぜ今更Android OのPush通知の話なのか
今年の8月以降はtargetSdkVersionを26以上に上げなければ新規アプリがPlayストアに申請できなくなる。
今年の11月以降はtargetSdkVersionを26以上に上げなければ既存アプリもPlayストアに申請できなくなる。
なお、それに引き続き2019年以降は新バージョンのリリースの1年以内にはtargetSdkVersionの引き上げが必要になる。

## 参考
- [NotificationChannel  |  Android Developers](https://developer.android.com/reference/android/app/NotificationChannel)
- [Android Developers Blog: Improving app security and performance on Google Play for years to come](https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html)