From d1bcdb7a7d0a57d02854430affbb6af3ac59f13b Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 6 Aug 2024 18:26:51 +0530 Subject: [PATCH] integrate api for the push notification in the rejected applications --- android/app/build.gradle | 3 + android/app/src/main/AndroidManifest.xml | 10 ++ android/settings.gradle | 3 + lib/main.dart | 99 +++++++++-- lib/notification_services.dart | 165 ++++++++++++++++++ lib/screens/home_screen.dart | 11 ++ macos/Flutter/GeneratedPluginRegistrant.swift | 6 + pubspec.lock | 96 ++++++++++ pubspec.yaml | 3 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 11 files changed, 386 insertions(+), 14 deletions(-) create mode 100644 lib/notification_services.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index e2ee37a..85f2127 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,5 +1,8 @@ plugins { id "com.android.application" + // START: FlutterFire Configuration + id 'com.google.gms.google-services' + // END: FlutterFire Configuration id "kotlin-android" // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id "dev.flutter.flutter-gradle-plugin" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c29f86c..04c6c49 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -29,7 +29,17 @@ + + + + + + HomeProvider()), - ], - child: const MyApp())); +@pragma('vm:entry-point') +Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { + await Firebase.initializeApp(); + log("Handling a background message: ${message.data["data"]}"); } -class MyApp extends StatelessWidget { +AndroidNotificationChannel channel = const AndroidNotificationChannel( + 'High Importance Channel', 'High Importance Notifications', + importance: Importance.high); + +late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + + if (!kIsWeb) { + flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + + FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); + + await FirebaseMessaging.instance.getInitialMessage().then((message) {}); + + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + RemoteNotification? notification = message.notification; + AndroidNotification? android = message.notification?.android; + if (notification != null && android != null) { + flutterLocalNotificationsPlugin.show( + notification.hashCode, + notification.title, + notification.body, + NotificationDetails( + android: AndroidNotificationDetails(channel.id, channel.name, + icon: '@mipmap/ic_launcher', importance: Importance.max), + iOS: const DarwinNotificationDetails())); + const AndroidInitializationSettings initializationSettingsAndroid = + AndroidInitializationSettings('@mipmap/ic_launcher'); + const DarwinInitializationSettings darwinInitializationSettings = + DarwinInitializationSettings(); + var initSettings = const InitializationSettings( + android: initializationSettingsAndroid, + iOS: darwinInitializationSettings); + flutterLocalNotificationsPlugin.initialize(initSettings); + } + }); + + if (Platform.isAndroid) { + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.requestNotificationsPermission(); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(channel); + } + if (Platform.isIOS) { + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + IOSFlutterLocalNotificationsPlugin>() + ?.requestPermissions(alert: true, badge: true, sound: true); + } + + await FirebaseMessaging.instance + .setForegroundNotificationPresentationOptions( + alert: true, badge: true, sound: true); + } + + runApp(MultiProvider(providers: [ + ChangeNotifierProvider(create: (context) => HomeProvider()), + ], child: const MyApp())); +} + +class MyApp extends StatefulWidget { const MyApp({super.key}); + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { @override Widget build(BuildContext context) { return MaterialApp( diff --git a/lib/notification_services.dart b/lib/notification_services.dart new file mode 100644 index 0000000..6777ade --- /dev/null +++ b/lib/notification_services.dart @@ -0,0 +1,165 @@ +import 'dart:io'; + +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; + +class NotificationServices { + //initialising firebase message plugin + FirebaseMessaging messaging = FirebaseMessaging.instance; + + //initialising firebase message plugin + final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + + //function to initialise flutter local notification plugin to show notifications for android when app is active + void initLocalNotifications( + BuildContext context, RemoteMessage message) async { + var androidInitializationSettings = + const AndroidInitializationSettings('@mipmap/ic_launcher'); + var iosInitializationSettings = const DarwinInitializationSettings(); + + var initializationSetting = InitializationSettings( + android: androidInitializationSettings, iOS: iosInitializationSettings); + + await _flutterLocalNotificationsPlugin.initialize(initializationSetting, + onDidReceiveNotificationResponse: (payload) { + // handle interaction when app is active for android + handleMessage(context, message); + }); + } + + void firebaseInit(BuildContext context) { + FirebaseMessaging.onMessage.listen((message) { + RemoteNotification? notification = message.notification; + AndroidNotification? android = message.notification!.android; + + if (kDebugMode) { + print("notifications title:${notification!.title}"); + print("notifications body:${notification.body}"); + print('count:${android!.count}'); + print('data:${message.data.toString()}'); + } + + if (Platform.isIOS) { + forgroundMessage(); + } + + if (Platform.isAndroid) { + initLocalNotifications(context, message); + showNotification(message); + } + }); + } + + void requestNotificationPermission() async { + NotificationSettings settings = await messaging.requestPermission( + alert: true, + announcement: true, + badge: true, + carPlay: true, + criticalAlert: true, + provisional: true, + sound: true, + ); + + if (settings.authorizationStatus == AuthorizationStatus.authorized) { + if (kDebugMode) { + print('user granted permission'); + } + } else if (settings.authorizationStatus == + AuthorizationStatus.provisional) { + if (kDebugMode) { + print('user granted provisional permission'); + } + } else { + //appsetting.AppSettings.openNotificationSettings(); + if (kDebugMode) { + print('user denied permission'); + } + } + } + + // function to show visible notification when app is active + Future showNotification(RemoteMessage message) async { + AndroidNotificationChannel channel = AndroidNotificationChannel( + message.notification!.android!.channelId.toString(), + message.notification!.android!.channelId.toString(), + importance: Importance.max, + showBadge: true, + playSound: true, + sound: const RawResourceAndroidNotificationSound('jetsons_doorbell')); + + AndroidNotificationDetails androidNotificationDetails = + AndroidNotificationDetails( + channel.id.toString(), channel.name.toString(), + channelDescription: 'your channel description', + importance: Importance.high, + priority: Priority.high, + playSound: true, + ticker: 'ticker', + sound: channel.sound + // sound: RawResourceAndroidNotificationSound('jetsons_doorbell') + // icon: largeIconPath + ); + + const DarwinNotificationDetails darwinNotificationDetails = + DarwinNotificationDetails( + presentAlert: true, presentBadge: true, presentSound: true); + + NotificationDetails notificationDetails = NotificationDetails( + android: androidNotificationDetails, iOS: darwinNotificationDetails); + + Future.delayed(Duration.zero, () { + _flutterLocalNotificationsPlugin.show( + 0, + message.notification!.title.toString(), + message.notification!.body.toString(), + notificationDetails, + ); + }); + } + + //function to get device token on which we will send the notifications + Future getDeviceToken() async { + String? token = await messaging.getToken(); + return token!; + } + + void isTokenRefresh() async { + messaging.onTokenRefresh.listen((event) { + event.toString(); + if (kDebugMode) { + print('refresh'); + } + }); + } + + //handle tap on notification when app is in background or terminated + Future setupInteractMessage(BuildContext context) async { + // when app is terminated + RemoteMessage? initialMessage = + await FirebaseMessaging.instance.getInitialMessage(); + + if (initialMessage != null) { + handleMessage(context, initialMessage); + } + + //when app ins background + FirebaseMessaging.onMessageOpenedApp.listen((event) { + handleMessage(context, event); + }); + } + + void handleMessage(BuildContext context, RemoteMessage message) {} + + Future forgroundMessage() async { + await FirebaseMessaging.instance + .setForegroundNotificationPresentationOptions( + alert: true, + badge: true, + sound: true, + ); + } +} diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index a85e5c6..039a57a 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1,3 +1,4 @@ +import 'package:cheminova/notification_services.dart'; import 'package:cheminova/provider/home_provider.dart'; import 'package:cheminova/screens/rejected_application_screen.dart'; import 'package:cheminova/screens/calendar_screen.dart'; @@ -13,6 +14,7 @@ import 'package:cheminova/screens/update_inventory_screen.dart'; import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_drawer.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -24,10 +26,19 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { + NotificationServices notificationServices = NotificationServices(); + @override void initState() { Provider.of(context, listen: false).getProfile(); super.initState(); + notificationServices.requestNotificationPermission(); + + notificationServices. getDeviceToken().then((value) { + if (kDebugMode) { + print('Device Token: $value'); + } + }); } @override diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 850b6d6..8b519a4 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,12 +6,18 @@ import FlutterMacOS import Foundation import file_selector_macos +import firebase_core +import firebase_messaging +import flutter_local_notifications import flutter_secure_storage_macos import geolocator_apple import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 9e91a02..89c2ba1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "67.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: b1595874fbc8f7a50da90f5d8f327bb0bfd6a95dc906c390efe991540c3b54aa + url: "https://pub.dev" + source: hosted + version: "1.3.40" analyzer: dependency: transitive description: @@ -209,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" dio: dependency: "direct main" description: @@ -281,6 +297,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.3+2" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "3187f4f8e49968573fd7403011dca67ba95aae419bc0d8131500fae160d94f92" + url: "https://pub.dev" + source: hosted + version: "3.3.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: "3c3a1e92d6f4916c32deea79c4a7587aa0e9dbbe5889c7a16afcf005a485ee02" + url: "https://pub.dev" + source: hosted + version: "5.2.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: e8d1e22de72cb21cdcfc5eed7acddab3e99cd83f3b317f54f7a96c32f25fd11e + url: "https://pub.dev" + source: hosted + version: "2.17.4" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "1b0a4f9ecbaf9007771bac152afad738ddfacc4b8431a7591c00829480d99553" + url: "https://pub.dev" + source: hosted + version: "15.0.4" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: c5a6443e66ae064fe186901d740ee7ce648ca2a6fd0484b8c5e963849ac0fc28 + url: "https://pub.dev" + source: hosted + version: "4.5.42" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "232ef63b986467ae5b5577a09c2502b26e2e2aebab5b85e6c966a5ca9b038b89" + url: "https://pub.dev" + source: hosted + version: "3.8.12" fixnum: dependency: transitive description: @@ -326,6 +390,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: dd6676d8c2926537eccdf9f72128bbb2a9d0814689527b17f92c248ff192eaf3 + url: "https://pub.dev" + source: hosted + version: "17.2.1+2" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af + url: "https://pub.dev" + source: hosted + version: "4.0.1" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" + url: "https://pub.dev" + source: hosted + version: "7.2.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -1021,6 +1109,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + timezone: + dependency: transitive + description: + name: timezone + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" + url: "https://pub.dev" + source: hosted + version: "0.9.4" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9e24874..65f9faa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,9 @@ dependencies: geocoding: ^3.0.0 pretty_dio_logger: ^1.3.1 csc_picker: ^0.2.7 + firebase_core: ^3.3.0 + firebase_messaging: ^15.0.4 + flutter_local_notifications: ^17.2.1+2 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 6a1b9be..41dfcd2 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -14,6 +15,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); GeolocatorWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index e55e969..9c3f356 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows + firebase_core flutter_secure_storage_windows geolocator_windows permission_handler_windows