Save and Retrieve notification with shared preferences list flutter - flutter

I have implemented Firebase Cloud Messaging in my flutter application. Everything works well but I want to store all list of messages locally with shared preferences and retrieve them in another screen. All my logic does not work well as I can't save the messages when the onMessage function is called.
PushNotificationService
class PushNotificationService {
final FirebaseMessaging _fcm = FirebaseMessaging();
List<String> titles;
List<String> msgs;
Future initialise() async {
notiList = List<NotiMessage>();
if (Platform.isIOS) {
// request permissions if we're on android
_fcm.requestNotificationPermissions(IosNotificationSettings());
_fcm.configure();
// For testing purposes print the Firebase Messaging token
String token = await _fcm.getToken();
print("FirebaseMessaging token: $token");
} else{
String token = await _fcm.getToken();
print("FirebaseMessaging token: $token");
}
_fcm.configure(
// Called when the app is in the foreground and we receive a push notification
onMessage: (Map<String, dynamic> message) async {
print('onMessage: $message');
//add list of messages to shared preferences
_setMessage(message);
},
// Called when the app has been closed comlpetely and it's opened
// from the push notification.
onLaunch: (Map<String, dynamic> message) async {
print('onLaunch: $message');
_serialiseAndNavigate(message);
//add list of messages to shared preferences
_setMessage(message);
},
// Called when the app is in the background and it's opened
// from the push notification.
onResume: (Map<String, dynamic> message) async {
print('onResume: $message');
_serialiseAndNavigate(message);
//add list of messages to shared preferences
_setMessage(message);
},
);
}
void _serialiseAndNavigate(Map<String, dynamic> message) {
var notificationData = message['data'];
var view = notificationData['view'];
if (view != null) {
// Navigate to desired page
if (view == 'create_post') {
}
}
}
_setMessage(Map<String, dynamic> message) {
//add list of messages to shared preferences
final notification = message['notification'];
final data = message['data'];
final String title = notification['title'];
final String body = notification['body'];
String mMessage = data['message'];
//add to list
titles.add(title);
msgs.add(mMessage);
//save to shared preferences (does not work)
storeTitles(titles);
storeMsgs(msgs);
print("Title: $title, body: $body, message: $mMessage");
}
void storeTitles(List<String> list) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setStringList("notiTitles", list);
//list returns null
}
void storeMsgs(List<String> list) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setStringList("notiMsgs", list);
}
Future<List<String>> getTitles(List<String> list) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
list = prefs.getStringList("notiTitles");
return prefs.getStringList("notiTitles");
}
Future<List<String>> getMsgs(List<String> list) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
list = prefs.getStringList("notiMsgs");
return prefs.getStringList("notiMsgs");
}
}
Whats the best way to achieve this. I want to save the messages persistently and call them in another screen. Please help me.

The code on saving the List on shared_preferences seems to be ok. The issue might be on how the data is fetched. If you're storing critical data, I suggest to better use something like provider instead. The shared_preferences plugin is unable to guarantee that writes will be persisted to disk after returning as mentioned in its docs.

Related

Can't Read Data of Notification Message - Flutter

