I need to implement Cloud Messaging in my Flutter app.
For now the app can receive and show Push Notifications depending on the app status as follows:
App Status: Started and in foreground
Android: OK
iOS: not OK
App Status: Started and in background
Android: OK
iOS: OK
App Status: Closed
Android: not OK
iOS: OK
I will put here my current code for the app:
main.dart
///STREAM QUE CONTROLA LA RECEPCION DE MENSAJES CUANDO LA APP ESTA CERRADA O EN BACKGROUND
Future<void> backgroundHandler(RemoteMessage message) async{
//INICIALIZAMOS FIREBASE
await Firebase.initializeApp();
print(message.data.toString());
print(message.notification!.title);
}
Future<void> main() async {
//PERMITIR EL USO DE LIBRERIAS EXTERNAS QUE NECESITEN INTERACTUAR CON EL ARBOL DE WIDGETS
WidgetsFlutterBinding.ensureInitialized();
//INICIALIZACION DE EASYLOCALIZATION (TRADUCCION DE LA UI A EN, CA, ES)
await EasyLocalization.ensureInitialized();
//INICIALIZAMOS FIREBASE
await Firebase.initializeApp();
//INICIALIZAMOS EL STREAM PARA PODER RECIBIR MENSAJES CUANDO LA APP ESTE CERRADA O EN BACKGROUND
FirebaseMessaging.onBackgroundMessage(backgroundHandler);
DarkThemeProvider themeChangeProvider = DarkThemeProvider();
runApp(EasyLocalization(
path: "idiomas",
fallbackLocale: Locale("es", "ES"),
saveLocale: true,
supportedLocales: [
Locale("en", "EN"),
Locale("es", "ES"),
Locale("ca", "CA")
],
child: MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) {
return themeChangeProvider;
}),
ChangeNotifierProvider(create: (_) => UsuarioProvider()),
ChangeNotifierProvider(create: (_) => EmpresaProvider()),
ChangeNotifierProvider(create: (context) => ApplicationBloc())
],
child: Consumer<DarkThemeProvider>(builder: (context, themeData, child) {
return MaterialApp(
theme: Styles.themeData(themeChangeProvider.darkTheme, context),
routes: {
"noticias": (_) => MyHomePage(currentIndex: 0,),
"avisos": (_) => MyHomePage(currentIndex: 1,),
"tareas": (_) => MyHomePage(currentIndex: 2,),
"perfil": (_) => MyHomePage(currentIndex: 3,),
},
home: MyApp());
}),
)));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String? token = " ";
DarkThemeProvider themeChangeProvider = DarkThemeProvider();
void getCurrentAppTheme() async {
themeChangeProvider.darkTheme =
await themeChangeProvider.darkThemePreferences.getTheme();
}
Future<void>_init() async{
if(Platform.isIOS){
final settings = await FirebaseMessaging.instance.requestPermission();
if(settings.authorizationStatus == AuthorizationStatus.authorized){}
}
else
{}
}
@override
void initState() {
getCurrentAppTheme();
super.initState();
//COMPROBAMOS LA PLATAFORMA
if(Platform.isIOS){
//SOLICITAMOS PERMISOS A IOS PARA RECIBIR PUSH
_init();
}
//INICIALIZAMOS LOCAL NOTIFICATION SERVICE
LocalNotificationService.initialize(context);
//DEJAMOS PREPARADA LA APP PARA RECIBIR UNA PUSH Y ABRIRLA EN EK CASO DE QUE LA APP ESTE CERRADA
FirebaseMessaging.instance.getInitialMessage().then((message) {
if(message != null){
final routeFromMessage = message.data["route"];
Navigator.of(context).pushNamed(routeFromMessage);
}
});
///CON LA APP ACTIVA SE EJECUTA ESTA STREAM PARA OBTENER LOS DATOS DE LA PUSH
FirebaseMessaging.onMessage.listen((message) {
if(message.notification != null){
print(message.notification!.body);
print(message.notification!.title);
}
LocalNotificationService.display(message);
});
///CON LA APP ABIERTA PERO EN SEGUNDO PLANO Y EL USUARIO HACE CLICK
///SOBRE LA PUSH, LA APP SE REABRE ABRIENDO LA PANTALLA INDICADA EN ROUTES
FirebaseMessaging.onMessageOpenedApp.listen((message) {
final routeFromMessage = message.data["route"];
print("ruta recibida en la push ${routeFromMessage}");
Navigator.of(context).pushNamed(routeFromMessage);
});
}
@override
Widget build(BuildContext context) {
return
Consumer<DarkThemeProvider>(builder: (context, themeData, child) {
return MaterialApp(
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
title: 'Evan.zero',
theme: Styles.themeData(themeChangeProvider.darkTheme, context),
home: MyHomePage(currentIndex: 0,),
);
});
}
}
local_notification_service.dart
class LocalNotificationService {
static final FlutterLocalNotificationsPlugin _notificationsPlugin =
FlutterLocalNotificationsPlugin();
static void initialize(BuildContext context) {
final InitializationSettings initializationSettings =
InitializationSettings(
android: AndroidInitializationSettings("@drawable/ic_stat_zf"));
_notificationsPlugin.initialize(initializationSettings,onSelectNotification: (String? route) async{
if(route != null){
Navigator.of(context).pushNamed(route);
}
});
}
static void display(RemoteMessage message) async {
try {
final id = DateTime.now().millisecondsSinceEpoch ~/1000;
const NotificationDetails notificationDetails = const NotificationDetails(
android: AndroidNotificationDetails(
"evanzero",
"evanzero channel",
importance: Importance.max,
priority: Priority.high,
)
);
await _notificationsPlugin.show(
id,
message.notification!.title,
message.notification!.body,
notificationDetails,
payload: message.data["route"],
);
} on Exception catch (e) {
print(e);
}
}
}
I am asking you to check the code and tell me what should I add or remove to receive Push Notifications on both platforms and on the three possible states
CodePudding user response:
Android closed app and in foreground and background my working example:
@override
void initState() {
super.initState();
var initializationSettingsAndroid = new AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = new IOSInitializationSettings();
var initializationSettings = new InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
flutterNotificationPlugin = FlutterLocalNotificationsPlugin();
flutterNotificationPlugin.initialize(initializationSettings, onSelectNotification : onNotificationInForegroundPressed);
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) {
if (message != null) {
Beamer.of(context).beamToNamed(
'/myroot/${message.data["id"].toString()}/myroot2');
notifications.setNotificationOpened(message.data["id"]);
}
});
FirebaseMessaging.onMessage.listen(
(RemoteMessage message) async {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
notifications.setNotificationReceived(message.data['id'].toString());
var requestId = message.data['requestId'].toString();
var messageId = message.data['messageId'].toString();
FCMPayload fcmPayload = FCMPayload(id: '$id', messageId : '$messageId');
String fcmPayloadJsonString = fcmPayload.toJsonString();
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body.toString(),
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
icon: 'launch_background',
),
),
payload: fcmPayloadJsonString
);
}
},
);
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
Beamer.of(context).beamToNamed(
'/myroot/${message.data["id"].toString()}/myroot2');
notifications.setNotificationOpened(message.data["messageId"]);
});
}
void Function()? onNotificationInForegroundPressed(String? payload) {
FCMPayload fcmpayload = FCMPayload.fromJsonString(payload!);
Beamer.of(context).beamToNamed(
'/myroot/${fcmpayload.requestId}/myroot');
notifications.setNotificationOpened(fcmpayload.messageId);
}