how can get paylod data when I using FCM in flutter?
I tried used this methods, but I still could not got the data...
where has issues?
void getInitialMessage() async {
RemoteMessage? message =
await FirebaseMessaging.instance.getInitialMessage();
print(message?.data["type"]);
if (message != null) {
if (message.data["type"] == "noti") {
print("AAAAA");
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
PostDetailScreen(postid: message.data["postid"]),
),
);
} else if (message.data["type"] == "active") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PostDetailScreen(postid: '456'),
),
);
}
}
}
When I go to postman to test, I will send this format
Future<void> sendPushMessage(String token, String body, String title,
String postid, String images) async {
try {
await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization':
'key=AAAAm2nkpqg:APA91bH9l8kYkJqGyGnVJhUe4dmG5KeYVrErEB_vl7vhZDGBAgFGOYsyHguDna-SBeP8juVoTtLQ61aI61QZ-46JFwaR-8KPai7CT6n4-jRZFBIMOHEl1Ph',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{'body': body, 'title': title},
'priority': 'high',
'timeToLive': 24 * 60 * 60,
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done',
'type': 'noti',
'postid': 'Mi6Y3sE9E0uz4uAvQjwC'
},
"to": token,
},
),
);
} catch (e) {
print("error push notification");
}
}
I can receive the Notification, but I have setting "type": "noti". So when I click the notification message, it shoule be print AAAAA and Navigator to PostDetailScreen. But It's always open app then go to homepage....
Send out FCM message with this structure, here I use NodeJS Firebase Cloud Function, but the important thing is to add the second, options part:
await admin.messaging().sendToDevice(tokens, {
data: {
click_action: 'FLUTTER_NOTIFICATION_CLICK',
type: 'noti',
postid: 'ulEdnFiEZxyyc33UNvJs'
},
notification: {
title: 'title',
body: 'body'
},
}, {
contentAvailable: true,
priority: 'high',
timeToLive: 24 * 60 * 60, // in seconds
});
After this, in getInitialMessage you should have:
message.data['type'] // 'noti'
message.data['postid'] // 'ulEdnFiEZxyyc33UNvJs'
Related
i tried to send notification to another device when the app is terminated using workManager
it does not work, however the same function works if i use it without workManager
here is the code
in the main
await Workmanager().initialize(callBAckDispatcher, isInDebugMode: true);
callBackDispathcer
callBAckDispatcher() {
WidgetsFlutterBinding.ensureInitialized();
Firebase.initializeApp();
Workmanager().executeTask((taskName, inputData) async {
if (taskName == "t") {
int id = 7
await sFunction(id, await returnUserName());
}
return Future.value(true);
});
}
sFunction
sFunction(int id, String sender) async {
List<Map> response =
await SQLdb().readData('''SELECT * FROM `timer_chat` WHERE id = $id
''');
String reciever = response[0]['reciever'];
String message = response[0]['message'];
try {
String currentToken = await auth.getusertoken(reciever);
auth.sendnotify("my app",
"your message has been sent: " + message, "1", currentToken);
} catch (e) {
print("notification did not send: " + e.toString());
}
}
finally sendnotify
sendnotify(String title, String body, String id, String token) async {
try {
await http.post(
Uri.parse("https://fcm.googleapis.com/fcm/send"),
headers: <String, String>{
'content-type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
'body': body.toString(),
'title': title.toString()
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': "FLUTTER_NOTIFICATION_CLICK",
'id': id.toString(),
"name": "me",
"lastname": "wolf"
},
"to": token
},
),
);
} catch (e) {
print("something went wrong in notiiiii" + e.toString());
}
}
i'm sending notifications using firebase cloud messaging API. it worked fine inside the app but in workManager it does not. any idea why?
thank you
Main Screen
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String? payload) async {
try {
if (payload != null && payload.isNotEmpty) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewScreen(info: payload.toString())));
} else {}
} catch (e) {}
return;
});
void sendPushMessage(String token, String body, String title) async {
try {
await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization':
'key=thekey'
},
body: jsonEncode(<String, dynamic>{
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'status': 'done',
'body': body,
'title': title
},
"notification": <String, dynamic>{
"title": title,
"body": body,
"android_channel_id": "androidchannelid"
},
"to": token,
}),
);
} catch (e) {
if (kDebugMode) {
print('error push notifications');
}
}
}
When the notification is received it should be send to the new screen and not the main screen.
This code works when the app is in background or foreground but it is not working when the app is terminated.
What should i do?
Use to getInitialMessage to check if there is a message when a application is opened.
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
// TODO navigate to a specific page
}
See Handling Interaction for details.
i tried method using firebase_messaging: 7.0.1 but now its firebase_messaging: 14.0.2.
i got this error :
Converting object to an encodable object failed: Instance of 'Future<String?>'
sendNotif(String? title, String? body, String? id) async {
try {
await http
.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
'body': body.toString(),
'title': title.toString()
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': id.toString(),
},
'to': FirebaseMessaging.instance.getToken(),
},
),
)
.then((value) => (value) {
print("send succeffuly");
});
} catch (e) {
print("THe ERROR : $e");
}
}
As the error message says, FirebaseMessaging.instance.getToken() returns a Future<String>, while the post API expects only current (non-Future) values.
The simplest fix is to await the value:
'to': await FirebaseMessaging.instance.getToken(),
I am trying to redirect user to specific page in flutter web on click of notification, till now I am receiving notification, the last open page is displayed in browser on click of notification, but I want user to redirect to specific page like specific post using unique post id, but I found no other ways, This thing happens in Android build, but doesn't happen on web build.
just take a look at ServiceWorker.js
in serviceworker.js even console.log() in not executing on receiving notification.
messaging.setBackgroundMessageHandler(function (payload) {
console.log(payload);
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(payload);
}
})
.then(() => {
const title = payload.notification.title;
const options = {
body: payload.notification.body
};
return registration.showNotification(title, options);
});
return promiseChain;
});
self.addEventListener('notificationclick', function (event) {
console.log('notification received: ', event)
});
now the logic for sending FCM Push Notification:
#required String message,
#required String fcmToken,
#required String title,
String type,
String typeId,
}) async {
await http
.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
"click_action": 'FLUTTER_NOTIFICATION_CLICK',
'body': message,
'title': '$title',
'sound': 'default'
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done',
'type': type ?? "",
'typeId': typeId ?? "",
},
'to': fcmToken.toString().trim(),
},
),
)
.then((value) {
print("Notification Sent");
});
final Completer<Map<String, dynamic>> completer =
Completer<Map<String, dynamic>>();
// firebaseMessaging.configure(
// onMessage: (Map<String, dynamic> message) async {
// completer.complete(message);
// },
// );
return completer.future;
}
Now the way I am handling Notification Receive:
print("in setup interacted message");
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.max,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
NotificationSettings notifSettings =
await FirebaseMessaging.instance.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true,
);
if (notifSettings.authorizationStatus == AuthorizationStatus.authorized) {
// Get any messages which caused the application to open from
// a terminated state.
try {
RemoteMessage initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "post",
// navigate to a post screen
if (initialMessage != null && initialMessage.data['type'] == 'post') {
await Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => IndividualPostPage(
postObjectId: initialMessage.data['typeId'],
),
),
);
print(initialMessage.data);
initialMessage = null;
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp
.listen((RemoteMessage message) async {
print("here");
if (message != null && message.data['type'] == 'post') {
if (message.data['type'] == 'post') {
await Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => IndividualPostPage(
postObjectId: message.data['typeId'],
),
),
);
}
print(message.data);
message = null;
}
});
} catch (e) {
print("Error $e");
}
}
}
messaging.setBackgroundMessageHandler(function (payload) {
console.log(payload);
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(payload);
}
})
.then(() => {
const title = payload.notification.title;
var click_action =payload.data.ui_route;//ui route is ur route
const options = {
body: payload.notification.body ,
data: {
click_action,
}
};
return registration.showNotification(title, options);
});
return promiseChain;
});
// Notification click event listener
self.addEventListener('notificationclick', e => {
data=e.notification.data.obj;
// Close the notification popout
e.notification.close();
// Get all the Window clients
e.waitUntil(clients.matchAll({ type: 'window' }).then(clientsArr => {
// If a Window tab matching the targeted URL already exists, focus that;
const hadWindowToFocus = clientsArr.some(windowClient => windowClient.url === e.notification.data.click_action ? (windowClient.focus(), true) : false);
// Otherwise, open a new tab to the applicable URL and focus it.
if (!hadWindowToFocus) clients.openWindow(e.notification.data.click_action).then(windowClient => windowClient ? windowClient.focus() : null);
}));
});
I want to update the value of a constructor coming from page-1 to page-2. And I am using that value in an APIs response and wanted to update the response value with the new value.
Here is the code for better understanding.
Page-1 Code:
Future<void> forgotpass() async {
if (emailController.text.isNotEmpty) {
var response = await http
.post(Uri.parse('http://123.123.123/forgotPassword'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8",
},
body: jsonEncode({
"email": emailController.text,
}))
.then((response) {
print(response.statusCode);
print(response.body);
final parsedJson = json.decode(response.body);
var token = parsedJson['data']['forgotPasswordToken'];
var otp = parsedJson['data']['otp'];
print('OTP: $otp');
print("Token: $token");
if (response.body.contains('"statusCode":200')) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OtpVerifyPage(
text: token,
)));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Invalid Email')));
}
return response;
});
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Please Enter your Email Addrees')));
}
The token is been sent to a New Page-2.
Future<void> otpVerify() async {
if (otp.text.isNotEmpty) {
int newOtp = int.parse(otp.text);
var response = await http
.post(Uri.parse('http://123.123.123/verifyOtp'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8"
},
body: jsonEncode({
"forgotPasswordToken": widget.text, //wanted to update value here from when hitting resendCode() function.
"otp": newOtp,
}))
.then((response) {
print(response.statusCode);
print(response.body);
if (response.body.contains('"statusCode":200')) {
final parsedJson = json.decode(response.body);
var resetToken = parsedJson['data']['resetPasswordToken'];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SetNewPassPage(
text: resetToken,
)));
} else if (response.statusCode == 202) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Server issue. Please Try Again Later')));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Invalid OTP')));
}
return response;
});
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Please Enter your OTP')));
}
I am also using the resend OTP function as :
Future<void> resendCode() async {
// ignore: unused_local_variable
var response = await http
.post(Uri.parse('http://123.123.123/resendCode'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8"
},
body: jsonEncode({
"forgotPasswordToken": widget.text, //Getting new Token but can't update it in otpVerify() function.
}))
.then((response) {
print(response.statusCode);
print(response.body);
final parsedJson = json.decode(response.body);
var token = parsedJson['data']['forgotPasswordToken'];
var otp = parsedJson['data']['otp'];
print('OTP: $otp');
print("Token: $token");
if (response.body.contains('"statusCode":200')) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('OTP Send to your Email ID')));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Try again later')));
}
return response;
});
}
Now I wanted to update the "forgotPasswordToken" in the body of otpVerify().
Its updating in resendCode() function but not in otpVerify(). So if anyone knows how to solve this issue please help.
Here is the UI snapshot for better understanding: Page-1 & Page-2
What you can simply do is put this in resendCode function this will refresh your page with new values.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OtpVerifyPage(text: token)));
Full code for better understanding:
Future<void> resendCode() async {
// ignore: unused_local_variable
var response = await http
.post(Uri.parse('http://123.123.123/resendCode'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8"
},
body: jsonEncode({
"forgotPasswordToken": widget.text,
}))
.then((response) {
print(response.statusCode);
print(response.body);
final parsedJson = json.decode(response.body);
var token = parsedJson['data']['forgotPasswordToken'];
var otp = parsedJson['data']['otp'];
print('OTP: $otp');
print("Token: $token");
if (response.body.contains('"statusCode":200')) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OtpVerifyPage(text: token))); // Added here to refresh the page with new value of token.
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('OTP Send to your Email ID')));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Try again later')));
}
return response;
});