Dart shared preferences not saving to disk - flutter

I've spent hours debugging this and can't find anything wrong with my code. I am on a MacOS, Big Sur, using VSCode and iOS emulator.
The shared preferences bloc returns that the storage was a success, but when I look on disk where the directory storage is, there is no file or anything there. This was just working the other day, but I did update flutter master. I downgraded to flutter beta but am having the same problem.
Does anyone see anything wrong with this or having a similar issue?
#override
Future<Either<Failure, UserEntity>> putStoredUserLoginModel() async {
final SharedPreferences sp = await SharedPreferences.getInstance();
final userMember = getUserMember();
await sp.setInt('foo', 1);
final userModel = userMember.toJson().toString();
print('PUTING: $userModel');
final bool notFailed = await sp.setString('userModel', userModel);
if (notFailed) {
return const Right(UserEmpty());
} else {
return Left(CacheFailure());
}
}

Related

ImagePicker return invalid image source

Im using ImagePicker to pick multiple image. On android just work fine. But iOS returning.
PlatformException (PlatformException(invalid_source, Invalid image source.
ImagePicker _picker = ImagePicker();
pickMultiImage() async {
Size size = MediaQuery.of(context).size;
AppLocalizations localization = AppLocalizations.of(context)!;
try {
final List<XFile>? images = await _picker.pickMultiImage();
if (images!.isNotEmpty) {
imageFileList!.addAll(images);
}
setState(() {});
} catch (e) {
showDialogOpenPermission(
context, localization, localization.gallery, size);
}
}
update : Checking on iOS real device just works fine. Long ago, I think just works fine on emulator :(.
** I'm prefer to test my apps by via emulator. So, If anyone here know the solution, please tell me ;)

Flutter - Firebase Dynamic Link not Working while app is in kill mode

I have integrated Firebase Dynamic link in my Flutter application to open and navigate application users to specific screen in app.
For that first of all I have added below plugin in pubspec.yaml file:
firebase_dynamic_links: ^5.0.5
Then, I have created a separate class to handle related stuffs as below:
class DynamicLinkService {
late BuildContext context;
FirebaseDynamicLinks dynamicLinks = FirebaseDynamicLinks.instance;
Future<void> initDynamicLinks(BuildContext context) async {
this.context = context;
dynamicLinks.onLink.listen((dynamicLinkData) {
var dynamicLink=dynamicLinkData.link.toString();
if (dynamicLink.isNotEmpty &&
dynamicLink.startsWith(ApiConstants.baseUrl) &&
dynamicLink.contains("?")) {
//Getting data here and navigating...
...
...
...
}
}).onError((error) {
print("This is error >>> "+error.message);
});
}
}
Now, I am initialising Deep-link as below in my home_screen:
final DynamicLinkService _dynamicLinkService = DynamicLinkService();
and then calling below method in initState()
#override
void initState() {
SchedulerBinding.instance.addPostFrameCallback((_) async {
await _dynamicLinkService.initDynamicLinks(context);
});
}
This is working like a charm! when my application is in recent mode or in background mode.
But the issue is when the application is closed/Killed, clicking on dynamic link just open the app but could not navigate.
What might be the issue? Thanks in advance.
Let me answer my own question, It might be useful for someone!
So, In above code I forgot to add code to handle dynamic link while the app is in closed/kill mode.
We need to add this code separately:
//this is when the app is in closed/kill mode
final PendingDynamicLinkData? initialLink = await FirebaseDynamicLinks.instance.getInitialLink();
if (initialLink != null) {
handleDynamicLink(initialLink);
}
So, final code looks like as below:
//this is when the app is in closed/kill mode
final PendingDynamicLinkData? initialLink = await FirebaseDynamicLinks.instance.getInitialLink();
if (initialLink != null) {
handleDynamicLink(initialLink);
}
//this is when the app is in recent/background mode
dynamicLinks.onLink.listen((dynamicLinkData) {
handleDynamicLink(dynamicLinkData);
}).onError((error) {
print("This is error >>> "+error.message);
});
Its working like a charm now! That's All.

PlatformException (PlatformException(channel-error, Unable to establish connection on channel., null, null)) while mocking method that use firestore

I'm currently having an issue when I try to do unit test on a method that use Firestore.
This is the method that I want to mock
Future<MediasState> loadMedias(AbstractEvent event) async {
late AbstractBlocState streamState;
try {
DataHelper _dataHelperMediasEvent = DataHelperFactory.instance
.createInstanceFromAnotherDataHelperAndEntityInstance(
_dataHelperEvents, event, 'medias');
List<AbstractMedia> medias =
(await _dataHelperMediasEvent.getAll()).cast<AbstractMedia>();
for (AbstractMedia media in medias) {
media.user = await (_dataHelperUsers.getEntity(media.user.get()));
}
medias = sortEntitiesByCreatedDateDesc(medias) as List<AbstractMedia>;
streamState = MediasShowed(medias);
} catch (error) {
streamState = MediasShowedError();
} finally {
return streamState as MediasState;
}
}
And this the test function that I wrote
test('Test load medias', () async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
AbstractEvent event =
EntityFactory.createInstance('Event') as AbstractEvent;
AbstractMedia media1 =
EntityFactory.createInstance('Media') as AbstractMedia;
AbstractMedia media2 =
EntityFactory.createInstance('Media') as AbstractMedia;
AbstractMedia media3 =
EntityFactory.createInstance('Media') as AbstractMedia;
List<AbstractMedia> listOfMedias = <AbstractMedia>[];
listOfMedias.add(media1);
listOfMedias.add(media2);
listOfMedias.add(media3);
when(mockMediasEvent.loadMedias(event))
.thenAnswer((_) async => MediasShowed(listOfMedias));
blocMedias.add(LoadMediaOfOneEvent(event));
await expectLater(blocMedias.state, isA<MediasShowedError>());
});
Unfortunately I got this error when I run this test : "PlatformException(channel-error, Unable to establish connection on channel., null, null)
package:firebase_core_platform_interface/src/pigeon/messages.pigeon.dart 199:7 FirebaseCoreHostApi.initializeCore"
The DataHelperFactory create an instance of DataHelper which need an firestore instance.
class DataHelper {
DataHelper.initialize(String collectionPath) {
this.setCollection(collectionPath);
}
late String collectionPath;
late String className;
late CollectionReference<Map<String, dynamic>> collection;
final FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
I already tried to upgrade my firebase dependencies but the problem is still there. I also tried on Windows and Mac device and on a friend device and I was able to reproduce the issue.
Any idea of how to fix my test will be welcome.
Thanks.
The documentation for flutter firebase testing states that mock firebase libraries need to be used. They are much easier to work with.

How to get App last Update time in flutter?

I want to get last app updates time in flutter, I tried but I can't get that time.
Hei,
I don't know if there is a package which manages this but I think you can manage it with some combinations. Add shared_preferences and package_info_plus as dependencies into your pubspec.yaml file as usual.
Then in a uppest stateful widget in your widget tree, define a function as below (runApp -> MyApp -> HomePage(stateful) on Homepage for example):
//import on top
import 'package:shared_preferences/shared_preferences.dart';
import 'package:package_info_plus/package_info_plus.dart';
// .........
void checkUpdateTime() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
SharedPreferences prefs = await SharedPreferences.getInstance();
var previousVersion = prefs.getString("version");
var previousTime = prefs.getString("latestTimeUpdated");
String currentVersion = packageInfo.version + "+" + packageInfo.buildNumber;
String now = DateTime.now().toUtc().toString();
// First launch after app downloaded
if(previousVersion == null && previousTime == null){
await prefs.setString("latestTimeUpdated", now);
await prefs.setString("version", currentVersion);
}
// There is previous version instance saved before so check if its the same with the current version
if (previousVersion != null) {
// check saved version and current version is different
if (previousVersion != currentVersion) {
// Update time
await prefs.setString("latestTimeUpdated", now);
await prefs.setString("version", currentVersion);
}
// Do nothing if saved version and current version is the same
}
}
Do not forget to call the function on initState:
#override
void initState() {
checkUpdateTime();
super.initState();
}
Basically;
This will cross-check your app's current version and last saved version. If these are not same, it will update the latestTimeUpdated. Then in your app anywhere you want:
SharedPreferences prefs = await SharedPreferences.getInstance();
String updateTimeUTCString = prefs.getString("latestTimeUpdated");
Format this updateTimeUTCString as you wish and use it.
I hope this becomes useful for you.

Autofill login credentials in flutter inappWebview

I am using flutter_inappwebview plugin for developing an android browser. Now I need to save and autofill login credentials for different websites like facebook, twitter etc.
I come to know about securely storing login data using flutter_secure_storage plugin but I don't have any knowledge about how to implement this.
I want this feature exactly as it has in Google Chrome. Please help if you can...
Thanks in advance!
flutter_secure_login currently does not support Flutter platform web.
Since this is the case I would recommend using shared_preferences found here
Its very similar to secure storage and can be utilized in a very similar way
in the following code i am using it to store my user data
// write to shared preferences
final prefs = await SharedPreferences.getInstance();
if (!_context.isLoggedIn) {
if (prefs.containsKey('userData')) prefs.remove('userData');
return;
}
final userData = Map<String, String>();
userData['refreshToken'] = _refreshToken;
userData['tenantId'] = _tenantId;
userData['userId'] = _userId;
await prefs.setString('userData', json.encode(userData));
That can then be accessed to refresh tokens.
Future init() async {
final prefs = await SharedPreferences.getInstance();
final prefData = prefs.getString('userData');
if (prefData == null) return;
final Map<String, Object> userData = json.decode(prefData);
_authWriter.write({
'refreshToken': userData['refreshToken'],
'userId': userData['userId'],
'tenantId': userData['tenantId']
});
await refreshAccessToken();
}