Firebase Messaging - Validate incoming background messages based on user logged in - android

I'm creating a chat app (kind of WhatsApp-like messaging) using Flutter.
First, the notifications mechanism is working as intended, whenever I send a message from 1 device to another device, the notification would pop up.
I created a local_notification_service.dart to handle the foreground notification & sending a not
import 'dart:math';
import 'package:get/get.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class LocalNotificationService extends GetConnect {
String serverKey ='xxxxxxxxxxxxxxxxxxxx'
static final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
static void initialize() {
const InitializationSettings initializationSettings = InitializationSettings(android: AndroidInitializationSettings("#mipmap/ic_launcher"));
_flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
static void display(RemoteMessage message) async {
try {
print("Display notification");
// int id = DateTime.now().microsecondsSinceEpoch ~/1000000;
Random random = Random();
int id = random.nextInt(1000);
const NotificationDetails notificationDetails = NotificationDetails(
android: AndroidNotificationDetails(
"mychanel",
"my chanel",
importance: Importance.max,
priority: Priority.high,
));
print("my id is ${id.toString()}");
await _flutterLocalNotificationsPlugin.show(
id,
message.notification!.title,
message.notification!.body,
notificationDetails,
);
} on Exception catch (e) {
print('Error>>>$e');
}
}
Future<void> sendNotification({
String? title,
String? message,
String? token,
String? uniqueId,
String? action,
String? channelId,
String? channelName,
String? channelDesc,
}) async {
final data = {
"click_action": "FLUTTER_NOTIFICATION_CLICK",
"action": action,
"uniqueId": uniqueId,
"message": message,
"channelId": channelId ?? 'my channel id',
"channelName": channelName ?? 'my channel Name',
"channelDesc": channelDesc ?? 'my channel description',
};
try {
final response = await post(
'https://fcm.googleapis.com/fcm/send',
{
'notification': {'title': title, 'body': message},
'priority': 'high',
'data': data,
'to': '$token',
'direct_boot_ok': true,
},
headers: {
'Content-Type': 'application/json',
'Authorization': 'key=$serverKey',
},
);
print('response body : ${response.body}');
} catch (e) {}
}
}
Then, I'm trying to validate the users in my flutter application whenever they receive FCM notification, here's the logic that I want to create:
If the user is not logged in, then the device could not receive the notification
If the user is logged in, but the specific user is not eligible to receive the message (in case there are some users with the same FCM token / device registered ) then the device could not receive the notification. I would want to solve this after the point number 1 is succeeded
Here's my main.dart file
void main() async {
await GetStorage.init();
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
GlobalController globalC = Get.put(GlobalController());
AuthController authC = Get.put(AuthController());
ErrorController errorC = Get.put(ErrorController());
ConnectivityResult connectivityResult = ConnectivityResult.none;
final Connectivity connectivity = Connectivity();
connectivityResult = await connectivity.checkConnectivity();
if (connectivityResult == ConnectivityResult.wifi || connectivityResult == ConnectivityResult.mobile) {
// Start FCM
final fcmToken = await FirebaseMessaging.instance.getToken();
globalC.fcmToken.value = fcmToken ?? ''; //set global fcm Token
final FirebaseMessaging fcmInstance = FirebaseMessaging.instance;
NotificationSettings settings = await fcmInstance.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
/* Handle message when in foreground */
FirebaseMessaging.onMessage.listen((event) {
if (globalC.isAuthenticated.isTrue) {
LocalNotificationService.display(event); //display notification
}
});
/* Handle message when in background */
if (globalC.isAuthenticated.isTrue) {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
}
fcmInstance.onTokenRefresh.listen((fcmToken) {
// Note: This callback is fired at each app startup and whenever a new
// token is generated.
}).onError((err) {
// Error getting token.
});
// End FCM
}
FirebaseAnalytics analytics = FirebaseAnalytics.instance;
runApp(MyApp());
}
as you can see, I'm trying to filter the non logged in user when in the foreground using the FirebaseMessaging.onMessage.listen with the globalC.isAuthenticated.isTrue validation. And it works (because the default of globalC.isAuthenticated is false whenever user is not logged in)
But for the FirebaseMessaging.onBackgroundMessage function does not seems to work with the validation. I've tried to search for the solution in the documentations, youtube but i couldn't find it till this question is made.
How can I make this kind of validation for background message?
Sorry for this newbie question, any help would be greatly appreciated.
Thank you .

