emulator always clear moor database - flutter

I am using drift as database for my flutter app.
Whenever I close the emulator tab and restart it again, then all the saved data are gone.
This is my way to open the database:
LazyDatabase connect() {
return LazyDatabase(() async {
final appDir = await getApplicationDocumentsDirectory();
final dbPath = p.join(appDir.path, 'db.sqlite');
return NativeDatabase.createInBackground(File(dbPath));
});
}
It doesn't happen on my own physical device though.
Best regards.

Related

Why device token generated in every run of the flutter application?

I'm using firebase cloud messaging to send notifications to devices. The problem is that the device token regenrated and added to firestore with different id in every run of the application. I want it to be generated juste once for the first installation of the application.
this is my code :
Future init() async {
_firebaseMessaging.getToken().then((token) {
saveTokens(token);
});
}
Future<void> saveTokens(var token) async {
try {
await _firestore.collection('deviceTokens').add({
'token': token,
});
} catch (e) {
print(e);
}
}
this is how I call it in the main():
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await _msgService.init();
// testFirestore();
FirebaseMessaging.onBackgroundMessage(_messageHandler);
this is _messageHandler function:
Future<void> _messageHandler(RemoteMessage message) async {
print(
'background message ${message.notification!.body} + ${message.notification!.title}');
}
Actually token only refresh on one of that cases:
The app deletes Instance ID
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
So you need to check in your firebase collection if your token (getted on getToken()) is saved yet before add it. If it already exists in your database, don't save it.
For example:
Future<bool> doesTokenAlreadyExist(String token) async {
final QuerySnapshot result = await Firestore.instance
.collection('deviceTokens')
.where('token', isEqualTo: token)
.limit(1)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
return documents.length == 1;
}
The registration token may change when:
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
More :
Update from Play Store - Token remains same.
When close the application and reopen it - Token remains same.
I recommend you should record that token for the user every time your app launches. Then, you don't face any problems.
(add function to init state of home page of your app)

How to grant system permissions while writing flutter integration tests?

I am writing flutter integration tests https://docs.flutter.dev/cookbook/testing/integration/introduction
I can find and tap on my widgets perfectly fine but the problem arises when I have to click the system widgets to grant permissions in order to continue and test the remaining flow.
For example:
I tap a button then have to grant location permissions. At this moment the screen as below is shown
This screen is shown by the system and I have no key or way how to tap "While using the app".
Also the system screen might change between devices like ios and android and the text might be different as well.
What is the best practice to solve this issue? I am blocked from testing the remaining screens that use the required permissions..
What I tried so far?
I tried to grant the permissions manually for Android as a start but did not work
Future<void> grantRequiredAppPermissions() async {
if (!Platform.isAndroid) {
return;
}
const appPackageName = 'my.package';
print(
'We are going to manually grant the required permissions to the android package $appPackageName');
final Map<String, String> envVars = Platform.environment;
String adbPath = join(
envVars['ANDROID_SDK_ROOT'] ?? envVars['ANDROID_HOME']!,
'platform-tools',
Platform.isWindows ? 'adb.exe' : 'adb',
);
print('Using adb at $adbPath');
final permissions = [
'android.permission.READ_EXTERNAL_STORAGE',
'android.permission.WRITE_EXTERNAL_STORAGE',
'android.permission.ACCESS_FINE_LOCATION',
'android.permission.ACCESS_COARSE_LOCATION'
];
for (final permission in permissions) {
await Process.run(
adbPath, ['shell', 'pm', 'grant', appPackageName, permission]);
}
}
I was calling that function in my app/integration_test/driver.dart
import 'dart:io';
import 'package:integration_test/integration_test_driver_extended.dart';
import 'helpers/grant_required_permissions.dart';
Future<void> main() async {
await grantRequiredAppPermissions();
await integrationDriver();
}
but did not help at all. Also it is not a proper solution because even if it was going to work, would work only for android and i test also on ios devices.
You can try out the testing framework patrol https://pub.dev/packages/patrol
See the documentation here: https://patrol.leancode.co/
It let's you interact with the native ui like this:
await $.native.grantPermissionWhenInUse();
await $.native.grantPermissionOnlyThisTime();
await $.native.denyPermission();

Flutter shared_preferences not persistent?

I have been using shared_preferences in flutter, was working fine until now. Suddenly it stopped working, both in iOS and Android. I debugged it step by step and it stores data to pref and while app is on, data still persists, but after hot restart _preferencecache always is empty. How can I solve this? (version is 0.5.12)
When user logs in I save the user_id:
final prefs = await SharedPreferences.getInstance();
final userData = json.encode(
{
'user_id': userID,
},
);
prefs.setString('userData', userData);
Later, when user restarts again:
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
// print("no user data in shared preference");
return false;
}
But the abpve function returns false, that's the issue, I checked the previous version of shared_preferences as well, but no solution.
you have do it like this
final prefs = await SharedPreferences.getInstance();
final data = prefs.getString("userData");
if(data != null){
final userData = json.dncode(userData);
}
I realized I was clearing my shared preferences some where in my app and I had forgotten about it. Please check every where in your code for sharedPreferences.clear(). You never know.
I assume that somewhere in your code, you faced this error and as a quick solution, you had added SharedPreferences.setMockInitialValues({}); in your code, which should be the reason (other than sharedPreferences.clear()).
The SharedPreferences.setMockInitialValues({}); is the thing that is preventing data to persist between sessions.
A quick getaway is to add a try-catch block to your code. Somethink like the following:
try {
prefs.getInt(YOUR_KEY_HERE);
} catch (e) {
SharedPreferences.setMockInitialValues({});
}
But this isn't a conventional fix to this problem, I recommend checking out this answer by Siddharth Agrawal.

How do you download an image from the internet onto a file in Flutter?

I'm making a Flutter project where an image is displayed in listview and the user can share, favourite or download the image. I'm stuck on the downloading part. Is it possible to save an image file onto the phone's storage for offline use?
What I want to happen is I can create and write an image file
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/$title.txt');
}
// Write an image by obtaining an image through a URL
and then be able to access it through
Image.file('$path/$title.txt')

Flutter How can I check internet connection through the whole app NOT only in one particular Class, and prompt pop-up dialog when it lost?

How can I continuously check internet connection for whole application(I mean all classes and widgets) and prompt the pop-up dialog when the connection is lost. Please provide an example if it is possible.
You need to use the Connectivity Plugin.
import 'dart:io';
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
print('connected');
}
} on SocketException catch (_) {
print('not connected');
}