how to activate GPS after get user location permission once in flutter - asynchronous

i want to enable GPS location automatically when user open application, user location permission granted when user install app. how i can activate location automatically in flutter?
Geolocator geolocator = Geolocator()..forceAndroidLocationManager;
Future<Position> getCurrentLocation() async {
Position position = await geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
return position;
}

Using location lib from pub.dev you can find the desired solution. After taking Location Permission from user by using your code just add 2 lines. Here is also a sample code.
import 'package:location/location.dart' as loc;
Future<Position> getCurrentLocation() async {
loc.Location locationR = loc.Location();
if (!await locationR.serviceEnabled()) {
locationR.requestService();
}
Position position = await geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
return position;
}
This 2 lines code check your GPS is turned ON/OFF. If OFF then it gives a prompt dialog to turn on GPS.

Related

Flutter firebase dynamic link not listening

I am trying to implement Firebase Dynamic links in a flutter app. When I click on the link it opens the app but doesn't call the listen functions.
I reconfigured step by step according to FlutterFire, so I don't think the issue is in configuration, but maybe in the way I'm using the plugin as there is no documentation on the last version of the plugin.
Firebase is correctly initialised in my app as I'm using other services.
I'm doing tests on android simulator
I'm trying to listen the dynamic link from a stateful widget with the following code
I'm first navigating to the page containing this widget, then I background the app, I click on the link, the app opens at the same place and nothing happens.
#override
void initState() {
super.initState();
initLink();
}
void initLink() {
FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) {
print('dynamic link');
print(dynamicLinkData.toString());
// Navigator.pushNamed(context, dynamicLinkData.link.path);
}).onError((error) {
// Handle errors
});
}
There is an open issue here https://github.com/FirebaseExtended/flutterfire/issues/8261 where a few others are having the same problem including myself.
It seems for now the temporary solution to at least getting things working again is posted by odlund. If you make these changes the listener should work again until we have more of an official fix:
https://github.com/FirebaseExtended/flutterfire/commit/8bb4bee7e678241e75ab37a2bcfa0831426b91fa
Please update firebase_dynamic_links to 4.1.1. Seems to be an issue with the version 4.1.0 or earlier where FirebaseDynamicLinks.instance.onLink.listen doesn't work
You don't need to check if the app is in the background or resumed for this to work.
This Works Perfectly!
class _MainAppState extends State<MainApp> {
Future<void> initDynamicLinks() async {
print("Initial DynamicLinks");
FirebaseDynamicLinks dynamicLinks = FirebaseDynamicLinks.instance;
// Incoming Links Listener
dynamicLinks.onLink.listen((dynamicLinkData) {
final Uri uri = dynamicLinkData.link;
final queryParams = uri.queryParameters;
if (queryParams.isNotEmpty) {
print("Incoming Link :" + uri.toString());
// your code here
} else {
print("No Current Links");
// your code here
}
});
// Search for Firebase Dynamic Links
PendingDynamicLinkData? data = await dynamicLinks
.getDynamicLink(Uri.parse("https://yousite.page.link/refcode"));
final Uri uri = data!.link;
if (uri != null) {
print("Found The Searched Link: " + uri.toString());
// your code here
} else {
print("Search Link Not Found");
// your code here
}
}
Future<void> initFirebase() async {
print("Initial Firebase");
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// await Future.delayed(Duration(seconds: 3));
initDynamicLinks();
}
#override
initState() {
print("INITSTATE to INITIALIZE FIREBASE");
super.initState();
initFirebase();
}

Location Tracking in every 1 minute

I am creating a xamarin form app which require user location (user's longitude and latitude) after every 1 minute whether app is running in foreground or background.
I am able to get user location after every 1 minute if user stays at one position or moving slowly.
But Facing issue in getting location when user is in situation like riding bike or moving in speed,
I am not able to get user's location (user longitude and latitude) in such situatiion.
try
{
if (CrossGeolocator.Current.IsGeolocationAvailable)
{
if (CrossGeolocator.Current.IsGeolocationEnabled)
{
count += 1;
// var location = await GetLocationFromPhone().ConfigureAwait(false);
var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10)));
if (location != null)
{
var model = new lat_lon
{
lat = location.Latitude,
lon = location.Longitude,
dist = count
};
MessagingCenter.Send<lat_lon>(model, "LocationLngLet");
}
}
}
}
catch (TargetInvocationException srtiex)
{
}
catch (IllegalStateException ilsex)
{
}
catch (FeatureNotEnabledException fneex)
{
}
catch (NullReferenceException nrex)
{
}
catch (FeatureNotSupportedException fnsEx)
{
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (System.Exception ex)
{
// Unable to get location
}
Suggest any solution for this issue!!
This should run in a service (https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/services/ , https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/backgrounding/ios-backgrounding-walkthroughs/location-walkthrough), because you need it to work no matter the phone's/app's state. Consider using LocationManagers for each project and set the properties you need for locationChanged.
Are you using GeolocatorPlugin, right?
And from the Geolocator Plugin documentation, especially Listing For Location Changes and Background Updates, we see:
Before subscribing to events you must start listening, which will start the managers to query for location changes.
To check to see if you are listning there is a nifty IsListening property on the CrossGeolocator.Current that you can use.
bool IsListening { get; }
Once you are ready to start listening for changes you can call the StartListeningAsync. After this, you can add event handlers to get the changes.
Task<bool> StartListeningAsync(TimeSpan minimumTime, double minimumDistance, bool includeHeading = false, ListenerSettings listenerSettings = null);
Note:
ListenerSettings are details more in the Background Updates documentation.
And background updates are handled a bit different on each platform. The Driving application is a great sample showing how to handle this on all mobile platforms.
For more details, you can check:
https://jamesmontemagno.github.io/GeolocatorPlugin/BackgroundUpdates.html

How can I listen assigned location permisson for the HMS Core?

I try to migrate and GMS app to HMS app included maps and location service,But as I understand to get user location via Huawei Location kit, User need to assign location permission to HMS Core app but I can not follow this permission is assigned or not on my app , When the maps ready I check the locations but prompt and an allert about assign the location permission to HMS Core and I can not listen in this permission assigned or not and it is crash so I want to ask how can I listen User assign the location permission to HMS Core app ? or can i solve this issue with onether way ? can i get the user GPS location without location permission for HMS Core app ? or there is any callback about listen user assign the location permission for the HMS core app
Permission request and management is exactly the same as a GMS app, as this is handled by the Android OS. If your original GMS app had the code to check the location permission, it should be fine. Here are two examples of how to setup GMS and HMS location permission checks. You can see that they are quite similar to each other.
Stack Overflow - GMS Location permission example https://stackoverflow.com/a/33070595/14880637
Huawei Developer - HMS Location Kit setup guide https://developer.huawei.com/
checkLocationSettings method may help you.
Call the getSettingsClient() method to obtain a SettingsClient instance.
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
Call checkLocationSettings() to check the device location settings.
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
mLocationRequest = new LocationRequest();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Check the device location settings.
settingsClient.checkLocationSettings(locationSettingsRequest)
// Define the listener for success in calling the API for checking device location settings.
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
LocationSettingsStates locationSettingsStates =
locationSettingsResponse.getLocationSettingsStates();
StringBuilder stringBuilder = new StringBuilder();
// Checks whether the location function is enabled.
stringBuilder.append(",\nisLocationUsable=")
.append(locationSettingsStates.isLocationUsable());
// Checks whether HMS Core (APK) is available.
stringBuilder.append(",\nisHMSLocationUsable=")
.append(locationSettingsStates.isHMSLocationUsable());
Log.i(TAG, "checkLocationSetting onComplete:" + stringBuilder.toString());
}
})
// Define callback for failure in checking the device location settings.
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception e) {
// Processing when the device is a Huawei device and has HMS Core (APK) installed, but its settings do not meet the location requirements.
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException rae = (ResolvableApiException) e;
// Call startResolutionForResult to display a popup asking the user to enable related permission.
rae.startResolutionForResult(MainActivity.this, 0);
} catch (IntentSender.SendIntentException sie) {
// TODO
}
break;
}
}
});
Could check this Docs for more info.