Related

Send notification to specific user firebase in flutter

How do I send a notification to another user when one user presses a button? Can someone show me a code snippet?
I realize that this question was asked before, however, it was closed since there were "several answers." The links that were provided that were similar did not explain sending notifications in flutter.
The below solution works, however, my solution is much simpler, and avoids adding new technologies
I have figured out how send a notification to another device using an in app feature.
First, you will need to import the necessary packages:
firebase_messaging
flutter_local_notifications
Note: you will also use the http package
Also note: to send notifications to another device, you must know the device token of that device. I prefer getting the token and saving it in Firestore or Realtime Database. Here is the code to get the device token.
String? mtoken = " ";
void getToken() async {
await FirebaseMessaging.instance.getToken().then((token) {
setState(() {
mtoken = token;
});
});
}
The token will be saved in mtoken, you can now use this as the token for the coming steps.
The next step is to request permission to send push notifications to your app.
void requestPermission() async {
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.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');
}
}
(If you get "User declined or has not accepted permission" in your console, try going out of your app, finding the icon in the homescreen, pressing and holding on the app icon, tapping "App Info", tapping "Notifications" and turn on "All [app name] notifications."
You will also need two functions to load a Firebase Cloud Messaging notification and one to listen for a notification.
Code to load a Firebase Cloud Messaging notification:
void loadFCM() async {
if (!kIsWeb) {
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
importance: Importance.high,
enableVibration: true,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
}
And this function to listen for a Firebase Cloud Messaging notifcation.
void listenFCM() async {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
),
);
}
});
}
You will want to run loadFCM, listenFCM, and requestPermission when the page is initialized.
void initState() {
super.initState();
requestPermission();
loadFCM();
listenFCM();
}
The next step is to find your Firebase Cloud Messaging API key. This can simply be done by heading to your Firebase project > Project Settings > Cloud Messaging then copy the API key under Cloud Messaging API (Legacy).
When you have your Firebase Cloud Messaging API key, this is the code to display a notification given the notification title, body, and device token to send it to.
void sendPushMessage(String body, String title, String token) async {
try {
await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization':
'key=REPLACETHISWITHYOURAPIKEY',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
'body': body,
'title': title,
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done'
},
"to": token,
},
),
);
print('done');
} catch (e) {
print("error push notification");
}
}
Now you can call this function like this:
sendPushMessage('Notification Body', 'Notification Title', 'REPLACEWITHDEVICETOKEN');
I hope this helps.
You will need Firebase Cloud Messaging for that.
The way I've done it is using a Cloud Function that you can trigger via HTTP or even via a Firestore trigger, like this:
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
/**
* Triggered by a change to a Firestore document.
*
* #param {!Object} event Event payload.
* #param {!Object} context Metadata for the event.
*/
exports.messageNotificationTrigger = (change, context) => {
db.collection('users').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
const userData = doc.data();
if (userData.id == '<YOUR_USER_ID>') {
admin.messaging().sendToDevice(userData.deviceToken, {
notification: {
title: 'Notification title', body: 'Notification Body'}
});
}
});
});
};
Every user you have registered in your users collection must have a device token, sent from their device they access the app.
From Flutter, using the FCM package, this is how you send the device token to Firebase:
// fetch the device token from the Firebase Messaging instance
// and store it securely on Firebase associated with this user uid
FirebaseMessaging.instance.getToken().then((token) {
FirebaseFirestore.instance.collection('users').doc(userCreds.user!.uid).set({
'deviceToken': token
});
});
Where userCredentials.user!.uid is the user you use to log in to your application using Firebase Authentication like this:
UserCredential userCreds = await FirebaseAuth.instance.signInWithCredential(credential);
Hope that helps.

