LoginSignup
51
30

More than 5 years have passed since last update.

FlutterでローカルからNotification

Posted at

はじめに

Push通知ではなくアプリケーション上から通知を出すためにどうするのか調べました。

環境

Android Studio
Flutter1.0

今回はiOSを表示させる環境用意しなかったので、Androidのみに言及しています。
iOSだと動かない箇所が出てくると思います。

Dependencyの追加

Flutterには通知を簡単に実現するためのflutter_local_notificationsが用意されているので、それをpubspec.yamlに追加してあげます。
バージョンがまだ0.5.1なので、バージョンアップ後に動かなくなる可能性がありますので、この先読む方はご注意ください。

dependencies:
  flutter_local_notifications: ^0.5.1

アプリ側のトリガーを元に通知を行う

アプリ側のイベントを契機に通知を行う方法について見ていきます。

まずは必要となるpackageをimportしてあげます。

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

次からはState<T>内部に実装する必要があるため、必要な実装は先に行なっておきます。
私はFlutterを勉強しながら継ぎ足し製法でソースを拡充させているため、それを使います。
なお、色んなコードが入ってきてしまっているため、本ページでは全体のコードはのせませんがご了承ください。

State<T>の実装が完了したらメンバ変数としてFlutterLocalNotificationsPluginを追加します。
様々なサンプルだとメンバ変数になってませんが、これを使って実際の通知を行う必要があるため、メンバ変数としないと無理です。

FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
NotificationDetails platformChannelSpecifics;

まずは通知を行うための初期化処理を行います。
初期化はState<T>initState内に実装します。
ここでの注意点はサンプルをコピーしただけではエラーとなるため、実装が必要になる部分があることです。

また、実際の通知する際に使用するオブジェクトもここで生成しておいた方が良いです。
AndroidNotificationDetailsのコンストラクタはAndroid8.0以上のチャンネル機能用の通知用があるので、8.0以上を目的で作る場合は必須となります。

  @override
  void initState() {
    super.initState();
    _refresh();

    flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
    var initializationSettingsAndroid = AndroidInitializationSettings('app_icon');
    var initializationSettingsIOS = IOSInitializationSettings(
        onDidReceiveLocalNotification: onDidReceiveLocationLocation);
    var initializationSettings = InitializationSettings(
        initializationSettingsAndroid, initializationSettingsIOS);
    flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: onSelectNotification);

    var androidPlatformChannelSpecifics = AndroidNotificationDetails(
        'your channel id', 'your channel name', 'your channel description',
        importance: Importance.Max, priority: Priority.High);
    var iOSPlatformChannelSpecifics = IOSNotificationDetails();
    platformChannelSpecifics = NotificationDetails(
        androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
  }

そして必要な箇所を追加します。
onDidReceiveLocationLocationはiOS用のようなので、本ページに必要ない実装ですがなぜか実装してあったので、合わせてのせておきます。

onSelectNotificationについてが今回重要な点となります。
このメソッドは通知をクリックした際に呼ばれるイベントとなっているため、その動作について実装が必要となります。

今回はNavigator.pushを使用して別のWidgetを呼び出してます。
そもそもNotificationからの起動時は今の画面の次の画面として起動するか、一から起動してから次の画面として起動するかという動作をする感じなので、Future.syncなどからWidgetを作っても現状では動作がどう変わるかが良くわかりませんでした。

何かパラメータを渡す際は引数のpayloadを使って行う必要があります。
ここはString固定なので、複雑なデータを渡す際はJsonなんかで渡す必要があります。

  Future onSelectNotification(String payload) async {
    await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => Text(payload),
        maintainState : false,),
    );
  }

  Future onDidReceiveLocationLocation(
      int id, String title, String body, String payload) async {
    await showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text(title),
            content:  Text(body),
            actions: <Widget>[
              FlatButton(
                child: Text(payload),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        }
    );
  }

最後に実際に通知を行う箇所です。
initStateで生成したオブジェクトを使用して通知します。
onSelectNotificationに渡ってくるpayloadpushpayloadで設定したものと同じものなので、通知後にパラメータを渡したい場合はここで設定してあげてください。

  Future _onNotification() async {
    await flutterLocalNotificationsPlugin.show(
        0, 'plain title', 'plain body', platformChannelSpecifics,
        payload: 'item id 2');
  }

これで通知できるようになりました。

通知をスケジューリングする

アプリケーショントリガーですぐに実行することが出来るようになりましたが、そのトリガーを元にすぐに出さずにあとで出すようにしたい場合にスケジューリングさせることが出来ます。
その場合にどうするべきかを見ていきます。

AndroidManifest.xmlの修正

スケジューリングされた通知を行うのにAlarmManager使用しているらしく、それが使用できるようにManifestを修正してあげる必要があります。
修正内容は公式書いてあるので、その通りに追加してあげます。

AlermManagerを使用している場合はアプリが起動していなくても起動してくれるので、停止状態でも出せるようになります。

なお、com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiverを追加するとAndroid Studio上でエラーになりますが、特に問題ないので無視してください。

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>
<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />

dartファイル

コード的にはscheduleメソッドを使用して、時間を指定あげるだけの違いとなります。

  Future _onNotification() {
    return flutterLocalNotificationsPlugin.schedule(
        0, 'plain title', 'plain body', DateTime.now().add(Duration(seconds: 5)),
        platformChannelSpecifics, payload: 'item id 2');
  }

繰り返し通知

Manifestの修正はしておいてください。
コード的にはperiodicallyShowを使えば実現できます。
指定するRepeatIntervalはenumなので、簡単に繰り返す期間の指定が可能です。

  Future _onNotification() {
    return flutterLocalNotificationsPlugin.periodicallyShow(
        0, 'plain title', 'plain body', RepeatInterval.EveryMinute,
        platformChannelSpecifics, payload: 'item id 2');
  }

特定の時間で繰り返す

毎日定時に起動させたい場合はshowDailyAtTimeを使用します。

  Future _onNotification() {
    var date = DateTime.now().add(Duration(seconds: 5));
    return flutterLocalNotificationsPlugin.showDailyAtTime(
        0, 'plain title', 'plain body', Time(date.hour, date.minute, date.second),
        platformChannelSpecifics, payload: 'item id 2');
  }

特定の曜日、特定の時間で繰り返す

特定の曜日も追加したい場合はshowWeeklyAtDayAndTimeで曜日と時間を指定します。

  Future _onNotification() {
    var date = DateTime.now().add(Duration(seconds: 5));
    return flutterLocalNotificationsPlugin.showWeeklyAtDayAndTime(
        0, 'plain title', 'plain body', Day.Sunday, Time(date.hour, date.minute, date.second),
        platformChannelSpecifics, payload: 'item id 2');
  }

おわりに

本当は起動時にNotificationを設定する方法も合わせて見ていたのですが、没としました。
今の所は状態変化のタイミングに合わせて通知設定をするというのが一番良いです。
面倒だから起動と同時に設定できるようにしたいなーと思ってたんですが、しょうがないので別の方法考えます。

51
30
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
30