Flutter: Push уведомления firebase
С PUSH уведомлениями, во Flutter, вроде бы всё и просто, но вот я провозился три дня, чтобы заставить приложение стабильно их показывать. Большая часть проблем вытекает из-за постоянно развивающейся кодовой базы Flutter, в результате чего большая часть примеров в сети — уже не рабочие.
Проблема №1
Пакет flutter_webview_plugin_ios_android, который оказался не совместим с вызовом FirebaseMessaging.onBackgroundMessage, после инициализации которого, перестали работать кэлбеки webview на переходы на другие url (GitHub Issue).
Выход: не бросаться на простой в использовании пакет, а использовать максимально популярный webview_flutter. Хотя и оный у меня заработал, только в самой последней версии — до этого были проблемы с отображением некоторых сайтов с не понятными SSL сертификатами.
Проблема №2
Вызов ensureInitialized:
1 2 3 4 5 |
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); ... FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); ... |
который у «всех работает а у меня не работает». И вызывает ошибку
1 |
Unhandled Exception: [core/duplicate-app] A Firebase App named "[DEFAULT]" already exists |
Пришлось обернуть в:
1 2 3 |
try { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); } catch (e) {} |
Проблема №3
Подобрать комбинацию пакетов Flutter и окружение Android Studion, чтобы «всё заработало». В итоге удовлетворительно заработало при используемых версия пакетов Flutter:
firebase_messaging: ^14.4.0
flutter_local_notifications: ^13.0.0
И зависимостей build.grade для Android Studio:
\android\app\build.gradle:
1 2 3 4 5 6 7 |
dependencies <strong>{ </strong>implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.yandex.android:maps.mobile:4.2.2-full' implementation 'com.google.firebase:firebase-bom:31.4.0' implementation 'com.google.firebase:firebase-messaging:23.1.2' implementation 'com.android.support:multidex:1.0.3' <strong>}</strong> |
\android\build.gradle:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
buildscript <strong>{ </strong>ext.kotlin_version = '1.6.10' repositories <strong>{ </strong>google() mavenCentral() <strong>} </strong>dependencies <strong>{ </strong>classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.15' <strong>} }</strong> |
Итак, вот текущая минимальная обвязка для работы с PUSH уведомлениями получилась:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'firebase_options.dart'; import 'permissions.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; FirebaseMessaging messaging = FirebaseMessaging.instance; Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await setupFlutterNotifications(); showFlutterNotification(message); print('Handling a background message ${message.messageId}'); } late AndroidNotificationChannel channel; bool isFlutterLocalNotificationsInitialized = false; Future<void> setupFlutterNotifications() async { if (isFlutterLocalNotificationsInitialized) {return;} channel = const AndroidNotificationChannel( 'high_importance_channel', // id 'High Importance Notifications', // title description: 'High Importance Notifications', // description importance: Importance.high, ); flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(channel); await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(alert: true, badge: true, sound: true,); isFlutterLocalNotificationsInitialized = true; } void showFlutterNotification(RemoteMessage message) { RemoteNotification? notification = message.notification; AndroidNotification? android = message.notification?.android; if (notification != null && android != null && !kIsWeb) { print("Пришло ПУШ:"); print(notification.title); flutterLocalNotificationsPlugin.show( notification.hashCode, notification.title, notification.body, NotificationDetails( android: AndroidNotificationDetails( channel.id, channel.name, channelDescription: channel.description, icon: 'launch_background', ), ), ); } } late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin; Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); // требуется для PUSH сервиса // инициализация PUSH уведомлений try { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); } catch (e) {} FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); await setupFlutterNotifications(); // получаем токен уведомлений FirebaseMessaging.instance.getToken().then((token) { print("Token: $token"); // Выплюнем токен в консольку }); runApp(MyApp()); } ... ... @override Widget build(BuildContext context) { String? _token; String? initialMessage; bool _resolved = false; FirebaseMessaging.instance.getInitialMessage().then( value) => () { _resolved = true; initialMessage = value?.data.toString(); }, ); FirebaseMessaging.onMessage.listen(showFlutterNotification); // показ PUSH уведомлений при открытом приложении FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { print('A new onMessageOpenedApp event was published!'); }); .... .... |