Heads up notification with Cloud Functions - Flutter

I've configured my flutter app in order to receive push notifications, when I try from FCM it works properly and I obtain Heads up notification when the app is in foreground/background/closed.
I configured also the channel and all works.
The problem is when I want to send an automatic notification by using of Google Cloud Function, I never receive the heads up notificationn.
below my code:
Main.Dart
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(backgroundHandler);
runApp(...) }
...
#override
void initState() {
LocalNotificationService.initialize(changeMessage);
/// gives you the message on which user taps and it oened app from terminated state
FirebaseMessaging.instance.getInitialMessage().then((event) {
setState(() {
widget.message = event!.data["route"];
});
});
//foreground
FirebaseMessaging.onMessage.listen((event) {
print(event.notification?.body);
print(event.notification?.title);
LocalNotificationService.display(event);
});
// app in background but opened and user taps on notification
FirebaseMessaging.onMessageOpenedApp.listen((event) {
setState(() {
widget.message = event!.data["route"];
});
/*final routeFromMessage = event.data["route"];
print(routeFromMessage);
Navigator.of(context).pushNamed(routeFromMessage);*/
});
}
in Manifest I have:
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value = "myChannel"
/>
I created Service
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class LocalNotificationService{
static final FlutterLocalNotificationsPlugin _notificationsPlugin= FlutterLocalNotificationsPlugin();
static void initialize(Function updateRoute){
final InitializationSettings initializationSettings =
InitializationSettings(android: AndroidInitializationSettings("#mipmap/ic_launcher"));
_notificationsPlugin.initialize(initializationSettings,onSelectNotification: (String? route) async{
updateRoute(route);
});
}
static void display(RemoteMessage remoteMessage) async{
try {
final id = DateTime.now().millisecondsSinceEpoch ~/1000;
final NotificationDetails notificationDetails = NotificationDetails(
android: AndroidNotificationDetails(
"myChannel",
"myChannel channel",
importance: Importance.max,
priority: Priority.high
)
);
await _notificationsPlugin.show(
id, remoteMessage.notification!.title, remoteMessage.notification!.body, notificationDetails,payload: remoteMessage.data["route"]);
} on Exception catch (e) {
print(e);
}
}
}
and my Cloud Function:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().functions);
exports.messageTrigger = functions.firestore.document('events/{likedId}').onCreate(async (snap,context) => {
console.log('----------------start function--------------------')
const doc = snap.data()
console.log(doc)
const idFrom = doc.idFrom //chi mette like
const idTo = doc.idTo //creatore evento
const activity = doc.activity
console.log(`Recupero il TO`)
const res = await admin
.firestore()
.collection('users')
.where('uid', '==', idTo)
.get()
.then(querySnapshot => {
querySnapshot.forEach(userTo => {
console.log(`Found user to: "${userTo.data().surname}"`)
console.log(`Recupero il FROM`)
if (userTo.data().pushToken) {
// Get info user from (sent)
admin
.firestore()
.collection('users')
.where('uid', '==', idFrom)
.get()
.then(querySnapshot2 => {
querySnapshot2.forEach(userFrom => {
console.log(`Found user from: ${userFrom.data().name}`)
const payload = {
notification: {
title: ...,
body: ...,
channel_id: "myChannel",
},
data: {route: ...}
}
// Let push to the target device
admin
.messaging()
.sendToDevice(userTo.data().pushToken, payload)
.then(response => {
console.log('Successfully sent message:', response)
})
.catch(error => {
console.log('Error sending message:', error)
})
})
})
} else {
console.log('Can not find pushToken target user')
}
})
})
return null
});
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// functions.logger.info("Hello logs!", {structuredData: true});
// response.send("Hello from Firebase!");
// });
How I can solve,
thanks
For future readers I solve it by using of android_channel_id: "myChannel" instead of channel_id: "myChannel" in my cloud function

