Flutterアプリでネイティブ処理をバックグラウンドで動かした時に躓いたことのメモです。
前提
※発生環境
Flutter (Channel beta, v1.13.6, on Mac OS X 10.15.2 19C57, locale ja-JP)
Android 9
iOS 13
公式での概要
https://flutter.dev/docs/development/packages-and-plugins/background-processes
上記公式がおすすめしている詳細とサンプル
https://medium.com/flutter/executing-dart-in-the-background-with-flutter-plugins-and-geofencing-2b3e40a1a124
コールバックで可能なこと
コールバック自体はbackground isolateで実行されるので、main isolateで動いてる画面等が直接参照することはできません。ですが、ReceiverPort/SenderPortを使うことでbackground isolateからmain isolateへデータを送信することができます。
static String sendPortName = "myapp_send_port_name";
//background isolateで実行される。実際の使い方は上のサンプルを参照
void callback(data) {
//background isolateからmain isolateにデータを送る
final SendPort send = IsolateNameServer.lookupPortByName(sendPortName);
send?.send(data);
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_initPort();
}
Future<void> _initPort() async {
_rPort = ReceivePort();
final _sPort = _rPort.sendPort;
// register~は上書き更新できないので以前のStateが作成したものを消しておく
IsolateNameServer.removePortNameMapping(sendPortName);
IsolateNameServer.registerPortWithName(
_sPort, sendPortName);
// background isolateからデータを受け取って画面に反映
_rPort.listen((data) {
setState(() {
//dataを_MyAppStateに反映させる
});
});
}
@override
Widget build(BuildContext context) {
//ボタンタップしたら何かのバックグラウンド処理を開始するような画面
}
}
コールバックで不可能だったこと
MethodChannelを使ったネイティブ実行ができませんでした(MissingPluginExceptionがthrowされる)、つまりpluginが使えません。実際に以下を試したが無理でした。
- flutter_local_notificationsを使ってデータをローカル通知で表示する。
- sqfliteを使ってデータを格納する
- shared_preferencesを使ってデータを格納する
これらを実行したければ、background isolateからmain isolateにデータを渡してそちらでやるしかないようです。
main isolateが死んでたらどうする?
例えばAndroidでマルチタスク画面からアプリを上スワイプで消したとします。この時、background isolateは生きてますが、main isolateは消えます(知識が不正確なのでこの表現で正しいか怪しい)、明示的にこの動作をしなくてもOSの都合によって同じ状態になることもあるでしょう。この場合、main isolate側に記述した処理は当然実行されません。
対応方法としては、callbackではなくネイティブ側に該当の処理(通知、DB保存etc)を個別に書くしかないのではと考えています(まだ試していない)。flutterのplugin機能で共通API化したはずの機能を再度ベタ書きするという悲しみ。。。