flutter_local_notificationsのonSelectNotification属性でNavigatorを使うとき、contextを参照できない
結論:GlobalKey経由で「Navigator」を起動する
2022/5/7 Flutter エラー・バグ日記
ローカル通知を実装できる「flutter_local_notifications」パッケージを用いると、通知タップ時に特定の画面を開く処理を書けるのだが、「Navigator」の「push」メソッドを使おうとすると「Navigator.of(context).push」のように、「context」が必要になる。
しかし、通知タップ処理を設定する「onSelectNotification」属性は、「flutter_local_notifications」の初期化処理を行う「initialize」メソッドの引数であり、この「initialize」メソッドを、アプリ起動時にmain関数から呼び出していたため、この段階だとまだ「context」を渡せない。。。(「undefined name」のエラーになってしまう)。
buildメソッドを回して「context」を生成してから、「initialize」メソッドに渡してもよいが、状態管理にMVVMモデルを採用し、Model層に通知関係の処理(「initialize」メソッドなど)を書いていたため、View層→ViewModel層→Model層と「context」を渡していくと、とても煩雑になる。。。
調べると、こちらに全く同じ疑問を持った方からのイシュー情報があった。
コメントとして、「didChangeDependencies」を用いると「context」取得できる、という内容があるが、リプライにもあるとおり、自分も使い方がよくわからなかった。。。
ただ、本イシューの最後から、下記イシューに飛んでおり、こちらではGlobalKeyを使う方法が提案されていた。
こちらの方法は分かりやすかったので、早速、以下のようにGlobalKeyを宣言し、
// View層とModel層で共有できるようにするため、グローバルで定義 final GlobalKey<NavigatorState> navigatorKeyO = GlobalKey<NavigatorState>();
View層の「MaterialApp」の「navigatorKey」属性に上記GlobalKeyを設置。
MaterialApp( navigatorKey: navigatorKeyO,
続いて「onSelectNotification」属性のメソッドを下記のように規定したら、無事、通知タップから指定画面(下記の例では「TestScreenO」)を開くことができた。
/// initializeメソッドのonSelectNotification属性に設置するメソッド Future<void> selectNotificationO(String? payloadO) async { // GlobalKey経由で Navigator を起動する navigatorKeyO.currentState!.push( MaterialPageRoute( builder: (context) { // payloadOは、zonedScheduleメソッド(本記事では割愛)で設定する、通知から渡される値 return TestScreenO(payloadO: payloadO!); }, ), ); }
ちなみに、前述のイシューでは、「pushNamed」メソッドを使っているが、自分は使い慣れている「.push(MaterialPageRoute(builder:・・・{・・・}))」を使った。
MaterialPageRouteのbuilderに設定している「context」は、ここで生成するものなので、「undefined」のエラーにはならず、問題なかった(引数省略はできないが、「(context)」は別名称でも良いし、遷移先にcontextを渡す必要がない場合は「(_)」とすることもできる)。
リリースしたアプリ(全てFlutterで開発)
個人アプリ開発で役立ったもの
おすすめの学習教材
\超初心者向けでオススメな元Udemyの講座/
\キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/
\Gitの基礎について無料で学べる/
おすすめの学習書籍
\実用的。image_pickerに関してかなり助けられた/
\Dartの基礎文法を素早くインプットできる/