I used postman for Creating a Notification.Also I used Firebase Cloud Messaging as backend.
All works, even Notification pops in the android. But I can't read the data in my debug console ,
the Following errors are shown in console:
D/FLTFireMsgReceiver(23051): broadcast received for message
W/FLTFireMsgService(23051): A background message could not be handled in Dart as no onBackgroundMessage handler has been registered.
W/FirebaseMessaging(23051): Missing Default Notification Channel metadata in AndroidManifest. Default value will be used.
The Codes of the Push Notification class:
import 'dart:io';
import 'package:cholachol_drive/globalvariables.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
class PushNotificationService {
// final FirebaseMessaging fcm = FirebaseMessaging.instance;
Future initialize(context) async {
FirebaseMessaging.onMessage.listen((event) {
(Map<String, dynamic> message) async {
// retrieveRideRequestInfo(getRideRequestId(message), context);
print("onMessage: $message");
if (Platform.isAndroid) {
String rideID = message["data"]['ride_id'];
if (rideID != null) {
print("Fucked");
} else {
print('ride_id: $rideID');
}
}
};
});
FirebaseMessaging.onMessageOpenedApp.listen((event) {
(Map<String, dynamic> message) async {
// retrieveRideRequestInfo(getRideRequestId(message), context);
print("onLaunch: $message");
if (Platform.isAndroid) {
String rideID = message["data"]['ride_id'];
if (rideID != null) {
print("Fucked");
} else {
print('ride_id: $rideID');
}
}
};
});
}
Future<String> getToken() async {
String token = await FirebaseMessaging.instance.getToken();
print("token: $token");
DatabaseReference tokerRef = FirebaseDatabase.instance
.ref()
.child("drivers/${currentFirebaseUser.uid}/token");
FirebaseMessaging.instance.subscribeToTopic('alldrivers');
FirebaseMessaging.instance.subscribeToTopic('allusers');
}
}
It seems you don't have onBackgroundMessage implemented in your app. You need to use onBackgroundMessage in order to handle background messages. onMessage will only handle foreground messages.

how to retrieve a value from shared preferences instantly? - FLUTTER

I'm trying to show a page as an initial login, this is only displayed when my switch value is set to true.
The switch value is stored with shared preferences but when I open the application it is not recovered, only after an application update is it actually recovered. how can i get it to be recovered instantly when i open my application?
below the code:
Future<bool> saveSwitchState(bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("switched", value);
print('Switch Value saved $value');
return prefs.setBool("switched", value);
}
Future<bool> getSwitchState() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
SettingsPage.switched = prefs.getBool("switched")!;
print(SettingsPage.switched);
return SettingsPage.switched;
}
on another page then the value that is actually recovered:
if(AuthPage.authenticated == false && SettingsPage.switched == true ) {
yield ProfileNoAuth();
return; }
you can use dependency injection follow these steps :
get it package
create a Separate dart containing the following code file like this:
GetIt locator = GetIt.instance;
Future<void> setupLocator() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
locator.registerLazySingleton<SharedPreferences>(() => sharedPreferences);
}
call the setupLocator() method and wait for it in your main function
void main() async {
await setupLocator();
runApp(App());
}
access SharedPreferences Instance from anywhere like this:
locator();
now the SharedPreferences Instance if available anywhere in your project
please note that you dont have to wait for getting the Instance anymore, because you have only one Instance sharable across the application
bool getSwitchState() {
final prefs = locator<SharedPreferences>();
SettingsPage.switched = prefs.getBool("switched")!;
print(SettingsPage.switched);
return SettingsPage.switched;
}

AlarmManager not starting when app is removed from the background

