I'm using the firebase_messaging package on my flutter app and it works perfectly for everything except that when the app on the background and I get a notification it only opens the app and never do what I ask it does after opening the app ..here is my code:
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print("Handling a background message: ${message.messageId}");
final dynamic data = message.data;
print("data is $data");
if(data.containsKey('request_id')) {
print("we are inside ..!");
RegExp exp = RegExp(r'\d+');
var id = int.parse(exp.firstMatch(data['request_id']!)!.group(0)!);
OpenRequestsController openRequestsController = Get.isRegistered<OpenRequestsController>()?Get.find():Get.put(OpenRequestsController());
OpenRequest matchingRequest = openRequestsController.openRequestsList.firstWhere((request) => request.id == id);
print("the request from the list is $matchingRequest");
openRequestsController.openRequestDetails(matchingRequest,false);
}
}
what happens here is that it tries to run the whole function when the message is received not when clicked .. and ofc it fails because the app is not already running in the foreground
For opening the application and moving to the said screen you need to implement onMessageOpenedApp in the initstate of your first stateful widget which will let the application to know that it is supposed to open the application when a notification being clicked. The code function should look like this:
FirebaseMessaging.onMessageOpenedApp.listen((message) {
Get.to(() => const MainScreen()); // add logic here
});
It is better if you could assign identifiers for the type of screens you want to open on clicking a particular notification while sending the notification and implement an if-else or switch statement here on the basis of message type.
Thanks
Related
Is it possible to cancel a pushed notification before displaying it on the users phone ?
I have some custom logic which decides whether a notification needs to be displayed/appear . Is it possible for me to control this behaviour from the client side ios/android code ?
Once a message is sent to Firebase Cloud Message, there is no way to cancel its delivery.
If your message contains only a data element and no notification, displaying the message is handled by your application code - so in that case you may be able to suppress its display there.
Although the best way is to handle this is to cancel it on backend side, you still can add UNNotificationServiceExtension and override the didReceive method:
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
self.receivedRequest = request;
self.contentHandler = contentHandler
self.content = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let content = self.content {
// I had to check something inside the push itself
if let infoDictionary = content.userInfo {
// Check something inside the push notification
contentHandler(content)
return
}
}
// Otherwise, send an empty notification to the system and it will show nothing
contentHandler(UNNotificationContent())
}
I'm starting my adventure with Firebase cloud functions in my adnroid app in Android Studio and I have no experience with it. What is more I have never used javascript before so everything seems to be new for me. I would like to know if I can make a scheduled function that works like this :
At first function checks if value from realtime databse isn't zero.
If not, function checks if another value from realtime database is not bigger than 7.
If not, the value in database is increased by 1.
And then the notification is send.
I made test function to check if data from database are taken corectly but it execute with error "Firebase is not defined".
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun((context) => {
var user = user.uid;
var myRef = firebase.database().ref(user + "/CurrentChallenge/numOfActiveChallenge");
myRef.on('value', (snapshot) => {
const data = snapshot.val();
console.log(data);
});
In a Cloud Function, if you want to interact with the Firebase services, you need to use the Admin SDK.
Also, if you want to read a database node in a Cloud Function, it is more appropriate to read once the node (with get() or once()) instead of setting a listener with on(). As a matter of fact the CF has a short life time and setting a listener is therefore not the correct approach.
It is nor clear how you get the value of the user variable. There is no user in a Scheduled Cloud Function. You need to adapt this line, because, as such it will not work.
Finally, it is important to note that you need to terminate a Cloud Function when all the asynchronous work is completed, see the doc. In the case of a background triggered Cloud Function (e.g. a Pub/Sub schedules Cloud Function) you must return the entire chain of promises returned by the asynchronous method calls. Another possibility is to use async/await, as shown below, and return a value (e.g. null) when all the asynchronous work is completed.
So, the following code skeleton should do the trick:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {
var user = ... // Set the value of user
const db = admin.database(); // Admin SDK
const snapshot1 = await db.database().ref("...").get();
if (snapshot1.val() !== 0) {
const snapshot2 = await db.database().ref("...").get();
if (snapshot2.val() <= 7) {
await db.ref("...").update({
fieldName: firebase.database.ServerValue.increment(1)
});
//send the notification
// See https://github.com/firebase/functions-samples/blob/main/fcm-notifications/functions/index.js
} else {
return null;
}
} else {
return null;
}
});
Cloud functions are secure environment just like any server. Generally you use the Firebase Admin SDK when using Firebase in Cloud functions or your own servers. To add firebase admin, open terminal and go to the function directory and run the following command:
npm install firebase-admin
The important thing to note is admin sdk doesn't obey any database security rules as the name says. It has privileged access.
You can try the following code.
const admin = require("firebase-admin")
admin.initializeApp()
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {
const myRef1Value = (await admin.database().ref("path/to/resoures").once("value")).val()
if (myRef1Value > 0) {
//make another request
}
}
Similarly make multiple requests as needed (sorry for throwing bunch of JS concepts but feel free to ask any queries)
Another thing I noticed is you are trying to get user ID in it. Scheduled Cloud Functions are not invoked by any user so you can't get any UID in that Cloud function. Can you clarify what is your use case so we can figure out a work around for this?
But what you want to achieve is simple chain if else statements and doing stuff.
You'll need to import and initialize the Firebase Admin SDK as shown here:
// The Firebase Admin SDK to access the database
const admin = require('firebase-admin');
admin.initializeApp();
With that, you can then use it with:
var myRef = admin.database().ref(user + "/CurrentChallenge/numOfActiveChallenge");
myRef.once('value', (snapshot) => {
...
I am working on one app in react-native. I want to do this kind of functionality.
1)When the user will log in from 1st device with their credential at that time I am storing device ID in my firestore database.
now, If the user will do sign in from 2nd device with the same credential at that time I am going to log out that user from 1st device. I have implemented that logic.
But the issue is this is not happening in real-time. When I will restart the 1st device's application at that time this logic works.
Is there any type of method that triggers when my database updates?
I want this logic to works immediately when the user logs in from another device with the same ID.
const onAuthStateChanged = async (user) => {
setUser(user);
if (user) {
//here i am checking for token
await firestore()
.collection('Users')
.doc(user.email)
.get()
.then((documentSnapshot) => {
const data_device = documentSnapshot.data();
if (device_id != data_device.device_token) {
alert('you are signned in other device'); //and if not as same then logout
logout();
}
});
}
if (inisiallizing) setInisiallizing(false);
};
The onAuthStateChanged only run when the authState changed (Login, logout, register) and its state is run on it own (not run in multiple environment, devices).
As your usecase, I think you should listen to a documents on Firestore that store your deviceId
firestore()
.collection('Users')
.doc(user.email)
.onSnapshot((doc) => {
// Your logic to logout here
})
The above code will run everytime document firestore().collection('Users').doc(user.email) has update
I just learned about notifications in the expo, now I have successfully sent notifications and I have also managed to get data from the notifications I sent, the problem is, if the application is in background or foreground, addNotificationResponseReceivedListener is working properly (redirect to another page), but if I close the application, and I receive a notification, then I press the notification, the application opens but the addNotificationResponseReceivedListener function is not running, I try this in a standalone application
what i’m using:
“expo”: “~40.0.0”,
“expo-notifications”: “^0.9.0”,
here’s my example code in Home.js:
componentDidMount() {
//another code..
Notifications.addNotificationResponseReceivedListener(
this._handleNotificationResponse
);
}
_handleNotificationResponse = (response) => {
console.log(
"CONSOLE FROM NOTIF: " +
JSON.stringify(response.notification.request.content.data.from)
);
if (response.notification.request.content.data.from== "GEMASS") {
this.props.navigation.navigate("goToPage", {
//another code...
});
} else {
}
};
here’s my file tree:
App.js
Components
- Home.js
and here’s my terminal looks like when i run on expo client:
clickme
can you guys help me? it means a lot :)
I'm building Flutter android app for webrtc calls. When a call is coming I use Firebase Cloud Messages (background data messages) to notify my app. Using callkeep flutter plugin I can show incoming call screen. Everything works grate but I don't know how to open flutter app when it is terminated (not in background). I receive background notification and can run some code (e.g. show local notification, show incoming call screen) but I don't know how to open my app. Any suggestions?
You can use connectycube_flutter_call_kit package after which you can then navigate to the desired screen
ConnectycubeFlutterCallKit.instance.init(
onCallAccepted: (String sessionId, int callType, int callerId,
String callerName, Set opponentsIds
, Map callOpponentsop
) async {
// Navigator.pushNAmed()
return null;
},
onCallRejected: (String sessionId, int callType, int callerId,
String callerName, Set opponentsIds
, Map callOpponents
) {
return null;
},
);