С PUSH уведомлениями, во Flutter, вроде бы всё и просто, но вот я провозился три дня, чтобы заставить приложение стабильно их показывать. Большая часть проблем вытекает из-за постоянно развивающейся кодовой базы Flutter, в результате чего большая часть примеров в сети — уже не рабочие.
Проблема №1
Пакет flutter_webview_plugin_ios_android, который оказался не совместим с вызовом FirebaseMessaging.onBackgroundMessage, после инициализации которого, перестали работать кэлбеки webview на переходы на другие url (GitHub Issue).
Выход: не бросаться на простой в использовании пакет, а использовать максимально популярный webview_flutter. Хотя и оный у меня заработал, только в самой последней версии — до этого были проблемы с отображением некоторых сайтов с не понятными SSL сертификатами.
Проблема №2
Вызов ensureInitialized:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
... FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
...
который у «всех работает а у меня не работает». И вызывает ошибку
Unhandled Exception: [core/duplicate-app] A Firebase App named "[DEFAULT]" already exists
Пришлось обернуть в:
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:
dependencies {
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'
}
\android\build.gradle:
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
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'
}
}
Итак, вот текущая минимальная обвязка для работы с PUSH уведомлениями получилась:
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!');
});
....
....