flutterで定期実行を行うのは易しくありません。
https://github.com/flutter/flutter/issues/24278
このissue(この記事の約1ヶ月前)にもある通り、flutterでは現在、両プラットフォームにおいてバックグランド実行できる機能が制限されています。この原因として、iOSの場合は特にアプリを放置しておくと勝手に終了されてしまうため、アプリの裏側でタイマーを起動しても時間が経つとなかったことにされてしまいます。androidの場合はandroid_alarm_managerというアプリが公式で出されているのでこれを使えばよいのですが、iOSは未だに公式サポートがありません。
アプリの定期実行を行うのは今の現状だとかなり厳しいと思われますが、実は定期的に通知を出すだけであればサードパーティ製ライブラリのflutter_local_notificationを使うことで解決します。このアプリはバックグラウンドに行っても通知を送ることができる通知用タイマーのようなライブラリです。
例えば毎朝8時に通知を送るサンプルです
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分後に実行
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);
・毎分実行
await flutterLocalNotificationsPlugin.periodicallyShow(0, 'repeating title',
'repeating body', RepeatInterval.EveryMinute, platformChannelSpecifics);
・毎週同じ時間に実行
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個キャンセル
await flutterLocalNotificationsPlugin.cancel(0);
・全部キャンセル
await flutterLocalNotificationsPlugin.cancelAll();
こんな感じで簡単に通知の利用ができます。
とはいえ、早く公式サポートしてくれないかなぁ...と願ってます。