Can't get user location after permission granted - flutter

I tried get user location when button clicked using flutter location package
Code
FloatingActionButton(
onPressed: () async {
await location
.hasPermission()
.then((PermissionStatus status) async {
if (_permissionGranted == PermissionStatus.denied) {
await location.requestPermission().then(
(PermissionStatus requestStatus) async {
print("PERMISSION TAKEN");
await location
.getLocation()
.then((LocationData userLocation) {
print("LOCATION TAKEN 1");
print(userLocation);
});
},
);
} else {
await location
.getLocation()
.then((LocationData userLocation) {
print("LOCATION TAKEN 2");
print(userLocation);
});
}
});
},
child: Icon(Icons.place, color: Colors.white),
backgroundColor: Colors.green,
),
When user clicked to button requested permission to location and in my code after permission granted work this part of my code
print("PERMISSION TAKEN");
But then not work this part of code
await location
.getLocation()
.then((LocationData userLocation) {
print("LOCATION TAKEN 1");
print(userLocation);
});

you can also get the location by following:---------
pubspec.yaml file under dependencies:----
dependencies:
location: ^3.0.0
Android, add this permission in AndroidManifest.xml :
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
iOS, you have to add this permission in Info.plist :
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
Warning: there is a currently a bug in iOS simulator in which you have to manually select a Location several in order for the Simulator to actually send data. Please keep that in mind when testing in iOS simulator.
main.dart
import 'package:flutter/material.dart';
import 'package:location/location.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter GPS',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: GetLocationPage(),
);
}
}
class GetLocationPage extends StatefulWidget {
#override
_GetLocationPageState createState() => _GetLocationPageState();
}
class _GetLocationPageState extends State<GetLocationPage> {
LocationData _currentLocation;
Location _locationService = new Location();
#override
void initState() {
// TODO: implement initState
super.initState();
_getLocation().then((value) {
setState(() {
_currentLocation = value;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_currentLocation == null
? CircularProgressIndicator()
: Text("Location:" +
_currentLocation.latitude.toString() +
" " +
_currentLocation.longitude.toString()),
],
),
),
);
}
Future<LocationData> _getLocation() async {
LocationData currentLocation;
try {
currentLocation = await _locationService.getLocation();
} catch (e) {
currentLocation = null;
}
return currentLocation;
}
}
ss:---
In order to request location, you should always check manually Location Service status and Permission status. refer this https://pub.dev/packages/location

i get current location as below , try to use like this
Future<LatLng> getUserLocation() async {
LocationData currentLocation;
var location = new Location();
bool _serviceEnabled;
PermissionStatus _permissionGranted;
LocationData _locationData;
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.DENIED) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.GRANTED) {
}
}
// Platform messages may fail, so we use a try/catch PlatformException.
try {
currentLocation = await location.getLocation();
final lat = currentLocation.latitude;
final lng = currentLocation.longitude;
final coordinates = new Coordinates(lat, lng);
var addresses =
await Geocoder.local.findAddressesFromCoordinates(coordinates);
var first = addresses.first;
updateLocation(lat, lng, first.postalCode, first.locality,
first.countryName, first.adminArea, first.addressLine);
final center = LatLng(lat, lng);
return center;
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_DENIED') {
showToast("LOCATION PERMISSION DENIED",
gravity: Toast.TOP, duration: Toast.LENGTH_LONG);
}
currentLocation = null;
}
}
And don't forget to add this permission in Info.plist
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription

Related

my flutter app is not taking location in real device at first time but work properly in emulator?

