カテゴリー: Android

Androidでのローカルプッシュ通知実装

はじめに

こんにちは。カイザーです。今回は、Androidでのローカルプッシュ通知をするために、WorkManagerを使用した実装を紹介します。

WorkManagerとは?

Jetpackの機能の1つで、簡単に定期的もしくは単発のバックグラウンドタスクを定義し、実行することができます。
実際には、JobScheduler、FirebaseJobDispatcher、AlarmManagerのいずれかを、OSのバージョンや、Google Play Servicesのインストール状況によって使い分けてくれるものです。

WorkManagerの導入

app/build.gradleに以下追加します。

dependencies {
  ・・・
    def work_version = "2.2.0"
    implementation "androidx.work:work-runtime-ktx:$work_version"
}

この後の実装をした際、以下のエラーが出る場合は、JVM target 1.8に変更する必要があります。

Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option

その場合は、以下を追加してください。

android {
  ・・・
    compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Android Studio側にも同様の設定項目がありますが、記事執筆時点のAndroid Studio 3.5では、上記設定を記載しないと反映されません。

実装例

主な登場人物は、Worker、WorkManager、WorkRequestの3つです。

Workerは実際にバックグラウンドタスクとして呼ばれ、WorkRequestで実行方法を指定し、WorkManagerエンキューする流れになります。

Workerの実装

WorkerManagerに登録し、実際にバックグラウンドタスクとして動作するクラスを実装します。
今回は、ここでNotificationChannelにプッシュ通知する実装をします。

class LocalNotificationWorker(context: Context, workerParams: WorkerParameters) :
    Worker(context, workerParams) {
    override fun doWork(): Result {
        val pendingIntent = PendingIntent.getActivity(applicationContext,
            0,
            Intent(applicationContext, MainActivity::class.java), PendingIntent.FLAG_ONE_SHOT)

        val notification = NotificationCompat.Builder(applicationContext, "default")
            .setContentTitle(inputData.getString("title")) // enqueue元から渡されたタイトルテキストを通知にセット
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentIntent(pendingIntent)
            .build()

        NotificationManagerCompat.from(applicationContext).notify(1, notification)

        return Result.success()
    }
}

inputDataは、Workerをエンキューする時にあらかじめデータを渡され、実行時に使用可能なプロパティです。今回は、プッシュ通知のtitleに表示するようにしています。

OneTimeWorkRequestBuilderの実装

OneTimeRequestBuilderは、Workerを1回だけ動作させるリクエストです。

val inputData = Data.Builder().putString("title", "単発メッセージ").build()
val workRequest = OneTimeWorkRequestBuilder<LocalNotificationWorker>()
     .setInitialDelay(5, TimeUnit.SECONDS)
    .setInputData(inputData)
    .build()
WorkManager.getInstance(this).enqueue(workRequest)

コンストラクタのGenericksでWorkerの型を指定します。

setInitialDelayで、Workerの実行遅延時間を設定できます。これにより、相対的にプッシュ通知を表示したい時間を設定できます。

PeriodicWorkRequestBuilderの実装

PeriodicWorkRequestBuilderは、Workerを定期実行させるリクエストです。

 val inputData = Data.Builder().putString("title", "繰り返しメッセージ").build(

// 15分ごとに、5分以内に実行する 
val workRequest = PeriodicWorkRequestBuilder<LocalNotificationWorker>(15, TimeUnit.MINUTES, 5, TimeUnit.MINUTES)
     .setInputData(inputData)
     .build()
WorkManager.getInstance(this).enqueue(workRequest)

こちらは、コンストラクタで、リピート間隔を指定する必要があります。(第1、第2引数)

しかし、これだけでは確実に定期実行される訳ではありません。AndroidがDozeモードになっていると、実行されません。

そこで、実行時間(リピートする際に、何分以内に実行すべきか)を指定することで、確実に実行することができます。(第3、第4引数)

注意点としては、PeriodicWorkRequestでは、時間指定に制限があります。

リピート間隔は15分以上、実行時間は5分以上とする必要があります。これを満たしていないと、エンキューの際に以下ログと共に、Workerが実行されないので注意してください。

W/WM-WorkSpec: Interval duration lesser than minimum allowed value; Changed to 900000
2019-09-29 22:46:18.255 20701-20701/
W/WM-WorkSpec: Flex duration lesser than minimum allowed value; Changed to 300000

NotificationChannelの作成

ローカルプッシュ通知用のNotificationChannelを作成します。

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            return
        }
        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val channel = NotificationChannel("default", "Default", NotificationManager.IMPORTANCE_DEFAULT)

        channel.description = "Local Notification Sample"
        manager.createNotificationChannel(channel)

これは、エンキューするまでには実行しておいた方が良いでしょう。

これで完了です。

プッシュ通知が表示されました。

さいごに

iOS は割と簡単に実装できるローカルプッシュ通知ですが、Androidでは全く異なる概念であることが分かりました。

バックグラウンドの実行制限も受けるため、ローカルプッシュ実装時にはその辺りの制約にも気をつけたいですね。

おすすめ書籍

カイザー

シェア
執筆者:
カイザー

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前