How to enable the "Show Notification as Pop Up" by default on android devices?

I am working on a food delivery app with Flutter. I have recently Implemented the flutter_local_notifications and the notification is working fine. But there's one problem is that the notification doesn't show as pop up by default. The "Show as pop up" option is disabled by default in the notification settings.
Is there any way that when the app is installed the "Show as pop up" option is enabled by default.
Here's my Notification Configuration Code:
void registerNotification() {
// This function registers the user for recieving push notifications.
// After registering the user, it creates a new field inside 'userForChat' Database
// The field is called : 'pushToken' which is later used on to configure Firebase Automatic Cloud Messaging
firebaseMessaging.requestNotificationPermissions();
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
Platform.isAndroid
? showNotification(message['notification'])
: showNotification(message['aps']['alert']);
return;
},
onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return;
},
onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
},
);
// Token for Firebase Messaging
firebaseMessaging.getToken().then((token) {
print('token: $token');
Firestore.instance
.collection('usersForChat')
.document(currentUserId)
.updateData(
{'pushToken': token}); //Sets the firebase Token into the database
}).catchError((onError) {
setState(() {});
});
}
void configLocalNotification() {
var initializationSettingsAndroid = AndroidInitializationSettings(
'mipmap/ic_launcher');
var initializationSettingsIOS = IOSInitializationSettings();
var initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
void showNotification(message) async {
// This function takes the notfication message as input triggers the notification to show the message.
// The input is in a json format so you have to decode the json with dart:convert.
// IMPORTANT: Specify the Application package name according to the OS.
//For Android, Use the android app package name from firebase
//For iOS, Use the iOS app package name from firebase
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
// add your apps package name for each OS(Android:iOS)
Platform.isAndroid
? 'com.jexmovers.app' //Update the package name to your app's package names
: 'com.jexmovers.ios', //Update the package name to your app's package names
'JexMovers Chat',
'App that lets you contact with your food delivery person',
playSound: true,
enableVibration: true,
importance: Importance.Max,
priority: Priority.Max,
visibility: NotificationVisibility.Public,
enableLights: true,
);
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
print(message);
print(message['body'].toString());
print(json.encode(message));
await flutterLocalNotificationsPlugin.show(
0,
message['title'].toString(),
message['body'].toString(),
platformChannelSpecifics,
payload: json.encode(message),
);
}

Call a HTTP request in flutter local notification

I would like to ask if there's a http get in flutter local notifications? My aim here is when the flutter notification will show, a http get request will be triggered
This my http request for my api:
final String url = 'http://192.168.43.45:8000/api';//url in my request
List data;
Future<String> getData() async {
var response =await http.get(
Uri.encodeFull(url),
headers:{"Accept":"application/json"}
);//get data and decode it to json
}
This code will initialize the notifications:
initializeNotifications() async {
var initializationSettingsAndroid =
AndroidInitializationSettings('#mipmap/launcher_icon');//icon will display when notification appears
var initializationSettingsIOS = IOSInitializationSettings();
var initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
}
Future onSelectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: ' + payload);
}
await Navigator.push(
context,
new MaterialPageRoute(builder: (context) => HomePage()),
);
}
Code for the notification when click it will redirect to homePage:
Future<void> scheduleNotification(Medicine medicine) async {
var hour = int.parse(medicine.startTime[0] + medicine.startTime[1]);
var ogValue = hour;
var minute = int.parse(medicine.startTime[2] + medicine.startTime[3]);
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'repeatDailyAtTime channel id',
'repeatDailyAtTime channel name',
'repeatDailyAtTime description',
importance: Importance.Max,
ledColor: Color(0xFF3EB16F),
ledOffMs: 1000,
ledOnMs: 1000,
enableLights: true,
);
//notification details
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
//this code will show the whats the notification must appear
await flutterLocalNotificationsPlugin.showDailyAtTime(
int.parse(medicine.notificationIDs[i]),
'Mediminder: ${medicine.medicineName}',
medicine.medicineType.toString() !=
MedicineType.None.toString()
? 'It is time to take your Medicine, according to schedule'
: 'It is time to take your medicine, according to schedule',
Time(hour, minute,),
platformChannelSpecifics);
hour = ogValue;
}
//await flutterLocalNotificationsPlugin.cancelAll();//cancel the flutter notifications
}
}
it seems that you are using flutter_local_notifications, looking at their documentation i don't think it's possible to you to handle the onReceive notification, this is done internally by the package.
But maybe you could implement your own receiver class extending BroadCastReceiver and listen for the same action that the packages send, from there you'll be able to send HTTP requests.
Take a look at this question, maybe it helps.

