This question already has an answer here:
Generate Flutter Local Notification when background FCM Triggers
(1 answer)
Closed 1 year ago.
I am trying to use Firebase messaging in Flutter app. Somewhere I am missing something so I am facing with errors...
My notification_handler code;
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
Future<void> myBackgroundMessageHandler(Map<String, dynamic> message) {
if (message.containsKey('data')) {
// Handle data message
NotificationHandler.showNotification(message);
}
return Future<void>.value();
}
class NotificationHandler {
FirebaseMessaging _fcm = FirebaseMessaging();
static final NotificationHandler _singleton = NotificationHandler._internal();
factory NotificationHandler() {
return _singleton;
}
NotificationHandler._internal();
BuildContext myContext;
initializeFCMNotification(BuildContext context) async {
myContext = context;
var initializationSettingsAndroid = AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = IOSInitializationSettings(onDidReceiveLocalNotification: onDidReceiveLocalNotification);
var initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: onSelectNotification);
_fcm.onTokenRefresh.listen((newToken) async {
User _currentUser = FirebaseAuth.instance.currentUser;
await FirebaseFirestore.instance.doc("tokens/" + _currentUser.uid).set({"token": newToken});
});
_fcm.configure(
onMessage: (Map<String, dynamic> message) async {
//print("onMessage tetiklendi: $message");
showNotification(message);
},
onBackgroundMessage: myBackgroundMessageHandler,
onLaunch: (Map<String, dynamic> message) async {
//print("onLaunch tetiklendi: $message");
},
onResume: (Map<String, dynamic> message) async {
// print("onResume tetiklendi: $message");
},
);
}
static void showNotification(Map<String, dynamic> message) async {
var mesaj = Person(
name: message["data"]["title"],
key: '1',
//icon: userURLPath,
icon: DrawableResourceAndroidIcon('daisy'),
);
var mesajStyle = MessagingStyleInformation(mesaj, messages: [Message(message["data"]["message"], DateTime.now(), mesaj)]);
var androidPlatformChannelSpecifics = AndroidNotificationDetails('1234', 'Yeni Mesaj', 'your channel description',
styleInformation: mesajStyle, importance: Importance.max, priority: Priority.high, ticker: 'ticker');
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.showDailyAtTime(
1,
message["data"]["title"],
"Dont Forget to Set Your Weight in Today**",
Time(20,44,0),
platformChannelSpecifics,
);
print("handler succesful");
}
Future onSelectNotification(String payload) async {
final _userModel = Provider.of<UserModel>(myContext);
if (payload != null) {
// debugPrint('notification payload: ' + payload);
Map<String, dynamic> gelenBildirim = await jsonDecode(payload);
}
}
Future onDidReceiveLocalNotification(int id, String title, String body, String payload) {}
}
Instead of notification, I gets that below error and the app shut downs.
PID: 21082
E/AndroidRuntime(21082): java.lang.RuntimeException: Unable to start receiver com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
E/AndroidRuntime(21082): at android.app.ActivityThread.handleReceiver(ActivityThread.java:3259)
E/AndroidRuntime(21082): at android.app.ActivityThread.-wrap17(Unknown Source:0)
E/AndroidRuntime(21082): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1677)
E/AndroidRuntime(21082): at android.os.Handler.dispatchMessage(Handler.java:105)
E/AndroidRuntime(21082): at android.os.Looper.loop(Looper.java:164)
E/AndroidRuntime(21082): at android.app.ActivityThread.main(ActivityThread.java:6541)
E/AndroidRuntime(21082): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(21082): at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
E/AndroidRuntime(21082): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
E/AndroidRuntime(21082): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
E/AndroidRuntime(21082): at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.setSmallIcon(FlutterLocalNotificationsPlugin.java:237)
E/AndroidRuntime(21082): at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:179)
E/AndroidRuntime(21082): at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.showNotification(FlutterLocalNotificationsPlugin.java:791)
E/AndroidRuntime(21082): at com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver.onReceive(ScheduledNotificationReceiver.java:46)
E/AndroidRuntime(21082): at android.app.ActivityThread.handleReceiver(ActivityThread.java:3252)
E/AndroidRuntime(21082): ... 8 more
F/crash_dump64(25605): crash_dump.cpp:235] target died before we could attach (received main tid = 25603)
Lost connection to device.
I noticed that there were questions asked about this error before And solved the problem. Here is the link;
Generate Flutter Local Notification when background FCM Triggers
Related
I have built my app in flutter and I have implemented both LocalNotifications and FCM messaging.
this is my code:
final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
#override
void initState() {
super.initState();
registerNotification();
configLocalNotification();
}
void registerNotification() {
firebaseMessaging.requestNotificationPermissions();
firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
return ;
}, onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NotificationsScreen()));
},
onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
});
firebaseMessaging.getToken().then((token) {
print('token: $token');
FirebaseFirestore.instance
.collection('Consultant')
.doc(firebaseUser.uid)
.update({'deviceToken': token});
}).catchError((err) {
//Fluttertoast.showToast(msg: err.message.toString());
});
}
Future selectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
await Navigator.push(
context,
MaterialPageRoute<void>(builder: (context) => NotificationsScreen(payload: payload,)),
);
}
void showNotification(message) async {
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
Platform.isAndroid
? 'it.wytex.vibeland_pro_app'
: 'it.wytex.vibeland_pro_app',
'Vibeland Pro',
'Vibeland Pro',
playSound: true,
enableVibration: true,
importance: Importance.max,
priority: Priority.high,
);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
android: androidPlatformChannelSpecifics, iOS: 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));
await flutterLocalNotificationsPlugin.show(
1, '📩 Hai ricevuto un messaggio 📩 ', 'Controlla subito le Tue notifiche 🔔🔔', platformChannelSpecifics,
payload: 'item x',
);
}
void configLocalNotification() {
var initializationSettingsAndroid =
new AndroidInitializationSettings('#mipmap/ic_launcher');
var initializationSettingsIOS = new IOSInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
var initializationSettings = new InitializationSettings(
android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
I have built a function in firebase to push some New collections as notifications.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
const fcm = admin.messaging();
exports.sendNotification = functions.firestore
.document("Notifications/{id}")
.onCreate((snapshot) => {
const name = snapshot.get("name");
const subject = snapshot.get("subject");
const token = snapshot.get("token");
const payload = {
notification: {
title: "" + name,
body: "" + subject,
sound: "default",
click_action: "FLUTTER_NOTIFICATION_CLICK",
},
};
return fcm.sendToDevice(token, payload);
});
the version of firebase_messaging: ^7.0.3 and flutter_local_notifications: ^4.0.1
at the moment I don't upgrade due to some conflict with dependencies.
In this way I got both notifications when an app is open I get Local notifications correctly and when an app is in foreground and background I get Firebasemessaging according to the new collection added into my firestore.
The problem now comes when I close the app or the app after some minutes starts to sleep...
I can't get any notifications
To start again to get notifications, I need to run again the app and wake the app.
This is a problem with my app because my Apps notifications are very important and users need to get them always.
As you can on the FlutterFire documentation, foreground and background notification are handled differently by the plugin, so there are 2 thing you need to fix in your app.
First you need to prepare your Cloud Function to send background notifications as well as foreground, and in order to to that, you need to prepare your json to not only have a notification but also a data field, as follows:
const payload = {
notification: {
title: "" + name,
body: "" + subject,
sound: "default",
},
data: {
click_action: "FLUTTER_NOTIFICATION_CLICK"
}
};
Second, you are going to need configure your firebaseMassaging to receive background messages, like this:
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
return ;
},
onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NotificationsScreen()));
},
onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
},
onBackgroundMessage: myBackgroundMessageHandler
);
And finally you need to create a handler that will manually handle background messages, following the example in the documentation you can do something like this:
Future<void> myBackgroundMessageHandler(RemoteMessage message) async {
print("Handling a background message: ${message}");
}
Adding the Line:
onBackgroundMessage: myBackgroundMessageHandler
Future<void> myBackgroundMessageHandler(RemoteMessage message) async {
print("Handling a background message: ${message}");
}
I got these error:
Nexus, [10.03.21 16:59]
[ File : app-release.apk ]
Amore, [10.03.21 17:09]
java.lang.RuntimeException: Unable to create service io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService: java.lang.RuntimeException: PluginRegistrantCallback is not set.
at android.app.ActivityThread.handleCreateService(ActivityThread.java:4023)
at android.app.ActivityThread.access$1600(ActivityThread.java:224)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1903)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7562)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.lang.RuntimeException: PluginRegistrantCallback is not set.
at io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService.C(Unknown Source:70)
at io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService.onCreate(Unknown Source:40)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:4011)
... 8 more
I wanted to change the package name of my project so I changed the applicationId in build.gradle and in android.xml.
I changed package name using below guide
https://medium.com/#skyblazar.cc/how-to-change-the-package-name-of-your-flutter-app-4529e6e6e6fc
Firebase database was linked with my project so I thought I had to change the package name in Firebase too. So, I added new app in Firebase with UPDATED package name of the project and added SHA key as required. After doing all this I started to test my app. Everything is working fine except phone authentication. Google authentication is working fine.
I don't know why, while phone authentication, I get below error and app get crashed. Build in function FirebaseAuth.instance.verifyPhoneNumber never executed. I'm wondering why?
Error before termination of the app
I/flutter (15570): New user result at the end before await: null
E/zzf (15570): Problem retrieving SafetyNet Token: 7:
W/ActivityThread(15570): handleWindowVisibility: no activity for token android.os.BinderProxy#7518a38
D/ViewRootImpl#9a0d0b4[MainActivity](15570): MSG_WINDOW_FOCUS_CHANGED 0 1
D/InputMethodManager(15570): prepareNavigationBarInfo() DecorView#b62e3fa[MainActivity]
D/InputMethodManager(15570): getNavigationBarColor() -855310
I/DecorView(15570): createDecorCaptionView >> DecorView#1ec25a[], isFloating: false, isApplication: true, hasWindowDecorCaption: false, hasWindowControllerCallback: true
W/System (15570): Ignoring header X-Firebase-Locale because its value was null.
I/System.out(15570): (HTTPLog)-Static: isSBSettingEnabled false
I/System.out(15570): (HTTPLog)-Static: isSBSettingEnabled false
D/InputTransport(15570): Input channel constructed: fd=97
D/ViewRootImpl#141d474[RecaptchaActivity](15570): setView = DecorView#1ec25a[RecaptchaActivity] TM=true MM=false
D/ViewRootImpl#141d474[RecaptchaActivity](15570): dispatchAttachedToWindow
D/ViewRootImpl#141d474[RecaptchaActivity](15570): Relayout returned: old=[0,0][1080,2220] new=[0,0][1080,2220] result=0x7 surface={valid=true 545211748352} changed=true
D/OpenGLRenderer(15570): eglCreateWindowSurface = 0x7efbe16f80, 0x7ef1271010
D/ViewRootImpl#141d474[RecaptchaActivity](15570): MSG_RESIZED: frame=Rect(0, 0 - 1080, 2220) ci=Rect(0, 63 - 0, 0) vi=Rect(0, 63 - 0, 0) or=1
D/InputTransport(15570): Input channel destroyed: fd=132
D/AndroidRuntime(15570): Shutting down VM
E/AndroidRuntime(15570): FATAL EXCEPTION: main
E/AndroidRuntime(15570): Process: com.xxxxx.xxxxx, PID: 15570
E/AndroidRuntime(15570): java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/browser/customtabs/CustomTabsIntent$Builder;
E/AndroidRuntime(15570): at com.google.firebase.auth.internal.RecaptchaActivity.zza(com.google.firebase:firebase-auth##20.0.1:13)
E/AndroidRuntime(15570): at com.google.android.gms.internal.firebase-auth-api.zzth.zzb(com.google.firebase:firebase-auth##20.0.1:7)
E/AndroidRuntime(15570): at com.google.android.gms.internal.firebase-auth-api.zzth.onPostExecute(Unknown Source:2)
E/AndroidRuntime(15570): at android.os.AsyncTask.finish(AsyncTask.java:695)
E/AndroidRuntime(15570): at android.os.AsyncTask.access$600(AsyncTask.java:180)
E/AndroidRuntime(15570): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
E/AndroidRuntime(15570): at android.os.Handler.dispatchMessage(Handler.java:106)
E/AndroidRuntime(15570): at android.os.Looper.loop(Looper.java:214)
E/AndroidRuntime(15570): at android.app.ActivityThread.main(ActivityThread.java:7073)
E/AndroidRuntime(15570): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(15570): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
E/AndroidRuntime(15570): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
E/AndroidRuntime(15570): Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.browser.customtabs.CustomTabsIntent$Builder" on path: DexPathList[[zip file "/data/app/com.storeifie.storeify-DOxHXgyJA9JAe6BK8YeeWA==/base.apk"],nativeLibraryDirectories=[/data/app/com.storeifie.storeify-DOxHXgyJA9JAe6BK8YeeWA==/lib/arm64, /data/app/com.storeifie.storeify-DOxHXgyJA9JAe6BK8YeeWA==/base.apk!/lib/arm64-v8a, /system/lib64, /system/vendor/lib64]]
E/AndroidRuntime(15570): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
E/AndroidRuntime(15570): at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
E/AndroidRuntime(15570): at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
E/AndroidRuntime(15570): ... 12 more
I/Process (15570): Sending signal. PID: 15570 SIG: 9
Lost connection to device.
Exited (sigterm)
Below is the code snippet of verifyPhone function.
In below code snippet await FirebaseAuth.instance.verifyPhoneNumber never ran.
verificationComplete and smsCodeSent never got executed. I'm wondering why? It was working fine before changing package name
Future<dynamic> verifyPhone(phoneNo, BuildContext context) async {
var completer = Completer<dynamic>();
dynamic newUserResult;
Future<String> getOTPresult() async {
print("Dialog shown");
await showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (context) => Container(
height: 270,
child: OTPBottomSheet(controller: _otpController),
),
);
return _otpController.text;
}
// >>>>>>>>>>>>> On Complete
final PhoneVerificationCompleted verificationComplete =
(AuthCredential authCred) async {
print(" I N S I D E C O M P L E T E ");
newUserResult = await signInWithPhoneNumber(authCred);
completer.complete(newUserResult);
};
// >>>>>>>>>>>>> On Timeout
final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verID) {
print("\n2. Auto retrieval time out");
completer.complete(newUserResult);
};
// >>>>>>>>>>>>> On manual code verification
final PhoneCodeSent smsCodeSent =
(String verID, [int forceCodeResend]) async {
print(" I N S I D E C O D E S E N T");
var OTPDialogResult = await getOTPresult();
if (OTPDialogResult != null) {
AuthCredential authCred = PhoneAuthProvider.credential(
verificationId: verID, smsCode: OTPDialogResult);
newUserResult = AuthService().signInWithPhoneNumber(authCred);
if (!completer.isCompleted) {
completer.complete(newUserResult);
}
}
};
// >>>>>>>>>>>>> On Ver failed
final PhoneVerificationFailed verificationFailed =
(Exception authException) {
completer.complete(newUserResult);
};
await FirebaseAuth.instance
.verifyPhoneNumber(
phoneNumber: phoneNo,
timeout: Duration(seconds: 50),
verificationCompleted: verificationComplete,
verificationFailed: verificationFailed,
codeSent: smsCodeSent,
codeAutoRetrievalTimeout: autoRetrieve,
).catchError((error) {
print(error.toString());
});
print("New user result at the end before await: " + newUserResult.toString());
newUserResult = await completer.future;
print("New user result at the end after await: " + newUserResult.toString());
return newUserResult;
}
signInWithPhoneNumber function
Future signInWithPhoneNumber(AuthCredential authCreds) async {
try {
UserCredential result = await FirebaseAuth.instance.signInWithCredential(authCreds);
User customUser = result.user;
return _userFormFirebaseUser(customUser).getuid;
}
CustData _userFormFirebaseUser(User user) {
print("----> Inside _userFormFirebaseUser and user ID: " + user.uid);
return user != null
? CustData(
custId: user.uid,
)
: null;
}
// --- CustData model class
class CustData {
String custId;
String custName;
String custPhNo;
String custContactNO;
DateTime custDateOfBirth;
Map<String, dynamic> address;
String cartID;
CustData({
this.custId,
this.custName,
this.custPhNo,
this.custDateOfBirth,
this.address,
this.cartID,
this.custContactNO,
});
CustData.initial() : custId = '';
String get getuid => this.custId;
}
I solved the problem by simply adding below line into app/build.gradle dependencies.
implementation "androidx.browser:browser:1.2.0"
I'm using firebase_messaging 6.0.9 with flutter 1.12.13. In the repo's readme: https://pub.dev/packages/firebase_messaging#-readme-tab- it says to declare the onBackgroudMessage callback as a static or top level method. Which I did, but it doesn't work when this callback invokes a non-static method. The following example demonstrates this with a singleton class:
class NotificationService {
static NotificationService _instance;
final FirebaseMessaging _firebase;
static NotificationService get instance => _instance;
NotificationService._internal() : this._firebase = FirebaseMessaging();
factory NotificationService() {
if (_instance == null) {
_instance = NotificationService._internal();
_instance._firebase.configure(
onBackgroundMessage: NotificationService.staticHandler
);
}
return _instance;
}
static Future<dynamic> staticHandler(Map<String, dynamic> msg) {
print("Static Func >>> $msg"); // Successfully prints
return NotificationService.instance.instanceFunc(msg); // Fails here, complaining that it's being invoked on null.
}
Future<dynamic> instanceFunc(Map<String, dynamic> msg) {
print("Instance Func >>> $msg");
}
void myVarFunc() {
print("This is my var func");
}
}
in main.dart, the notification service factory constructor is called:
import 'package:myProject/services/notification/notification_service.dart';
run(MyApp());
class MyApp extends StatelessWidget {
final NotificationService _ns = NotificationService();
NotificationService.instance.myVarFunc(); // Prints successfully.
.......
.......
.......
}
The invocation of instanceFunc fails, saying it's being called on null. The following are the logs:
I/flutter ( 6935): Static Func >>> {data: {title: Title_is_here, message: Message_is_here}}
I/flutter ( 6935): Unable to handle incoming background message.
I/flutter ( 6935): NoSuchMethodError: The method 'instanceFunc' was called on null.
I/flutter ( 6935): Receiver: null
I/flutter ( 6935): Tried calling: instanceFunc(_LinkedHashMap len:1)
I'm not really sure if this is right way to handle this scenario. Since I'm new to Dart and Flutter, my knowledge is pretty limited. I can't declare everything static and work, that's not good design IMO. I'm probably missing something here.
There are some reason of not getting callback on onBackgroundMessage:-
onBackgroundMessage didn't worked on iOS so you have to implement platform check
For example:-
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
printDebug("onMessage foreground: $message");
},
onBackgroundMessage: Platform.isIOS ? null : _myBackgroundMessageHandler,
onLaunch: (Map<String, dynamic> message) async {
printDebug("onLaunch Kill: $message");
},
onResume: (Map<String, dynamic> message) async {
print("onResume Background: $message");
},
);
static Future<dynamic> _myBackgroundMessageHandler(
Map<String, dynamic> message) async {
print("onBackgroundMessage: $message");
return Future<void>.value();
}
And You have to make sure that your Notification payload didn't contain the notification key because if notification key is exist in payload then notification directly handled by your system. So you have to remove the notification key from payload to get callback on onBackgroundMessage.
Note:- If you remove the notification key then notification didn't rendered in systems notification tray. For this you can you local notification.
I have an application that is supposed to send the Firebase Token from my Flutter app to an ASP.Net App Server. The endpoint on the app server works - the request from the Flutter app to the App Server is not working.
The reason it is not working is because when I try to send the token, the token doesn't appear to have arrived yet - it's of type Future. How do I turn that token into a string when it finally arrives?
I've tried turning the token directly into a string in the fcmStream.Listen function, I've also tried turning it into a string using _firebaseMessaging.getToken. Neither of them work
FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
#override
void initState() {
// TODO: implement initState
super.initState();
location.onLocationChanged().listen((value) {
if (this.mounted) {
setState(() {
currentLocation = value;
});
}
});
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) {
print('on message $message');
},
onResume: (Map<String, dynamic> message) {
print('on resume $message');
},
onLaunch: (Map<String, dynamic> message) {
print('on launch $message');
},
);
_firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound: true, badge: true, alert: true));
String clientToken = _firebaseMessaging.getToken().then((token) {
print("Token Init: " + token.toString());
}
).toString();
BackendService.postToken(clientToken.toString(), "email#gmail.com");
#override
Stream<String> fcmStream = _firebaseMessaging.onTokenRefresh;
fcmStream.listen((token) {
/*print("Token On Refresh: " + token);
BackendService.postToken(token.toString(), "email#gmail.com");*/
}
);
fcmStream.toString();
class BackendService {
static Future<String> postToken(String token, String hostEmail) async {
final responseBody = (await http.get(
'realurlomitted/.../Meets/RegisterDevice?token=$token&hostEmail=$hostEmail')).body;
print(" Response: " + responseBody.toString());
return responseBody.toString();
}
}
Whenever the token.toString prints, it prints the token just fine - I can see that. It just seems like whenever it tries to make the post using http, the token hasn't arrived from whatever getToken is.
If I can turn that Futrure into a string by awaiting it or something, it would solve my problem so that the $token parameter is the token as a string.
More specifically, my request URL should look like:
https://-----/Meets/RegisterDevice?token=c6V49umapn0:Jdsf90832094890s324&hostEmail=email#gmail.com
But it looks like:
https://-----/Meets/RegisterDevice?token=instance of Future<Dynamic>&hostEmail=email#gmail.com
In the Flutter debugger
As you said, awaiting the future will solve your problem. You can write an async function and put the code in your initState inside it and use await, or you can do this:
_firebaseMessaging.getToken().then((token) {
final tokenStr = token.toString();
// do whatever you want with the token here
}
);
This style is now available
FirebaseAuth.instance.currentUser().then((user) {
if (user != null) {
user.getIdToken().then((token) {
Map<dynamic,dynamic> tokenMap = token.claims;
print(tokenMap['sub']);
});
}
});
so this complete code
#override
void initState() {
FirebaseAuth.instance.currentUser().then((user) {
if (user != null) {
user.getIdToken().then((token) {
Map<dynamic,dynamic> tokenMap = token.claims;
print(tokenMap['sub']);
});
}
});
super.initState();
}
I try to send a message from my website to users with Firebase and store the message in the user device with sqflite plugin.
When the application in the foreground, everything works good and message insert in the database. But when the application in the background or completely close it just displays notification and data not inserted in the database.
edit:
After setting click_action for notification, Clicking on the notification data will be saved but if the user dismisses notification data lost.
code
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
#override
void initState() {
prepareFirebaseCloudMessaging();
super.initState();
}
void prepareFirebaseCloudMessaging() {
if (Platform.isIOS) IOSPermission();
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
notificationDataHandler(message);
},
onResume: (Map<String, dynamic> message) async {
notificationDataHandler(message);
},
onLaunch: (Map<String, dynamic> message) async {
notificationDataHandler(message);
},
);
}
void notificationDataHandler(Map<String, dynamic> message) async {
try {
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'MY_DATABASE_FILE.db');
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
'CREATE TABLE Messages (id INTEGER PRIMARY KEY, message TEXT, date TEXT, seen INTEGER)');
});
Message messageStore = Message(
null, message["data"]["message"], message["data"]["date"], false);
await database.insert("Messages", messageStore.toMap());
database.close();
}catch(e){
debugPrint(e.toString());
}
}