Saving Cache from api response on flutter - flutter

I Would like to seek advice for a simple way to cache this response from my API on flutter. What I am intending to do is when there no internet available it will use the cache item and if there is internet available it will update the cache to the latest one.The code below is the current API call that I am using.
_getCurrentPlanDetails() async{
var url = "http://dmp-portal-fixture.herokuapp.com/getCurrentPlan";
var response = await http.get(url);
if (response.statusCode == 200){
var jsonResponse = convert.jsonDecode(response.body);
setState(() {
currentPlan = jsonResponse["data"]["CurrentPlan"];
cutOffDate = jsonResponse["data"]["CutoffDate"];
contractExpiry = jsonResponse["data"]["ContractExpiry"];
monthsRemaining =jsonResponse["data"]["MonthsRemaining"];
});
print("get Current plan");
}else{
print("error current plan");
}
}

There are multiple packages that handle this depending on the use-case of your requirements:
localstorage which is a JSON based storage.
shared_preferences for storing key-value pairs.
flutter_secure_storage for storing all your access token and security related components of the app such as all session information, user credentials etc...
SQL database there is a quite extensive tutorial on storing files in a databese in Flutter, so I suggest reading that one as well in case you need to preserve a lot of app related data in case no internet is available.

Related

For PWA, what is the easiest way to get per-device settings (as in reading a .ini file or environment variables)?

For PWA, what is the easiest way to get per-device settings (as in reading a .ini file or environment variables)?
I'm making a very simple in-company react PWA for andriod-based tablets (only). I just want to store a couple of settings (the room number where the device is being used, and a device id) and read those in upon startup.
My experience in recently in Windows, and so I'm imaging a text file that I could place on each tablet with the settings. Does that make sense for our PWA?
Or is there a better/easier way to do app settings?
Thank you.
The answer depends on how that data is initially provisioned and what kind of guarantees you need about it being "tamper-proof."
Assuming you can provision the information during the web app's initial launch, and you're fine using storage that's exposed via a browser's Developer Tools (i.e. your threat model doesn't include a motivated user using DevTools to erase/modify the data), a simple approach would be to a) use the Cache Storage API to read/write that data as JSON, using a synthetic URL as the key and b) requesting persistent storage just for an added guarantee that it won't be purged if the device ends up running low on storage.
This could look like:
// Just use any URL that doesn't exist on your server.
const SETTINGS_KEY = '/_settings';
const SETTINGS_CACHE_NAME = 'settings';
async function getSettings() {
const cache = await caches.open(SETTINGS_CACHE_NAME);
const cachedSettingsResponse = await cache.match(SETTINGS_KEY);
if (cachedSettingsResponse) {
return await cachedSettingsResponse.json();
}
// This assumes a generateInitialSettings function that does provisioning
// and returns an object that can be stringified.
const newSettings = await generateInitialSettings();
await cache.put(SETTINGS_KEY, JSON.stringify(newSettings), {
headers: {
'content-type': 'application/json',
}
});
// Optional: request persistent storage.
// This call may trigger a permissions dialog in the local browser, so it is
// a good idea to explain to the user what's being stored first.
// See https://web.dev/persistent-storage/#when-should-i-ask-for-persistent-storage
if (navigator.storage && navigator.storage.persist) {
// This returns a promise, but we don't have to delay the
// rest of the program execution by await-ing it.
navigator.storage.persist();
}
return newSettings;
}

How to retrieve multiple different files form firebase to flutter

I don't want to upload my code but I am having problems with retrieving multiple files from firebase storage. So in my app, I want to make users upload different files and while uploading it will show up in a list form.
The thing is I am able to save files into the firebase storage but I am freaking out trying to retrieve them into my application. I really hope if I get some to help me with this.
I don't exactly know what you're trying to achieve but maybe this would help.
When you upload your file to firestore storage, get a download link of that file and store it in the collection. Then you can retrieve the list of files you have uploaded.
Get the download URL of the uploaded file
UploadTask imageUploadTask = storageReference.putFile(file);
await imageUploadTask.whenComplete(() async {
mediaURL = await imageUploadTask.snapshot.ref.getDownloadURL();
print("download url = $mediaURL");
return mediaURL;
}).catchError((err){
print(err.toString());
});
Save URL to the collection
final CollectionReference _filesCollectionReference = FirebaseFirestore.instance.collection("files");
Map<String, String> file = {
"downloadURL" : url,
};
var result = await _filesCollectionReference.add(file);
Retrieve files
await _filesCollectionReference.get();

Flutter - Storing Authenticated User details

I am new to Flutter and I am writing an app which requires users to login. I already have an API that provides me with a JWT. I then store this using the secure storage library.
Once the user gets the 200 OK with the token, I want to send another request to the server to retrieve the user's details and store it in a kind of singleton class, so I can use it through out the app until he logs out. There are so many buzzwords being thrown at me right now, Providers and BLoCs.
I was wondering what is the best practice to store the current logged in user details in the app? Previously I've been aware of storing the data in a singleton class. But now I'm not sure whether I should write a singleton class or a Provider? (I'm still rusty on my knowledge about how Providers and BLoCs work).
Start Simple
A simple starting point to store the data, which i assume is the form of key/value pairs, would be using shared preferences.
What are Shared Preferences
The main use of Shared Preferences is to save user preferences, settings, maybe data (if not too large) so that next time the application is launched, these pieces of information could be retrieved and used.
How to use
Set an instance variable of Shared Preferences and store the value with a key identifier.
Any time you want to retrieve the value when the app starts, just get it using the key. See example below of setting and getting a stored username.
Future<bool> setUserName(String value) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.setString("username",value);
}
Future<String> getUserName(String value) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString("username");
}
Installation
To installed shared preferences, add this to your package's pubspec.yaml file:
dependencies:
shared_preferences: ^0.5.7+3
More information on the package page.
Solution 1
This is how my app stores data:
Create a new dart file for storing "global" variables like so, and store all the "session" data there:
class SessionData{
String encryptedUserId;
String encryptedPassword;
String encryptedToken;
int userId;
}
SessionData globalSessionData;
//Having a clear function is pretty handy
void clearSessionData(){
globalSessionData = new SessionData();
}
And if you named the file for example global.dart import it, read and write nonpermanent data to it (persist until the app is closed):
import 'global.dart' as global;
global.globalSessionData = ...;
//If you want to clear it:
global.clearSessionData();
Solution 2
If you want to persist the data even if the application closes there are two ways to do that:
Solution 2a
Use sharedPrefences to store and retrieve key-data values on the user's device:
import 'package:shared_preferences/shared_preferences.dart';
final SharedPreferences prefs = await SharedPreferences.getInstance();
//Write different types of data
await prefs.setBool("male", true);
await prefs.setDouble("key", 7.0);
await prefs.setString("username", "Mr. User");
//Retrive different types of data
prefs.getBool("male");
prefs.getDouble("key");
prefs.getString("username");
Solution 2b
Use sqflite to store advanced data structures, as it is a fully-featured database.
Flutter has a great tutorial on using SQLite with flutter. Although if you go with this type of solution you must know a little SQL.