This code is working fine in emulator but it doesn't work properly in real device . This code for taking user location but when i open 1st time app it only ask permission for location and doesn't getlocation if restart my application then it take location.
#override
void initState() {
// TODO: implement initState
super.initState();
showAddress(context);
didChangeDependencies();
}
Future showAddress(BuildContext context) async {
await locationService();
}
void getYourAddress() {
homeServices.addAddress(
context: context,
address: address,
latitude: lat!,
logitude: long!,
locality: locality,
);
}
double? lat;
double? long;
String address = '';
String locality = '';
//For convert lat long to address
getAddress(lat, long) async {
List<geocoding.Placemark> placemarks =
await geocoding.placemarkFromCoordinates(lat, long);
if (mounted) {
setState(() {
address =
"${placemarks[0].street!} ${placemarks[0].subLocality!} ${placemarks[0].locality!} ${placemarks[0].postalCode!} ${placemarks[0].country!} ";
if (placemarks[0].locality == '') {
locality = placemarks[0].street!;
} else {
locality = placemarks[0].locality!;
}
});
}
for (int i = 0; i < placemarks.length; i++) {
print("INDEX $i ${placemarks[i]}");
}
getYourAddress();
}
Future locationService() async {
Location location = Location();
bool serviceEnabled;
PermissionStatus permissionLocation;
LocationData locData;
serviceEnabled = await location.serviceEnabled();
if (serviceEnabled == false) {
serviceEnabled = await location.requestService();
if (serviceEnabled == true) {
permissionLocation = await location.hasPermission();
if (permissionLocation == PermissionStatus.denied) {
permissionLocation = await location.requestPermission();
if (permissionLocation != PermissionStatus.granted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const IntroScreen(),
),
);
} else if (permissionLocation == PermissionStatus.granted) {
await getLocation();
}
} else if (permissionLocation == PermissionStatus.granted) {
await getLocation();
}
}
} else if (serviceEnabled == true) {
permissionLocation = await location.hasPermission();
if (permissionLocation == PermissionStatus.denied) {
permissionLocation = await location.requestPermission();
if (permissionLocation != PermissionStatus.granted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const IntroScreen(),
),
);
} else if (permissionLocation == PermissionStatus.granted) {
await getLocation();
}
} else if (permissionLocation == PermissionStatus.granted) {
await getLocation();
}
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const IntroScreen(),
),
);
}
}
// Problem occuring at this point in emulator it work fine but not work in real device.
getLocation() async {
try {
LocationData locData;
Location location = Location();
locData = await location.getLocation();
if (mounted) {
setState(() {
lat = locData.latitude!;
long = locData.longitude!;
});
await getAddress(lat, long);
}
} catch (e) {
getLocation();
}
}
This code is working fine in emulator but it doesn't work properly in real device . This code for taking user location but when i open 1st time app it only ask permission for location and doesn't getlocation if restart my application then it take location.
I am expecting this app to ask user for location permission and store data imidiately to database. But it doesn't doing it on first time after i restart app then it take location . Please help me to solve this problem.
I am use Using Location and Gecoding widget of flutter. when i try ti= check logs of my app in real device it show that asynchronous suspension.

Flutter download a file from url automatically to downloads directory

