flutterで定期通知を行う

flutterで定期実行を行うのは易しくありません。
https://github.com/flutter/flutter/issues/24278

このissue（この記事の約1ヶ月前）にもある通り、flutterでは現在、両プラットフォームにおいてバックグランド実行できる機能が制限されています。この原因として、iOSの場合は特にアプリを放置しておくと勝手に終了されてしまうため、アプリの裏側でタイマーを起動しても時間が経つとなかったことにされてしまいます。androidの場合は[android_alarm_manager](https://pub.dartlang.org/packages/android_alarm_manager)というアプリが公式で出されているのでこれを使えばよいのですが、iOSは未だに公式サポートがありません。

アプリの定期実行を行うのは今の現状だとかなり厳しいと思われますが、実は定期的に通知を出すだけであればサードパーティ製ライブラリの[flutter_local_notification](https://pub.dartlang.org/packages/flutter_local_notifications)を使うことで解決します。このアプリはバックグラウンドに行っても通知を送ることができる通知用タイマーのようなライブラリです。


例えば毎朝8時に通知を送るサンプルです

```dart

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

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

    var initializationSettingsAndroid =
        new AndroidInitializationSettings('app_icon');
    var initializationSettingsIOS = new IOSInitializationSettings();
    var initializationSettings = new InitializationSettings(
        initializationSettingsAndroid, initializationSettingsIOS);
    flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
    flutterLocalNotificationsPlugin.initialize(initializationSettings);
  }

  // notification
  Future _showNotification() async {
    var time = new Time(8, 0, 0);
    var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
        'your channel id', 'your channel name', 'your channel description',
        importance: Importance.Max, priority: Priority.High);
    var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
    var platformChannelSpecifics = new NotificationDetails(
        androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
    await flutterLocalNotificationsPlugin.showDailyAtTime(
      0,
      'Timer',
      'You should check the app',
      time,
      platformChannelSpecifics,
      payload: 'Default_Sound',
    );
  }

  void _setSchedular() {
    _showNotification();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              'Hello World',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _setSchedular,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

```

これ、ほぼほぼデフォルトのアプリを継承したものなのですがこんな感じで簡単に利用できます。
ここで一回起動するだけで毎朝8時に通知が来ます。

このflutterLocalNotificationsPlugin.showDailyAtTimeの部分を変えれば色々な定期通知が可能で
・X分後に実行

```dart
var scheduledNotificationDateTime =
        new DateTime.now().add(new Duration(seconds: 5));
var androidPlatformChannelSpecifics =
    new AndroidNotificationDetails('your other channel id',
        'your other channel name', 'your other channel description');
var iOSPlatformChannelSpecifics =
    new IOSNotificationDetails();
NotificationDetails platformChannelSpecifics = new NotificationDetails(
    androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.schedule(
    0,
    'scheduled title',
    'scheduled body',
    scheduledNotificationDateTime,
    platformChannelSpecifics);

```


・毎分実行

```dart
await flutterLocalNotificationsPlugin.periodicallyShow(0, 'repeating title',
    'repeating body', RepeatInterval.EveryMinute, platformChannelSpecifics);
```

・毎週同じ時間に実行

```dart
await flutterLocalNotificationsPlugin.showWeeklyAtDayAndTime(
    0,
    'show weekly title',
    'Weekly notification shown on Monday at approximately ${_toTwoDigitString(time.hour)}:${_toTwoDigitString(time.minute)}:${_toTwoDigitString(time.second)}',
    Day.Monday,
    time,
    platformChannelSpecifics);
```

といったことができます。
キャンセルする場合は以下の関数を呼んでください。

・1個キャンセル

```dart
await flutterLocalNotificationsPlugin.cancel(0);
```

・全部キャンセル

```dart
await flutterLocalNotificationsPlugin.cancelAll();
```

こんな感じで簡単に通知の利用ができます。

とはいえ、早く公式サポートしてくれないかなぁ...と願ってます。