Flutter: How can i send push notification programmatically with fcm

I'm creating a chat application and i want to use fcm to send notification if the person has a new message, but i don't know how to proceed. All the tutorials i found use to send the message from firebase. But i want to send it automatically when there is a new message for the person
A possible workaround if you use firebase should be like this:
You need to store each firebase FCM token for a specific user (need to take in account here that a user can log in at the same time on his account from multiple devices) so you can store the userId and his deviceUniqueId on flutter you can get it from device_info https://pub.dev/packages/device_info:
String identifier;
final DeviceInfoPlugin deviceInfoPlugin = new DeviceInfoPlugin();
try {
if (Platform.isAndroid) {
var build = await deviceInfoPlugin.androidInfo;
identifier = build.id.toString();
} else if (Platform.isIOS) {
var data = await deviceInfoPlugin.iosInfo;
identifier = data.identifierForVendor;//UUID for iOS
}
} on PlatformException {
print('Failed to get platform version');
}
and after that to get the unique CFM token that Firebase provide for each device, you can get it using Firebase firebase_messaging plugin (https://pub.dev/packages/firebase_messaging) getToken() and insert the token to firestore (or an other database you want to store it)
FirebaseMessaging firebaseMessaging = new FirebaseMessaging();
firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound: true, badge: true, alert: true));
firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
});
firebaseMessaging.getToken().then((token){
print('--- Firebase toke here ---');
Firestore.instance.collection(constant.userID).document(identifier).setData({ 'token': token});
print(token);
});
After that you can insert one or more FCM token connected to multiple device for one user. 1 user ... n devices , 1 device ... 1 unique token to get push notifications from Firebase.
send it automatically when there is a new message for the person : now you need to call the Firestore API(is very fast indeed but need to be careful about the plan limit that you are using here) or another API call if you store the token to another db, in order to get the token/tokens for each user and send the push notifications.
To send the push notification from flutter you can use a Future async function.
P.s: I'm passing as argument a List here in order to use "registration_ids" instead of "to" and send the push notification to multiple tokens if the user has been logged in on multiple devices.
Future<bool> callOnFcmApiSendPushNotifications(List <String> userToken) async {
final postUrl = 'https://fcm.googleapis.com/fcm/send';
final data = {
"registration_ids" : userToken,
"collapse_key" : "type_a",
"notification" : {
"title": 'NewTextTitle',
"body" : 'NewTextBody',
}
};
final headers = {
'content-type': 'application/json',
'Authorization': constant.firebaseTokenAPIFCM // 'key=YOUR_SERVER_KEY'
};
final response = await http.post(postUrl,
body: json.encode(data),
encoding: Encoding.getByName('utf-8'),
headers: headers);
if (response.statusCode == 200) {
// on success do sth
print('test ok push CFM');
return true;
} else {
print(' CFM error');
// on failure do sth
return false;
}
}
You can also check the post call from postman in order to make some tests. POST request
On Headers add the:
key Authorization with value key=AAAAO........ // Project Overview -> Cloud Messaging -> Server Key
key Content-Type with value application/json
And on the body add
{
"registration_ids" :[ "userUniqueToken1", "userUniqueToken2",... ],
"collapse_key" : "type_a",
"notification" : {
"body" : "Test post",
"title": "Push notifications E"
}
}
"registration_ids" to send it to multiple tokens (same user logged in to more than on device at the same time)
"to" in order to send it to a single token (one device per user / or update always the user token that is connected with his device and have 1 token ... 1 user)
I'm making an edit to the response, in order to add that is very important to add the FCM Server Key on a trusted environment or server!
I'll list here a few related questions which I have participated with answers. I guess you'll find a lot of relevant info on using firebase cloud messaging (FCM) in a chat app.
Is FCM the only way to build a chat app ?
Suggested approach to use FCM in a chat app
Is using topics a better solution then using the fcmToken in a chat app?
Problems with FCM onMessage while app is in background
Problem: after logoff, user continues to receive notifications
Good luck!
//Notification Sending Side Using Dio flutter Library to make http post request
static Future<void> sendNotification(receiver,msg)async{
var token = await getToken(receiver);
print('token : $token');
final data = {
"notification": {"body": "Accept Ride Request", "title": "This is Ride Request"},
"priority": "high",
"data": {
"click_action": "FLUTTER_NOTIFICATION_CLICK",
"id": "1",
"status": "done"
},
"to": "$token"
};
final headers = {
'content-type': 'application/json',
'Authorization': 'key=AAAAY2mZqb4:APA91bH38d3b4mgc4YpVJ0eBgDez1jxEzCNTq1Re6sJQNZ2OJvyvlZJYx7ZASIrAj1DnSfVJL-29qsyPX6u8MyakmzlY-MRZeXOodkIdYoWgwvPVhNhJmfrTC6ZC2wG7lcmgXElA6E09'
};
BaseOptions options = new BaseOptions(
connectTimeout: 5000,
receiveTimeout: 3000,
headers: headers,
);
try {
final response = await Dio(options).post(postUrl,
data: data);
if (response.statusCode == 200) {
Fluttertoast.showToast(msg: 'Request Sent To Driver');
} else {
print('notification sending failed');
// on failure do sth
}
}
catch(e){
print('exception $e');
}
}
static Future<String> getToken(userId)async{
final Firestore _db = Firestore.instance;
var token;
await _db.collection('users')
.document(userId)
.collection('tokens').getDocuments().then((snapshot){
snapshot.documents.forEach((doc){
token = doc.documentID;
});
});
return token;
}
//Now Receiving End
class _LoginPageState extends State<LoginPage>
with SingleTickerProviderStateMixin {
final Firestore _db = Firestore.instance;
final FirebaseMessaging _fcm = FirebaseMessaging();
StreamSubscription iosSubscription;
//this code will go inside intiState function
if (Platform.isIOS) {
iosSubscription = _fcm.onIosSettingsRegistered.listen((data) {
// save the token OR subscribe to a topic here
});
_fcm.requestNotificationPermissions(IosNotificationSettings());
}
_fcm.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
showDialog(
context: context,
builder: (context) => AlertDialog(
content: ListTile(
title: Text(message['notification']['title']),
subtitle: Text(message['notification']['body']),
),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
// TODO optional
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
// TODO optional
},
);
//saving token while signing in or signing up
_saveDeviceToken(uid) async {
// FirebaseUser user = await _auth.currentUser();
// Get the token for this device
String fcmToken = await _fcm.getToken();
// Save it to Firestore
if (fcmToken != null) {
var tokens = _db
.collection('users')
.document(uid)
.collection('tokens')
.document(fcmToken);
await tokens.setData({
'token': fcmToken,
'createdAt': FieldValue.serverTimestamp(), // optional
'platform': Platform.operatingSystem // optional
});
}
}

Categories

Resources