Limiting Login attempt in Flutter?

I was wondering to find a way to limit login attempt in flutter/firebase. I want the user to be able attempt login post 5 minutes of waiting. I had searched through the internet and could not find any resources to help me out. Do you have any sample code for my references ?
You can stored the time in local storage and when user login again match the stored time with current time if it's less then current time then show error.
You can use SharedPreferences to store the last attempt of the user.
Before the user can login you have to check if got a login restriction and have to pass 5 minutes.
In checkLogin you check if the user has a restriction, in this case if a login attempt time was stored. If not then he has no restriction and can login as usual. Else you check if 5 minutes have passed.
static const int fiveMinutes = 5 * 60 * 1000;
static const String lastAttemptKey = 'lastAttempt';
Future<void> checkLogin() async {
// Initialize SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
// Get last login attempt
final int lastAttempt = prefs.getInt(lastAttemptKey);
// Check if is not null
if (lastAttempt != null) {
// Get time now
final int now = DateTime.now().millisecondsSinceEpoch;
// Get the difference from last login attempt
final int difference = now - lastAttempt;
// Check if 5 minutes passed since last login attempt
if (difference >= fiveMinutes) {
// User can try to login again
prefs.remove(lastAttemptKey);
await login();
} else {
// Still in limit, show error
print('You have to wait 5 minutes');
}
} else {
// First try of user login
await login();
}
}
Here the user can try to login. If it is succesfull navigate to the HomePage. Else you set the time of the login attempt to the local storage.
Future<void> login() async {
if (login.success) {
// Navigate to HomePage
} else {
// Initialize SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
// Store attempt time
prefs.setInt(lastAttemptKey, DateTime.now().millisecondsSinceEpoch);
}
}