I am trying to get the location data on some particular time. On every time we want to fetch the location data, we are sending a silent notification to our app. When app sees a silent notification It tries to get the data and upload back to the server. Every thing is working fine when app is running in foreground, but when i close the app and clear from the background, alarm manager is not getting fired to fetch and save the location.
_firebaseMessaging.configure(
onMessage: (
Map<String, dynamic> message,
) async {
final Map data =
message.containsKey('data') ? message['data'] as Map : null;
if (data?.isEmpty ?? false) {
_handleNotification(message);
} else {
_handleSilentEvent(message); // This method will be called when server will make call to fetch location data
}
},
onResume: (Map<String, dynamic> message) async {},
onLaunch: (Map<String, dynamic> message) async {},
onBackgroundMessage: _handleSilentEvent,
);
Future<dynamic> _handleSilentEvent(
final Map<String, dynamic> message,
) async {
final Map data = message.containsKey('data') ? message['data'] as Map : null;
if (data?.isNotEmpty ?? false) {
if (data.containsKey('getLocation')) {
await LocationService.triggerServiceToGetAndSaveLocation();
} else {
_handleWebEngage(data);
}
}
}
abstract class LocationService {
static const int _alarmManagerId = 1001;
static final ILocationFacade _locationFacade = getIt<ILocationFacade>();
LocationService._();
static Future<void> triggerServiceToGetAndSaveLocation() async {
AndroidAlarmManager.oneShotAt(
DateTime.now(),
_alarmManagerId,
LocationService._fetchAndSaveLocation,
wakeup: true,
exact: true,
);
}
static Future<void> _fetchAndSaveLocation() async {
final position = await _getCurrentLocation();
final capturedAt = DateTime.now().millisecondsSinceEpoch.toString();
final gpsEnabled = await Geolocator.isLocationServiceEnabled();
final LocationInfo locationInfo = LocationInfo(
lat: position.latitude,
lng: position.longitude,
capturedAt: capturedAt,
gpsEnabled: gpsEnabled,
);
print(
'onMessage:: Lat: ${position.latitude} Long: ${position.longitude} capturedAt: $capturedAt gpsEnabled: $gpsEnabled'); // This print is getting called when app is in foreground, when i kill the app this print is not event getting called.
// await _locationFacade.saveLocationInfo(locationInfo);
}
static Future<Position> _getCurrentLocation() async {
final _gpsServiceEnabled = await Geolocator.isLocationServiceEnabled();
if (_gpsServiceEnabled) {
return Geolocator.getCurrentPosition();
}
return Geolocator.getLastKnownPosition();
}
}
Can someone point me out where i am making the mistake?

Flutter : How to use SharedPreference to get List<String>?

I've create an initState in my page and call callData to get favId (type : List) every I open this page. But, when the application start, my compiler show this error message :
_TypeError (type 'List<String>' is not a subtype of type 'String')
and this is my getData's function :
getData(favId) async {
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.getStringList(favId);
}
also this is my saveData's function :
void saveData() async {
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setStringList("id", favId);
}
How to fix this problem and I can call getData every I open this page in my application?
Thank you :)
if you want to save and retrieve List to and from SharedPreferences, you to use same key to save and retrieve the value.
here is a simple example,
const favKey = 'favoriteKey';
To save data,
void saveData(String favKey, List<String> favorites) async {
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setStringList(favKey,favorites);
}
To retrive data,
getData(String favKey) async {
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.getStringList(favKey);
}
Note: You need to use same key to set and get data using SharedPreference.
"id" is a String, you need to store a List<String> into setStringList
There are the steps if you want to add an item to the list:
List<String> ids = await getData(favId);
ids.add("id");
saveData(ids, favId);
then change the saveData() to
void saveData(ids, favId) async {
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setStringList(ids, favId);
}
getData()
List<String> getData(favId) async {
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.getStringList(favId);
}

Flutter how to access provider.of(context) in FCM backgroundHandler static method?

I have successfully setup background notifications and tested it using postman and all is good.
Now I need to access Provider.of(context) in my backgroundHandler which must be a static method where there is no context.
All I need to do is to perform an action according to the data in the background notification.
Here is my code for initializing FCM (I do it in Splash screen)
Future<void> initFcm() async {
_firebaseMessaging.configure(
onBackgroundMessage: myBackgroundMessageHandler,
onMessage: (msg) async {
print('this is ONMESSAGE $msg');
},
onLaunch: (msg) async {
print('ON LAUNCH');
},
onResume: (msg) async {
print('ON RESUME');
},
);
// For testing purposes print the Firebase Messaging token
deviceToken = await _firebaseMessaging.getToken();
print("FirebaseMessaging token: $deviceToken");
}
static Future<dynamic> myBackgroundMessageHandler(
Map<String, dynamic> message) async {
print(message);
if (message.containsKey('data')) {
// Handle data message
final dynamic data = message['data'];
final orderId = data['order_id'];
//THE PROBLEM IS THAT HERE I DON'T HAVE CONTEXT (coz static method)
Provider.of<Orders>(context, listen: false).setBackgroundStatus(orderId);
}
if (message.containsKey('notification')) {
// Handle notification message
final dynamic notification = message['notification'];
}
// Or do other work.
}
My question is how can I handle tasks in provider in my backgroundHandler which is a static method that doesn't have context?