Flutter flutter_local_notifications 当点击通知时,打开特定页面

问题描述 投票:0回答:1

因此,在我的 flutter 应用程序中,当用户单击通知时,它应该将他们带到特定页面。但是,它目前无法使用,并且 Navigator.push 也无法工作,因为它位于 Widget 构建之外。

这是我的 main.dart 文件:

import 'dart:async';
import 'dart:io';

// import 'package:fetch_client/fetch_client.dart'
// import 'package:fetch_client/fetch_client.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
// import 'package:go_router/go_router.dart';
import 'package:shared_preferences/shared_preferences.dart';
// import 'package:ticket_wallet/pages/login_page.dart';

import 'package:pocketbase/pocketbase.dart';
// import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
import 'dart:developer';
// import 'dart:io' show Platform;
// import 'package:flutter/foundation.dart' show TargetPlatform;
import 'package:flutter/foundation.dart' show kIsWeb, kReleaseMode;
import 'package:ticket_wallet/data/ticket.dart';
import 'package:ticket_wallet/extensions/locale_ext.dart';
import 'package:ticket_wallet/l10n/en_NL_intl.dart';
import 'package:ticket_wallet/logger/tw_logger.dart';
import 'package:ticket_wallet/pages/login_page.dart';
// import 'package:url_launcher/url_launcher.dart';
import 'package:ticket_wallet/fetchClient/custom_platform.dart';
import 'package:ticket_wallet/pages/ticket_view_page.dart';

import 'pages/ticket_wallet_app.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import 'package:flutter_timezone/flutter_timezone.dart';

late PocketBase pb;
bool online = false;
TwLogger logger = TwLogger(level: Level.trace);
Locale? currentLanguage;
Ticket? notifTicket = null;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await _configureLocalTimeZone();
  FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  final NotificationAppLaunchDetails? notificationAppLaunchDetails =
      await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();

  log('notification app launch details: $notificationAppLaunchDetails');
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
  const AndroidInitializationSettings initializationSettingsAndroid =
      AndroidInitializationSettings('tw_logo');
  final DarwinInitializationSettings initializationSettingsDarwin =
      DarwinInitializationSettings(
          onDidReceiveLocalNotification: onDidReceiveLocalNotification());
  final LinuxInitializationSettings initializationSettingsLinux =
      LinuxInitializationSettings(defaultActionName: 'Open notification');
  final InitializationSettings initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsDarwin,
      macOS: initializationSettingsDarwin,
      linux: initializationSettingsLinux);
  await flutterLocalNotificationsPlugin.initialize(initializationSettings,
      onDidReceiveNotificationResponse:
          (NotificationResponse notificationResponse) async {
    log('notification response: ${notificationResponse.payload}');
    String ticketID = notificationResponse.payload!;
    var tempPb = await _notificationPb();
    log('userid: ${tempPb.authStore.model.id}');
    RecordModel ticketRM = await tempPb.collection("ticket").getOne(ticketID);
    Ticket ticket = Ticket.fromRecord(ticketRM);

    // Push the TicketWalletApp onto the navigation stack and remove all previous routes
    notifTicket = ticket;
    log('notifTicket: $notifTicket');
  });
  runApp(const App());
}

Future onDidReceiveNotificationResponse(
    NotificationResponse notificationResponse) async {
  log('notification response: ${notificationResponse.payload}');
  String ticketID = notificationResponse.payload!;
  var tempPb = await _notificationPb();
  log('userid: ${tempPb.authStore.model.id}');
  RecordModel ticketRM = await tempPb.collection("ticket").getOne(ticketID);
  Ticket ticket = Ticket.fromRecord(ticketRM);

  // Push the TicketWalletApp onto the navigation stack and remove all previous routes
  notifTicket = ticket;
  log('notifTicket: $notifTicket');
}

onDidReceiveLocalNotification() {}

Future<void> _configureLocalTimeZone() async {
  if (kIsWeb || Platform.isLinux) {
    return;
  }
  tz.initializeTimeZones();
  final String? timeZoneName = await FlutterTimezone.getLocalTimezone();
  tz.setLocalLocation(tz.getLocation(timeZoneName!));
}

Future<PocketBase> _notificationPb() async {
  final prefs = await SharedPreferences.getInstance();
  final connectivityResult = await (Connectivity().checkConnectivity());

  log('connectivity: $connectivityResult');

  final store = AsyncAuthStore(
    save: (String data) async => prefs.setString('auth', data),
    initial: prefs.getString('auth'),
  );
  var url = 'https://api.ticketwallet.eu';

  var fetchClientFactory = FetchClientFactory();
  log("http client factory: $fetchClientFactory");
  log("create: ${fetchClientFactory.create()}");
  var tempPb = PocketBase(
    url,
    authStore: store,
    httpClientFactory: kIsWeb ? () => fetchClientFactory.create() : null,
  );

  return tempPb;
}

class App extends StatefulWidget {
  const App({super.key});

  @override
  State<App> createState() => _AppState();

  static _AppState of(BuildContext context) {
    return context.findAncestorStateOfType<_AppState>()!;
  }
}

class _AppState extends State<App> {
  final ValueNotifier<Locale> localeNotifier =
      ValueNotifier(const Locale('en', 'US'));

  // final router = GoRouter(
  //   routes: [
  //     GoRoute(
  //       path: '/add_ticket_link',
  //       builder: (context, state) => Scaffold(
  //         appBar: AppBar(
  //           title: const Text("test"),
  //         ),
  //       ),
  //     ),
  //   ],
  // );

  void setLocale(Locale locale) {
    logger.i('New Language: ${locale.toLanguageTag()}');
    currentLanguage = locale;
    localeNotifier.value = locale;
  }

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