Is there a way or a package in Flutter that downloads a file directly to downloads folder for Android and iOS from a direct URL for example: https://******/image.jpg, without any user overhead just a click and download..
Yes use following packages to completely achieve it :
dio: ^4.0.0
path_provider: ^2.0.2
permission_handler: ^8.0.0+2
then use following code :
define variables:
late String _localPath;
late bool _permissionReady;
late TargetPlatform? platform;
get device platform in initState()
#override
void initState() {
super.initState();
if (Platform.isAndroid) {
platform = TargetPlatform.android;
} else {
platform = TargetPlatform.iOS;
}
}
for check and requesting device's permissions :
Future<bool> _checkPermission() async {
if (platform == TargetPlatform.android) {
final status = await Permission.storage.status;
if (status != PermissionStatus.granted) {
final result = await Permission.storage.request();
if (result == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
} else {
return true;
}
return false;
}
prepare for finding localpath :
Future<void> _prepareSaveDir() async {
_localPath = (await _findLocalPath())!;
print(_localPath);
final savedDir = Directory(_localPath);
bool hasExisted = await savedDir.exists();
if (!hasExisted) {
savedDir.create();
}
}
Future<String?> _findLocalPath() async {
if (platform == TargetPlatform.android) {
return "/sdcard/download/";
} else {
var directory = await getApplicationDocumentsDirectory();
return directory.path + Platform.pathSeparator + 'Download';
}
}
and at last for downloading file:
InkWell(
onTap: () async {
_permissionReady = await _checkPermission();
if (_permissionReady) {
await _prepareSaveDir();
print("Downloading");
try {
await Dio().download("https://******/image.jpg",
_localPath + "/" + "filename.jpg");
print("Download Completed.");
} catch (e) {
print("Download Failed.\n\n" + e.toString());
}
}
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.grey.withOpacity(0.5)),
padding: EdgeInsets.all(8),
child: Icon(Icons.download, color: Colors.black),
));
Make sure you have added required permissions in the AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
EDIT :
if your app directory is not shown in iOS files then add the below line in Info.plist
<key>UISupportsDocumentBrowser</key>
<true/>
You can use Dio package to download any file.
A powerful Http client for Dart, which supports Interceptors, Global
configuration, FormData, Request Cancellation, File downloading,
Timeout etc.
Example
import 'package:dio/dio.dart';
var dio = Dio();
response = await dio.download('https://******/image.jpg');

Flutter - Get user GPS location and use throughout screens globally

How can I get the user's GPS (current address) on launch and then use that throughout the app where needed? I'd like to be able to use both options of the coordinates and written address being output. I'd like to have it be string data instead of text widget, so that then I can use it in other widgets where appropriate. Here's what I have so far, but I can't figure out how to incorporate this into my app properly and extract and implement that data.
Oh, also how to make it update periodically for when then user changes locations?
Any ideas?
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
class FindMe extends StatefulWidget {
initState() {
FindMe();
}
#override
_FindMeState createState() => _FindMeState();
}
class _FindMeState extends State<FindMe> {
String currentAddress = '';
late Position currentposition;
Future<String> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
Fluttertoast.showToast(msg: 'Please enable Your Location Service');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
Fluttertoast.showToast(msg: 'Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
Fluttertoast.showToast(msg:'Location permissions are permanently denied, we cannot request permissions.');
}
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.bestForNavigation);
try {
List<Placemark> placemarks = await placemarkFromCoordinates(position.latitude, position.longitude);
Placemark place = placemarks[0];
setState(() {
currentposition = position;
currentAddress = "${place.locality}, ${place.postalCode}, ${place.country}";
});
} catch (e) {
print(e);
}
return currentAddress;
}
#override
Widget build(BuildContext context) {
_determinePosition();
return Text(
currentAddress,
style: const TextStyle(color: Colors.black),
);
}
}
You could use state-management solutions like blocor riverpod to do this.
With Riverpod one solution could look like this:
class LocationService {
Future<String> determinePosition(){...}
}
...
final locationServiceProvider = Provider((ref) => LocationService());
final positionProvider = FutureProvider((ref) => ref.watch(locationServiceProvider).determinePosition);
...
// in a consumer widget
build(BuildContext context, WidgetRef ref){
final position = ref.watch(positionProvider);
// do something with the position
}
You can then access the value in your position provider from different parts of your app.

An eexception occurs when using flutter_downloader package