Flutter Firestore take long retrieving data while offline

I am using Firestore in flutter application. Each time user launch the application it retrieves some data from Firestore Cloud.
QuerySnapshot dataSnapshot = await Firestore.instance
.collection('/data')
.getDocuments();
When user opens the application on first time, it required from him to connect online, to get the data, and as Firebase documents say
For Android and iOS, offline persistence is enabled by default. To disable persistence, set the PersistenceEnabled option to false.
So, it should save the data that application have been read before to retrieve it while the device is offline; so user can access application at anytime with the same data that have been read.
The problem is: it takes too long time to retrieve the data while the device is offline, with the same codes and nothing changed!.
I tried to configure how much time it takes? On offline, it takes about 8 minutes and 40 seconds. But while on online, it takes just 10 seconds, maybe less.
So how can I solve this problem?
============
UPDATE
I manged to get more logs about this problem, which after take a lot of time, and will start application with the offline saved data, it prints this log
This typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.
And then take 3 second for example (not much time) and continue with the next works.
I did open a new issue in GitHub too.
Is there a way to limit the time it takes?
And finally, with the help of diegoveloper comment in GitHub issue, I have reached the solution.
This comment
await Firestore.instance
.collection("Collection")
.getDocuments(source: source)
was a good solution if I decided to check source each time and then use it or I can use it in starting of a new Flutter project, but now I already have a lot of codes that need a better solution. So I decided to fork the cloud_firestore package and edit it.
You can find it here: https://github.com/ShadyBoshra2012/flutterfire/tree/master/packages/cloud_firestore
What I have edited:
firestore.dart
// The source of which the data will come from.
static Source _source = Source.serverAndCache;
static Source get source => _source;
Future<void> settings(
{bool persistenceEnabled,
String host,
bool sslEnabled,
bool timestampsInSnapshotsEnabled,
int cacheSizeBytes,
Source source}) async {
await channel.invokeMethod<void>('Firestore#settings', <String, dynamic>{
'app': app.name,
'persistenceEnabled': persistenceEnabled,
'host': host,
'sslEnabled': sslEnabled,
'timestampsInSnapshotsEnabled': timestampsInSnapshotsEnabled,
'cacheSizeBytes': cacheSizeBytes,
});
if (source != null) _source = source;
}
query.dart
source = Firestore.source; Line 92
document_reference.dart
source = Firestore.source; Line 83
How you can use it?
So you can use my forked repository in this way with using connectivity package from Google : https://pub.dev/packages/connectivity .
Add my forked repository in pubspec.yaml file
cloud_firestore:
git:
url: https://github.com/ShadyBoshra2012/flutterfire.git
path: packages/cloud_firestore
Then in your first screen or main
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
await Firestore.instance.settings(source: Source.cache);
} else {
await Firestore.instance.settings(source: Source.serverAndCache);
}
and if you want to refresh the source when change the connection state:
StreamSubscription subscription;
void initState() {
super.initState();
// Check the internet connection after each change
// of the connection.
subscription = Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult result) async {
// Check the internet connection and then choose the appropriate
// source for it.
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
await Firestore.instance.settings(source: Source.cache);
} else {
await Firestore.instance.settings(source: Source.serverAndCache);
}
});
}
#override
void dispose() {
super.dispose();
subscription.cancel();
}
So I hope it works with everyone see it, and waiting for Flutter Team to code a better and better solution. Thanks for everyone has participated.
In addition to Shady Boshra's answer you can use FirebaseFirestore.instance.disableNetwork() functionality so your code will look like this:
StreamSubscription subscription;
void initState() {
super.initState();
// Check the internet connection after each change
// of the connection.
subscription = Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult result) async {
// Check the internet connection and then choose the appropriate
// source for it.
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
await FirebaseFirestore.instance.disableNetwork();
} else {
await FirebaseFirestore.instance.enableNetwork();
}
});
}

Resources