  Future<PocketBase> _pocketbaseSetup(BuildContext context) async {
    // final test = await ZxinQrScanner().startQrScanner();
    // log('test native code: $test');
    final prefs = await SharedPreferences.getInstance();
    final connectivityResult = await (Connectivity().checkConnectivity());

    log('connectivity: $connectivityResult');

    final store = AsyncAuthStore(
      save: (String data) async => prefs.setString('auth', data),
      initial: prefs.getString('auth'),
    );
    var url = 'https://api.ticketwallet.eu';
    // ignore: use_build_context_synchronously
    // var platform = Theme.of(context).platform;
    // if (platform == TargetPlatform.android) {
    //   log('android');
    //   url = 'http://10.0.2.2:8090';
    // } else {
    //   log('other');
    //   url = 'http://127.0.0.1:8090';
    // }
    var fetchClientFactory = FetchClientFactory();
    log("http client factory: $fetchClientFactory");
    log("create: ${fetchClientFactory.create()}");
    var tempPb = PocketBase(
      url,
      authStore: store,
      httpClientFactory: kIsWeb ? () => fetchClientFactory.create() : null,
    );

    log("tempP b: $tempPb");
    try {
      await tempPb.health.check().catchError((e) {
        logger.e("Health check failed: $e");
        throw e;
      });
      online = true;
    } catch (e) {
      if (connectivityResult == ConnectivityResult.none) {
        online = false;
        WidgetsBinding.instance.addPostFrameCallback(
          (timeStamp) {
            if (!online) {
              _showPopup(context, 'No Internet Connection',
                  'You can still view your tickets, but you need an internet connection to add new tickets, view archived tickets or update your account information.\n\nIf you are reconnected, please restart the app to enable these features.');
            }
          },
        );
      } else {
        online = false;
        WidgetsBinding.instance.addPostFrameCallback(
          (timeStamp) {
            if (!online) {
              _showPopup(context, 'Server Not Reachable',
                  'The server is not reachable. You can still view your tickets, but you need to wait until the server is reachable again to add new tickets, view archived tickets or update your account information.\n\nIf the server is reachable again, please restart the app to enable these features.');
            }
          },
        );
      }
      logger.e(e.toString());
      online = false;
    }

    try {
      logger.d('getting user');
      final user =
          await tempPb.collection("users").getOne(tempPb.authStore.model.id);
      logger.d('user: $user');
    } catch (e) {
      logger.e("ClientException: $e");
      logger.e('User not found');
      tempPb.authStore.clear();
      WidgetsBinding.instance.addPostFrameCallback(
        (timeStamp) {
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(
              builder: (context) => const LoginPage(),
            ),
          );
        },
      );
    }
    // _getLocale(tempPb).then((value) {
    //   setLocale(value);
    // });
    await initializeDateFormatting();

    logger.d('tempPb: $tempPb');
    return tempPb;
  }

  void _showPopup(BuildContext context, String title, String message) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: Text(message),
          actions: <Widget>[
            TextButton(
              child: const Text('OK'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    log('notifTicketBuild: $notifTicket');
    return ValueListenableBuilder<Locale>(
      valueListenable: localeNotifier,
      builder: (context, localeValue, child) {
        // logger.d(
        //     'Language from ValueListenableBuilder: ${localeValue.countryCode} ${localeValue.toLanguageTag()}, ${localeValue.languageCode}, ${localeValue.countryCode}, ${localeValue.scriptCode}');
        return MaterialApp(
          title: 'Ticket Wallet',
          theme: ThemeData(
            scaffoldBackgroundColor: const Color(0xFFfaf9fe),
            colorScheme: ColorScheme.fromSeed(
              seedColor: const Color.fromARGB(255, 254, 179, 199),
            ),
            useMaterial3: true,
          ),
          localizationsDelegates: const [
            ...AppLocalizations.localizationsDelegates,
            EnNlMaterialLocalizationsDelegate.delegate
          ],
          supportedLocales: AppLocalizations.supportedLocales,
          locale: localeValue,
          home: Builder(
            builder: (BuildContext context) {
              return FutureBuilder(
                future: _pocketbaseSetup(context),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    log('snapshot: ${snapshot.data}');
                    if (snapshot.data == null) {
                      logger.f('No connection to server');
                      return Scaffold(
                        body: Center(
                          child: Text(
                              AppLocalizations.of(context)!.noConnectionFatal),
                        ),
                      );
                    }
                    pb = snapshot.data as PocketBase;
                    // if (!online) {
                    //   return const Scaffold(
                    //     body: Center(
                    //       child: Text('No connection to server'),
                    //     ),
                    //   );
                    // }

                    return pb.authStore.isValid
                        // ? const TicketWalletApp()
                        ? notifTicket != null
                            ? TicketViewPage(ticket: notifTicket!)
                            : const TicketWalletApp()
                        : const LoginPage();
                  }
                  return const Scaffold(
                    body: Center(
                      child: CircularProgressIndicator(),
                    ),
                  );
                },
              );
            },
          ),
        );
      },
    );
  }
}

我该如何解决这个问题,以便用户可以转到 TicketViewPage(ticket:ticket)。 onDidRecieveNotificationResponse 内的所有代码都有效。我还希望当用户单击 TicketViewPage 上的小后退箭头时,它会返回到正常主页(TicketWalletApp())

我已经尝试过使用全局密钥,但这也不起作用。

flutter flutter-local-notification
1个回答
0
投票

我希望这可以帮助你!

首先你可以使用NavigatorKey推送到你想要的页面:

navigatorKey.currentState?.pushNamed(notificationResponse.payload!);

notificationResponse.payload 是:你想要的路由器名称页面。

您可以将其放入 onNotificationTap 函数中:

enter image description here

ontap函数的调用方式如下: enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.