I'm trying to use flutter_downloader package to download some files (images/pdf). There is a listView with ListTiles each containing a button to start downloading when clicked but this error occurs when scrolling the list view.
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter_downloader/src/downloader.dart': Failed assertion: line 30 pos 12: '!_initialized': FlutterDownloader.initialize() must be called only once!
//my code is like this:
import 'dart:io';
import 'dart:isolate';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class DownloadFile extends StatefulWidget {
DownloadFile({this.downloadUrl});
final String downloadUrl;
#override
_DownloadFileState createState() => _DownloadFileState();
}
class _DownloadFileState extends State<DownloadFile> {
String downloadId;
String _localPath;
ReceivePort _port = ReceivePort();
#override
void initState(){
super.initState();
_init();
}
Future<void> _init() async {
await FlutterDownloader.initialize();
IsolateNameServer.registerPortWithName(
_port.sendPort, 'downloader_send_port');
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
print("status: $status");
print("progress: $progress");
print("id == downloadId: ${id == downloadId}");
});
FlutterDownloader.registerCallback(downloadCallback);
_localPath = (await _findLocalPath()) + '/Download';
final savedDir = Directory(_localPath);
bool hasExisted = await savedDir.exists();
if (!hasExisted) {
savedDir.create();
}
}
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
print(
'Background Isolate Callback: task ($id) is in status ($status) and process ($progress)');
final SendPort send =
IsolateNameServer.lookupPortByName('downloader_send_port');
send.send([id, status, progress]);
}
Future<String> _findLocalPath() async {
final directory = await getExternalStorageDirectory();
return directory.path;
}
Future<bool> _checkPermission() async {
if (Theme.of(context).platform == TargetPlatform.android) {
PermissionStatus permission = await PermissionHandler()
.checkPermissionStatus(PermissionGroup.storage);
if (permission != PermissionStatus.granted) {
Map<PermissionGroup, PermissionStatus> permissions =
await PermissionHandler()
.requestPermissions([PermissionGroup.storage]);
if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
} else {
return true;
}
return false;
}
//----------------------------------------------------------------
#override
void dispose() {
super.dispose();
}
//---------------------------------------------------------------
#override
Widget build(BuildContext context) {
return FlatButton(
onPressed: () async {
if (await _checkPermission()) {
final taskId = await FlutterDownloader.enqueue(
url: widget.downloadUrl,
savedDir: _localPath,
showNotification:
true, // show download progress in status bar (for Android)
openFileFromNotification:
true, // click on notification to open downloaded file (for Android)
);
downloadId = taskId;
}
},
child: Text('Downloa File',style: TextStyle(color: Colors.teal),)
);
}
}
According to the Usage section in the flutter_downloader package and the error you are getting, you must call the FlutterDownloader.initialize not more than once.
You can do that in the main method of your application, just like so:
WidgetsFlutterBinding.ensureInitialized();
await FlutterDownloader.initialize();

Shared preference save location address from geolocator

i was able to get current location using geolocator, but i want to cache and restore the string address without using lastKnownLocation in geolocator. im using shared preferences but cannot make it work. i used shared preference several times on my other codes, but with geolocator its kind of complicated. and im super new to flutter/dart
code:
final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;
Position _currentPosition;
String _currentAddress;
String _locationCache;
String key = "location_cache";
#override
void initState() {
super.initState();
_getCurrentLocation();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("current location = " + _currentAddress),
Text("last location = " + __locationCache) // HERE GET STORED DATA ISNT WORKING
],
),
),
);
}
_getCurrentLocation() {
geolocator
.getCurrentPosition(desiredAccuracy: LocationAccuracy.best)
.then((Position position) {
setState(() {
_currentPosition = position;
});
_getAddressFromLatLng();
}).catchError((e) {
print(e);
});
}
_getAddressFromLatLng() async {
try {
List<Placemark> p = await geolocator.placemarkFromCoordinates(
_currentPosition.latitude, _currentPosition.longitude);
Placemark place = p[0];
setState(() {
_currentAddress = "${place.country}";
});
saveAddress();
} catch (e) {
print(e);
}
}
Future<bool> saveAddress() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return await prefs.setString(key, _currentAddress);
}
Future<String> retrieveAddress() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//Return String
return prefs.getString(key) ?? "";
}
loadAddress() {
retrieveAddress().then((value) {
setState(() {
_locationCache = value;
});
});
}
}
heres the working code without _locationCache:
Thank you for your time
If I understood you correctly, what you want to accomplish is to store the last address you caught and retrieve it if you don't have gps active.
To do so you could use SharedPreferences or SQLite, just check the documentation on how to use them.
found the solution. just replace loadAddress() function with
void save() {
String address = _currentAddress;
saveAddress(address);
}
void _updateName(String address) {
setState(() {
this.locationCache = address;
});
}
and then put retrieveAddress().then(updateName) inside initState()