json Fetch rerun

So i'm writting app in which i fetch data from air quality index webpage www.waqi.info and display it. So i got it working for one city but when i change city on popuplist how to recall api with different url. Tried something but it doesn't work. Now i have idea to save city in phone memory and then reruning app. Any clues how i can recall Http request for different city almost same url but how to recall http request from onchange. Im new to flutter and dart. Sorry for any stupidty
you have to use http 0.12.0+2 library to do API calls http library page
you can simply create a function which will fetch data
getData(city) async{
String url="YOUR_URL_HERE?city="+city;
var response=await http.get(url);
return response.body;
}
You can call this method from your onChanged
you can use a function to call api and pass city name as argument
like this
callApi(city) async{
String url="Url/${city}";
var response=await http.get(url);
return response.body;
}
and after getting response set data drom response to model object and then call setState()
which will reset your whole screen

Firebase: Authenticate an existing user using REST API and Firebases hidden Auth URL

For the past 3 years we have used HTML/Js only with Firebase but now we are using Unity as well.
The current Unity/Firebase only works on Android/iOS when deployed and 99% of our work is on the windows store.
I've actually got a pretty decent Unity/Firebase codebase going but it requires me to use a full App Secret.
All the other libraries expose a method to login with Email/Password but the REST API only allows the use of a token or your app secret that it then states is ill advised to put into your client; I guess the thinking is if you're using a different library that you'll have your own auth/user method which we don't...
Now, I've pulled apart the web version and got this:
https://auth.firebase.com/v2/<myfirebase>/auth/password?&email=dennis%40<mysite>&password=<mypassword>v=js-2.2.9&transport=json&suppress_status_codes=true
So there IS an endpoint that I can send stuff to and I've tested it inside unity with good results.
Obviously the URL isn't guaranteed to stay working but I'm wondering if there is any reason NOT to use this?
Also, Why not just expose this endpoint in the official REST API?
As I understand it, that URL will continue to work for your Legacy Firebase project. You will have to do the same sort of reverse engineering if you want to update to the new Firebase 3.0 API. However, if you are still using a legacy Firebase project -- I encourage you to take a look at this. It has not been updated to work with Firebase 3.0 -- so I needed to do something similar to what you did to allow login to the new API.
I was able to do this with the new API using C# as follows (where FirebaseManager is a Singleton I wrote for Global variables and functions to write and read from/to the DB :
Hashtable loginData = new Hashtable();
loginData.Add ("email", <EMAIL-GOES-HERE>);
loginData.Add ("password", <PASSWORD-GOES-HERE>);
loginData.Add ("returnSecureToken", true);
UnityHTTP.Request loginRequest = new UnityHTTP.Request ("post",
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key="
+ <YOUR-PROJECT-API-KEY-GOES-HERE>, loginData);
loginRequest.Send ((request) => {
Hashtable jsonResponse = (Hashtable)JSON.JsonDecode(request.response.Text);
if (jsonResponse == null) {
DisplayErrorMessage("Error logging in. Server returned null or malformed response");
}
FirebaseManager.Instance.idToken = (string)jsonResponse["idToken"]; // This is your auth token
FirebaseManager.Instance.uid = (string)jsonResponse["localId"]; // this is your "uid"
});
// I have a list of users in my db keyed by the "uid" -- I access them like this
UnityHTTP.Request fullnameRequest = new UnityHTTP.Request ("get",
<YOUR-DATABASE-ROOT-URL-HERE>
+ "/users/" + FirebaseManager.Instance.uid + ".json?auth=" + FirebaseManager.Instance.idToken);
fullnameRequest.Send ((request) => {
Debug.Log(request.response.Text);
Hashtable jsonResponse = (Hashtable)JSON.JsonDecode(request.response.Text);
if (jsonResponse == null) {
DisplayErrorMessage("Error getting user info. Server returned null or malformed response");
}
FirebaseManager.Instance.fullname = (string)jsonResponse["fullname"];
FirebaseManager.Instance.groupId = (string)jsonResponse["group"]; // just storing this in memory
});
So I don't think there is any harm in using the URL, just make sure you budget time for more work when things change.