I try initialize Firebase Messaging and get token, but I receive this error
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print('on Background Message : ${message.data}');
}
class MyHttpOverrides extends HttpOverrides {
#override
HttpClient createHttpClient(SecurityContext context) {
return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
}
}
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await GlobalConfiguration().loadFromAsset("configurations");
NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
} else if (settings.authorizationStatus == AuthorizationStatus.provisional) {
print('User granted provisional permission');
} else {
print('User declined or has not accepted permission');
}
try{
await FirebaseMessaging.instance.getToken();
FirebaseMessaging.instance.getInitialMessage();
if(GetPlatform.isMobile){
FirebaseMessaging.instance.subscribeToTopic('suitableUser');
}else{
}
FirebaseMessaging.onMessage.listen((event) {
}).onError((error){
print('error');
});
FirebaseMessaging.onMessageOpenedApp.listen((event) {
print('success : ${event.data}');
}).onError((error){
print('error');
});
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
}catch(e){
print('555555 FirebaseMessaging ::: $e');
}
HttpOverrides.global = new MyHttpOverrides();
runApp(MyApp());
}
I have tried many methods such as deleting the build file, downloading Json file from firebase again, and creating another API, but i get this error in run
E/FirebaseInstanceId(13464): Failed to get FIS auth token
E/FirebaseInstanceId(13464): Caused by: com.google.firebase.installations.FirebaseInstallationsException: Firebase Installations Service is unavailable. Please try again later.
E/FirebaseInstanceId(13464): at com.google.firebase.installations.remote.FirebaseInstallationServiceClient.createFirebaseInstallation(FirebaseInstallationServiceClient.java:153)
E/FirebaseInstanceId(13464): at com.google.firebase.installations.FirebaseInstallations.registerFidWithServer(FirebaseInstallations.java:530)
E/FirebaseInstanceId(13464): at com.google.firebase.installations.FirebaseInstallations.doNetworkCallIfNecessary(FirebaseInstallations.java:385)
E/FirebaseInstanceId(13464): at com.google.firebase.installations.FirebaseInstallations.lambda$doRegistrationOrRefresh$2$FirebaseInstallations(FirebaseInstallations.java:374)
E/FirebaseInstanceId(13464): at com.google.firebase.installations.-$$Lambda$FirebaseInstallations$VZq1h0TBcWNH8Y5yY86ujrFFyLo.run(Unknown Source:4)
E/FirebaseInstanceId(13464): at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187)
E/FirebaseInstanceId(13464): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
E/FirebaseInstanceId(13464): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/FirebaseInstanceId(13464): ... 1 more
E/FirebaseInstanceId(13464): Topic sync or token retrieval failed on hard failure exceptions: FIS_AUTH_ERROR. Won't retry the operation.
I/flutter (13464): 555555 FirebaseMessaging ::: [firebase_messaging/unknown] java.io.IOException: FIS_AUTH_ERROR
Note: I use this code in another application and it works efficiently without any error
Related
I have an application, I want to send notifications only to authorized users,
authorization occurs by token if the token is empty, then the user is not authorized, for authorization and storing the token I use the shared_pref package. How can I disable notifications if the user is not logged in?
Token validation is only done in MyAppState notifications I need to disable in the same place
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await Permission.notification.request();
if(Constants.USER_TOKEN.isEmpty) {
FirebaseMessaging.instance.setAutoInitEnabled(false);
}
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
if (navKey.currentState != null) {
if(Constants.USER_TOKEN.isNotEmpty) {
navKey.currentState!.push(MaterialPageRoute(
builder: (context) => NotificationScreen()));
}
print('Message');
}
}
await _messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
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,
channelDescription: channel.description,
icon: '#mipmap/ic_launcher',
),
),
);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) {
print("On message opened app: ${message?.data}}");
if (navKey.currentState != null) {
if(Constants.USER_TOKEN.isNotEmpty) {
navKey.currentState!.push(MaterialPageRoute(
builder: (context) => const NotificationScreen()));
}
}
});
var initializationSettingsAndroid =
const AndroidInitializationSettings('#drawable/ic_notification');
var initializationSettingsIOS = const DarwinInitializationSettings();
var initializationSettings = InitializationSettings(
android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
await _messaging.requestPermission();
String? token = await _messaging.getToken();
if (token != null) {
print("FIREBASE TOKEN $token");
} else {
print("CANNOT TAKE FIREBASE TOKEN");
}
if (Platform.isIOS) {
var APNS = await _messaging.getAPNSToken();
print('APNS: $APNS');
}
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
getToken() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
Constants.USER_TOKEN = pref.getString('login') ?? "";
});
}
#override
void didChangeDependencies() async {
super.didChangeDependencies();
await getToken();
}
Use deleteToken which invalidates the current token and getToken again to get a new one when enabling.
getToken() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
Constants.USER_TOKEN = pref.getString('login') ?? "";
});
if(Constants.USER_TOKEN.isEmpty()){
// delete firebase token
}else{
// get firebase token
}
}
import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../export.dart';
class FirebaseNotificationManager {
FirebaseNotificationManager._privateConstructor();
static final FirebaseNotificationManager _instance = FirebaseNotificationManager._privateConstructor();
factory FirebaseNotificationManager() {
return _instance;
}
init() async {
// add firebase notification permission
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: true,
provisional: false,
sound: true,
);
if (await Permission.notification.request().isGranted) {
try {
// Either the permission was already granted before or the user just granted it.
FirebaseMessaging.onBackgroundMessage(_messageHandler);
_firebaseMessagingListener();
String? deviceToken = await FirebaseMessaging.instance.getToken();
logger.i(deviceToken);
} catch (e) {
logger.i(e);
}
}
}
/// must call it from view after getContext is initialized to show dialog message
checkAndroid() async {
if (!(await Permission.notification.request().isGranted) && GetPlatform.isAndroid) {
showOptionsDialog(
text: 'إذا كنت ترغب في تلقي الاشعارات ،برجاء اعطاء إذن الاشعارات في الإعدادات وإعادة تشغيل التطبيق',
yesFunction: (context) async {
openAppSettings();
});
}
}
// execute if app in background
Future<void> _messageHandler(RemoteMessage message) async {
// Data notificationMessage = Data.fromJson(message.data);
log('notification from background : ${message.toMap()}');
}
// execute if app in foreground
void _firebaseMessagingListener() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
logger.i('Got a message whilst in the foreground!');
logger.i('Message data: ${message.data}');
if (message.notification != null) {
logger.i('Message also contained a notification: ${message.notification!.toMap()}');
logger.i('Message also contained a notification: ${message.toMap()}');
// that means new message
try {
Get.snackbar(message.notification!.title.toString(), message.notification!.body.toString(),
duration: Duration(seconds: 6),
backgroundColor: Theme.of(Get.context!).cardColor,
barBlur: 10,
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(8));
} catch (e) {
logger.i(e);
}
}
});
}
}
As per the documentation, you need to put the onBackgroundMessage function outside of a class, at the top of your file as a top-level function. See Firebase messaging example for implementation.
source
file became:
import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../export.dart';
init() async {
// add firebase notification permission
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: true,
provisional: false,
sound: true,
);
if (await Permission.notification.request().isGranted) {
try {
// Either the permission was already granted before or the user just granted it.
FirebaseMessaging.onBackgroundMessage(_messageHandler);
_firebaseMessagingListener();
String? deviceToken = await FirebaseMessaging.instance.getToken();
logger.i(deviceToken);
} catch (e) {
logger.i(e);
}
}
}
/// must call it from view after getContext is initialized to show dialog message
checkAndroid() async {
if (!(await Permission.notification.request().isGranted) && GetPlatform.isAndroid) {
showOptionsDialog(
text: 'إذا كنت ترغب في تلقي الاشعارات ،برجاء اعطاء إذن الاشعارات في الإعدادات وإعادة تشغيل التطبيق',
yesFunction: (context) async {
openAppSettings();
});
}
}
// execute if app in background
Future<void> _messageHandler(RemoteMessage message) async {
// Data notificationMessage = Data.fromJson(message.data);
log('notification from background : ${message.toMap()}');
}
// execute if app in foreground
void _firebaseMessagingListener() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
logger.i('Got a message whilst in the foreground!');
logger.i('Message data: ${message.data}');
if (message.notification != null) {
logger.i('Message also contained a notification: ${message.notification!.toMap()}');
logger.i('Message also contained a notification: ${message.toMap()}');
// that means new message
try {
Get.snackbar(message.notification!.title.toString(), message.notification!.body.toString(),
duration: Duration(seconds: 6),
backgroundColor: Theme.of(Get.context!).cardColor,
barBlur: 10,
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(8));
} catch (e) {
logger.i(e);
}
}
});
}
I am trying to navigate my notifications while terminated, opened. I can navigate when app is open but not on screen. In my home page's initstate method, I created onMessageOpenedApp method to catch notification then call the api. Here is firebase messaging configuration.
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
AppleNotification? apple = message.notification?.apple;
if (notification != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
),
iOS: const IOSNotificationDetails()),
);
}
}
Future<void> iniciliazarFlutterLocalNotifications() async {
final NotificationAppLaunchDetails? notificationAppLaunchDetails = !kIsWeb &&
Platform.isLinux
? null
: await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
var androidSettings =
const AndroidInitializationSettings('mipmap/launcher_icon');
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
if (!kIsWeb) {
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title/ description
importance: Importance.high,
ledColor: Colors.blue);
var iOSSettings = const IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
);
var initSetttings =
InitializationSettings(android: androidSettings, iOS: iOSSettings);
flutterLocalNotificationsPlugin.initialize(initSetttings);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
AppleNotification? apple = message.notification?.apple;
if (notification != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
),
iOS: const IOSNotificationDetails()),
);
}
});
}
}
And here is my HomeScreen initState variables that only I can navigate my notification then call Api provider.
class Home extends StatefulWidget {
const Home({super.key});
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
void initState() {
super.initState();
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
if (message.data.containsKey('idReferance')) {
Provider.of<CustomerProvider>(context, listen: false)
.getTrackingInformationList(TrackingInformationFilterRequestModel(
searchBox: message.data['idReferance']));
}
});
}
#override
Widget build(BuildContext context) {
return Container();
}
}
There is a function called getInitialMessage which returns the remote notifiction if the app is opened from notification when it is terminated.
if the app is opened from other places it will return null. You can handle the navigation according to this remote notification object. Here is a sample function you can use
Future<void> setupInteractedMessage() async {
// Get any messages which caused the application to open from
// a terminated state.
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "chat",
// navigate to a chat screen
if (initialMessage != null) {
_handleMessage(initialMessage);
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
you can call this method from initstate from your app splash screen or some where you find it relevant. You can see example in this link for more detail
https://firebase.flutter.dev/docs/messaging/notifications/#handling-interaction
I'm trying to display the background and foreground notification in flutter using flutter_local_notifications package. here is my firebase class code
class FirebaseMessagingService {
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
IOSInitializationSettings? _initializationSettingsIOS;
AndroidInitializationSettings? _initializationSettingsAndroid;
AndroidNotificationDetails? _androidLocalNotificationDetails;
AndroidNotificationChannel? androidNotificationchannel;
static FirebaseMessagingService? _messagingService;
NotificationDetails? _androidNotificationDetails;
InitializationSettings? _initializationSettings;
//NotificationNavigationClass _notificationNavigationClass = NotificationNavigationClass();
NotificationAppLaunchDetails? _notificationAppLaunchDetails;
bool? _didNotificationLaunchApp;
static FirebaseMessaging? _firebaseMessaging;
FirebaseMessagingService._createInstance();
factory FirebaseMessagingService() {
// factory with constructor, return some value
if (_messagingService == null) {
_messagingService = FirebaseMessagingService
._createInstance(); // This is executed only once, singleton object
_firebaseMessaging = _getMessagingService();
}
return _messagingService!;
}
static FirebaseMessaging _getMessagingService() {
return _firebaseMessaging ??= FirebaseMessaging.instance;
}
Future<String?> getToken() {
return _firebaseMessaging!.getToken();
}
Future initializeNotificationSettings() async
{
NotificationSettings? settings = await _firebaseMessaging
?.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings?.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
} else
if (settings?.authorizationStatus == AuthorizationStatus.provisional) {
print('User granted provisional permission');
} else {
print('User declined or has not accepted permission');
}
androidNotificationchannel = const AndroidNotificationChannel(
NOTIFICATION_ID, // id
NOTIFICATION_TITLE, // title
description: NOTIFICATION_DESCRIPTION,
// description
importance: Importance.max,
);
//
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(androidNotificationchannel!);
if (Platform.isIOS) {
//configure local notification for ios
await _initializeIosLocalNotificationSettings();
}
else {
//configure local notification for android
await _initializeAndroidLocalNotificationSettings();
}
}
Future<void> _initializeIosLocalNotificationSettings() async
{
_initializationSettingsIOS = const IOSInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false
);
_initializationSettings = InitializationSettings(
iOS: _initializationSettingsIOS
);
}
Future<void> _initializeAndroidLocalNotificationSettings() async
{
_initializationSettingsAndroid =
const AndroidInitializationSettings('mipmap/ic_launcher');
_initializationSettings = InitializationSettings(
android: _initializationSettingsAndroid,
);
_androidLocalNotificationDetails =
const AndroidNotificationDetails(
LOCAL_NOTIFICATION_ID,
LOCAL_NOTIFICATION_TITLE,
channelDescription: LOCAL_NOTIFICATION_DESCRIPTION,
importance: Importance.max,
priority: Priority.high);
_androidNotificationDetails =
NotificationDetails(android: _androidLocalNotificationDetails);
//This will execute when the app is open and in foreground
void foregroundNotification() {
try {
_showLocalNotification(localNotificationId: DateTime
.now()
.hour + DateTime
.now()
.minute + DateTime
.now()
.second,
notificationData: message?.data,
messageTitle:message?.notification?.title ,
messageBody: message?.notification?.body,
);
} catch (error) {
log("error");
}
});
}
void _showLocalNotification(
{int? localNotificationId, Map<String, dynamic>? notificationData,String? messageTitle,String? messageBody}) async
{
if (notificationData != null) {
log("Notification Data:${notificationData}");
await _flutterLocalNotificationsPlugin.show(
localNotificationId ?? 0, notificationData["title"]??messageTitle,
notificationData["body"]??messageBody,
_androidNotificationDetails,
payload: jsonEncode(notificationData));
}
}
//This will excute when the app is in background but not killed and tap on that notification
void backgroundTapNotification() {
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) async {
try {
RemoteMessage? terminatedMessage = await _firebaseMessaging
?.getInitialMessage();
} catch (error) {
log("error");
}
});
}
}
and calling it in splash screen
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500));
heartbeatAnimation =
Tween<double>(begin: 100.0, end: 250.0).animate(controller);
controller.forward().whenComplete(() {
controller.reverse();
});
void _setNotifications() async {
FirebaseMessagingService().foregroundNotification();
FirebaseMessagingService().backgroundTapNotification();
}
await FirebaseMessagingService().initializeNotificationSettings();
_setNotifications();
}
When i close the app and hit the API notification is displaying on background, but when i open the app and hit the API notification is not displaying, nor foreground and not on background.
please help me to get out from this problem.
I've added FCM in my Flutter app and it works, but I can't find a way to send notifications in different languages.
I saw that you can set the conditions for the language on the Firebase console when sending a new notification, but I'm not quite sure how it works. I would like to know if I need to add something to my code to make it work.
Here's the code I have:
push_notification_service.dart
import 'package:firebase_messaging/firebase_messaging.dart';
enum AppState {
foreground,
background,
terminated,
}
class PushNotificationsManager {
PushNotificationsManager._();
factory PushNotificationsManager() => _instance;
static final PushNotificationsManager _instance = PushNotificationsManager._();
Future<void> init() async {
await _setFCMToken();
_configure();
}
_setFCMToken() async {
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
String? token = await messaging.getToken();
print('FirebaseMessaging token: $token');
}
}
void _configure() async {
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
_showForegroundNotificationInAndroid(message);
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
_handleNotification(message: message.data, appState: AppState.foreground);
});
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
_handleNotification(message: initialMessage.data, appState: AppState.terminated);
}
}
void _showForegroundNotificationInAndroid(RemoteMessage message) async {}
void _handleNotification({
Map<String, dynamic>? message,
AppState? appState,
}) async {
print('PushNotificationsManager: _handleNotification ${message.toString()} ${appState.toString()}');
}
}
and in main.dart I have:
initState(){
super.initState();
PushNotificationsManager().init();
}
Do I need to use flutter_analytics package?