Is there any way to get Documents Directory synchroniously? - flutter

I need to load a small settings file before showing the first screen.
I'm curently using the PathProvider plugin, but all the functions in it are async.
Is there any way to find the application documents directory synchroniously and then use dart:io sync functions on it? Instead of showing a placeholder for infinite decimal of a second.
EDIT: considering the first 2 answers, probably my explaination was really bad. The answers suggested me to still use async code. Problem is, I need the directory before runApp(), and I dont want my void main() to be async, because this ruins any splash animation for sure.
And the PathProvider API is async, as far as I can see, only because it utilizes MethodChannel, which is async, but functions behind it in PathProvider are pretty much synchronious.
What I'm asking is - is there a way, on Android or IOS, to know ApplicationDocumentsDirectory in sync code? Maybe without using platform-specific code at all?

You can use FutureBuilder for the same purpose without having to worry about execution.
It will allow you to do your process in the background and allows you to show a splash screen UI until your specified process is complete and data is ready to use.
Note: Any plugin or code which needs access to the device's native method channel will be async by default, since access of the method channel itself is supposed to be async.

Related

Flutter: Will callback supplied to Timer get fired when application goes to background

In Flutter if I create a Timer, will the supplied callback get executed if the application is in background?
I think documentation is not clear on this or I might have missed it (please supply a link if you find it anywhere).
I just tried doing this with a timer set up to 10 seconds and it works fine.
I assume that is approach is not very reliable and other methods* should be used instead. I think if the app is paused/terminated by operating system to preserve battery or due to low memory, nothing will be executed. But for me this situation could be an ok approach.
* I know there are isolates so I guess I could spawn the timer inside one of these. Downside is that the isolate must be regular function (or static method) so no access to application data in my scenario. Then there are different scheduling packages etc but I'm trying to avoid these for now. I know about background tasks but I'm really looking for an answer on code execution using timers.

Calling top-level async function from different Isolate

Unable to call a top-level async function from another isolate, an example would be trying to access SharedPreferences/Document-path value from a different isolate since getting the instance would require 'awaiting'.
In my case, I am using flutter_downloader, downloads in another isolate, as soon as the download completes an encryption method is called which saves the result in a document path, path_provider's getApplicationDocumentsDirectory() returns a future which requires awaiting. I have made the encrypt function async and it is never getting called using both compute and Isolate.spawn so that it computes the encryption in another isolate.
The problem is probably that there are no plugins available in isolates, thus path_provider and shared_preferences don't work when called from the isolate.
If you need the getApplicationDocumentsDirectory() then you can determine that path before you start the isolate and hand it to the isolate as a message. This way you have the path available in the isolate and can save the file there. Accessing shared_prefs is not really possible, you can only do that after the isolate completes.
There are some projects like https://pub.dev/packages/flutter_isolate that try to make plugins available in isolates. You can explore those and see if it fits your needs.
Specifically for flutter_downloader there is an example in the README that shows how to communicate between the background isolate that handles the download callback and the main isolate of your app.
Basically you need to pass a message to the main isolate like PleaseGiveMeTheApplicationDocumentsDirectory and then answer the message with HereYourGoThisIsTheApplicationDocumentsDirectory.
You can use IsolateNameServer.lookupPortByName to get the SendPort of the main isolate and pass it the SendPort of the background isolate and then answer with the correct path. Once both sides know where to send messages to, you can pass whatever you want, you can also pass a message that triggers some shared_preferences usage in the main isolate.

Why it must be use the await for save/get local data in Flutter?

I want to save data to local(just a few data), and I find several package for do that (e.g shared_preferences,secure_storage,sqflite), but all of them are need to use await (Future), if I use these, I have to change my existing codes for wrap in Future, but I just feel that's very troublesome, so I am wondering why all of these are need to use await for save data? or can I use another easy way to do that?
Thanks!
To be clear: It is impossible to have a synchronous system call in flutter.
This is due to an architectural decision: Instead of having the language bridge, Flutter uses two bus (one dart, one native) sending messages to each other.
This is faster than by using a bridge but enforce asynchronous messages.
await as the name suggest wait for some event without stopping following lines of code to execute because that work will take some milliseconds to perform. So, it's a good idea to use await which needs to have async in the function.
There is other way of doing this work without using async-await.
That's then().
So, you go with this without having to add async to your function.
performWork().then((result) {}));
If you do not wish to use await you can call then() on the Future object. Refer this link for more details.
If you are working with Flutter you will definitely have to handle Future's there is no work around it.

Is there a way to call specific code right before the app is killed or moves to the background?

I want to write the user's preferences to a file before they leave the app, so I'm looking for something in Flutter like Android's onPause() or onStop() methods. Is this something so platform-specific that I'd need to write services for it and actually use Android/iOS's specific methods for these situations or is there a way to do it only using Flutter/Dart?
My understaning is that this is possible with the didChangeAppLifecycleState callback on the WidgetsBindingObserver:
https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html
Examples:
https://github.com/flutter/flutter/search?utf8=%E2%9C%93&q=didChangeAppLifecycleState
We definitely need some better docs and examples here. I've filed:
https://github.com/flutter/flutter/issues/7394
If these are not sufficient for your needs, it is also possible to listen for any events in your Objective-C or Java code and forward those along to Dart via HostMessages (documented at https://flutter.io/platform-services).
first you need to add with WidgetsBindingObserver
then dont forget to init & dispose the WidgetsBindng
then you can call it from didChangeAppLifecycleState

How to execute a function in background at specific intervals in iOS

I would like for my iOS app when it is in background mode to execute at specific intervals some functions
(What I precisely want to do is to check a URL, and indicate its (int) content as a badge.)
However, I don't know how to have the function executed in the background.
Thanks.
Read about Executing Code in the Background. There is a limited set of things you can do in the background, what you describe not among them unfortunately.
I think you have two options to solve this problem each of them has pros and cons.
First, one is background refresh check the link. Have in mind that it is different for ios 13 and above. You need to define background tasks check here. It takes me some time to understand the background tasks but it seems more logical and easy to manage if you have several tasks. Still, you don't have the full control of when this task will be executed. It depends on how much battery, network and so on your task will use every time. The system will choose what is the best time to run it.
There is one more option, to implement a silent push notification check here.
Here you can implement a good push mechanism for updates but you will depend on network and permission for notifications. Also, you will need a backend for this solution.
You need to define what works best for you.
I think the best option is to use the voip background mode. Here you can find all the required information: how to run background process on the iOS using private APIs to sync email items without jailbreaking the phone
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app
To update the content frequently when the app is in the background might be difficult, Instead, you can wake the app by pushing a silent notification from backend at regular intervals.
For more information check this article also
https://medium.com/#m.imadali10/ios-silent-push-notifications-84009d57794c