🌴

Flutterで通知センターの通知をすべてクリアする

2021/09/09に公開

Flutterで通知機能を開発しているときに通知センターに残っている通知を削除する方法がわからなくて困ったので、その解決方法を書き残しておきます。

通知はタップしてアプリを開いた場合には通知は削除されますが、ユーザーが手動でアプリを開いた場合には通知センターに残ってしまいます。

Flutterからは通知のクリアはできなさそうなので、PlatformChannelという仕組みを使って通知を全てクリアするコードをAndroid/iOSのネイティブで書いてFlutterで呼び出す方法で解決しました。(もっと簡単な方法だったりpackageがあれば教えて下さい!)

PlatformChannelについての詳しい解説は今回は書かないので他の記事を参考にして見てください。
Flutterの公式サイトの記事がわかりやすくておすすめです。
「[Writing custom platform-specific code]」(https://flutter.dev/docs/development/platform-integration/platform-channels)

実装手順

PlatformChannelではチャネル名と関数名はFlutterで使うものとAndroid/iOSで同じものを使う必要があるのでわかる名前にしてください。

チャネル名 関数名
com.example/notifications clearAllNotifications
今回はこのように名前をつけました。

チャネル名は何でも良いですが、公式サイトでは「パッケージ名/メソッド名」のようになっていたので同じような形式の名前にしました。

Flutter側の実装

まずはFlutterでネイティブの関数を呼び出す処理を書いておきます。
Flutter側でネイティブの関数を呼び出すにはMethodChannelを利用します。

main.dart
Future<void> clearAllNotifications() async {
  const channel = MethodChannel('com.example/notifications');

  try {
    await channel.invokeMethod('clearAllNotifications');
  } on PlatformException catch (error) {
    print(error);
  }
}

Android側の実装

次にAndroid側に通知をクリアする関数を追加します。

MainActivity.kt
private fun clearAllNotifications() {
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.cancelAll()
}

MainActivityクラスのconfigureFlutterEngine()メソッド内でMethodChannelを呼び出しsetMethodCallHandlerにFlutterで呼び出したい関数を追加します。

MainActivity.kt
package com.example

import android.app.NotificationManager
import android.content.Context
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example/notifications"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
        call, result ->
            if (call.method == "clearAllNotifications") {
                clearAllNotifications()
            }
        }
    }
}

iOS側の実装

iOS側で通知をクリアする関数を追加します。
iOSはバッジに数値が表示されるので通知のクリアと一緒に、バッジの数値も0にしておきます。

AppDelegate.swift
private func clearAllNotifications(_ application: UIApplication) {
    application.applicationIconBadgeNumber = 0
    UNUserNotificationCenter.current().removeAllDeliveredNotifications()
}

FlutterMethodChannelを呼び出しsetMethodCallHandlerにFlutterで呼び出したい関数を追加します。

AppDelegate.swift
import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
    let notificationsChannel = FlutterMethodChannel(name: "com.example/notifications", binaryMessenger: controller.binaryMessenger)
    
    notificationsChannel.setMethodCallHandler { call, result in
        guard call.method == "clearAllNotifications" else {
            result(FlutterMethodNotImplemented)
            return
        }
        self.clearAllNotifications(application)
    }

    GeneratedPluginRegistrant.register(with: self)
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

さいごに

以上でFlutterで通知センターの通知を全てクリアする関数を実行できるようになりました。
あとはinitStateなどで作成した関数を呼べば通知をクリアできるようになります。

Discussion