I am trying to access storage on an Android emulator from Flutter.
Here is the code that I'm testing it with:
void test() async {
PermissionStatus storageStatus = await Permission.storage.request();
if (storageStatus == PermissionStatus.granted) {
print("granted");
}
if (storageStatus == PermissionStatus.denied) {
print("denied");
}
if (storageStatus == PermissionStatus.permanentlyDenied) {
openAppSettings();
}
}
I have included the "android.permission.WRITE_EXTERNAL_STORAGE" permission in the AndroidManifest.xml.
I have tried giving permissions for Camera and it worked, but it doesn't work for storage.
When I check for the storages permission status it is permanently denied, and when app's settings open it says "No permissions requested".
I have tried running "flutter clean" which seems to be necessary when updating the Manifest.
I have tried uninstalling from the phone and reinstalling the app
How do I fix it?
once try to do this.
Add in your manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
for requesting permission.
Future<bool> requestPermission(Permission permission) async {
if (await permission.isGranted) {
return true;
} else {
var result = await permission.request();
if (result == PermissionStatus.granted) {
return true;
}
}
return false;
}
for checking permission also you can change dialog text as per your need
Future<bool> checkPermission() async {
///For Check permission..
if (Platform.isAndroid ? !await requestPermission(Permission.storage) && !await requestPermission(Permission.manageExternalStorage) : !await requestPermission(Permission.storage)) {
await Get.dialog(CupertinoAlertDialog(
title: const Text("Photos & Videos permission"),
content: const Text(" Photos & Videos permission should be granted to connect with device, would you like to go to app settings to give Bluetooth & Location permissions?"),
actions: <Widget>[
TextButton(
child: const Text('No thanks'),
onPressed: () {
Get.back();
}),
TextButton(
child: const Text('Ok'),
onPressed: () async {
Get.back();
await openAppSettings();
})
],
));
return false;
} else {
return true;
}
}
Use like this
I hope these things solve your issue.
Related
I am developing a custom object detection app for Android using the camera package in conjunction with tflite. When the screen loads, it asks the user for camera and microphone permission using the permission_handler package. I'm also using a ChangeNotifier class to store the results after asking the user for permission. Then, depending on whether the user accepts these conditions, I'm conditionally rendering widgets. Now, there are a few cases here:
a. Neither is granted → request for both permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings
b. Permission for the camera is granted, but the user denied mic permission → request for mic permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings
c. Permission for the mic is granted, but camera permission is denied → request for camera permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings
d. Neither is granted → request for both permission if they aren't permanently denied and if they are then ask the user to manually grant them from settings
Here is my current implementation.
https://codeshare.io/X8eKWE
The problem is that even when the user grants both the permissions, it shows:
'Camera permission was denied!', 'Request camera permission' widget.
So, how can I handle all four different cases in a more elegant way?
class _LiveFeedState extends State<LiveFeed> with WidgetsBindingObserver {
Widget? errWidget;
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.resumed:
log("App Resumed");
_checkCameraPermissionStatus();
break;
case AppLifecycleState.inactive:
log("App Inactive");
break;
case AppLifecycleState.paused:
log("App Paused");
break;
case AppLifecycleState.detached:
log("App Detached");
break;
}
}
#override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
Widget bodyWidget() {
return CameraFeed...;
}
Widget permissionScreen(Function onPressedHandler, String titleText, String buttonText) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(titleText),
ElevatedButton(
onPressed: () {
onPressedHandler();
},
child: Text(buttonText)),
],
);
}
Future<void> _checkCameraPermissionStatus() async {
var status = await Permission.camera.request().then((value) => value);
switch (status) {
case PermissionStatus.granted:
errWidget = await _checkMicPermissionStatus();
setState(() {});
break;
case PermissionStatus.denied:
setState(() {
errWidget = permissionScreen(_checkCameraPermissionStatus, 'Camera permission was denied!', 'Request camera permission');
});
break;
case PermissionStatus.permanentlyDenied:
setState(() {
errWidget = permissionScreen(openAppSettings, 'Camera permission was permanently denied! Open app setings and manually grant permission', 'Open app settings');
});
break;
default:
errWidget = await _checkMicPermissionStatus();
setState(() {});
break;
}
}
Future<Widget> _checkMicPermissionStatus() async {
var status = await Permission.microphone.request().then((value) => value);
switch (status) {
case PermissionStatus.granted:
return bodyWidget();
case PermissionStatus.denied:
return permissionScreen(_checkCameraPermissionStatus, 'Microphone permission was denied!', 'Request Microphone permission');
case PermissionStatus.permanentlyDenied:
return permissionScreen(openAppSettings, 'Microphone permission was permanently denied! Open app setings and manually grant permission', 'Open app settings');
default:
return bodyWidget();
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: isPortrait
? AppBar(
title: const Text("SpotHole"),
)
: null,
body: FutureBuilder(
future: Future.wait([Permission.camera.status, Permission.microphone.status]),
builder: (BuildContext context, AsyncSnapshot<List<PermissionStatus>> snapshot) {
if (snapshot.hasData) {
if (snapshot.data![0] == PermissionStatus.granted ||
snapshot.data![0] == PermissionStatus.limited ||
snapshot.data![1] == PermissionStatus.granted ||
snapshot.data![1] == PermissionStatus.limited) {
return bodyWidget();
} else {
if (errWidget != null) {
return errWidget!;
} else {
if (snapshot.data![0] != PermissionStatus.granted || snapshot.data![0] != PermissionStatus.limited) {
return permissionScreen(_checkCameraPermissionStatus, 'Camera permission was denied!', 'Request camera permission');
} else {
return permissionScreen(_checkCameraPermissionStatus, 'Microphone permission was denied!', 'Request Microphone permission');
}
}
}
} else {
return const CircularProgressIndicator.adaptive();
}
},
)));
}
}
I am currently using the latest geolocator that is 'geolocator: ^9.0.1'and for some reason am not able to get any data from the position function when i run
bool isLoc = await Geolocator.isLocationServiceEnabled();
print(isLoc);
The result is true which i think means the location services are all enabled but when i run
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.best);
print('position');
nothing is been returned i have tried all the accuracy values low, high, best,lowest, medium am really confused at what could be wrong i have also try it in the initState and also using a *button
Here is the full dart code
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class GeoLoc extends StatefulWidget {
const GeoLoc({Key? key}) : super(key: key);
#override
State<GeoLoc> createState() => _GeoLocState();
}
class _GeoLocState extends State<GeoLoc> {
#override
void initState() {
super.initState();
getLoc();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(onPressed: () {
getLoc();
},
child: const Text('Get Location'),
),
],
);
}
getLoc() async{
bool isLoc = await Geolocator.isLocationServiceEnabled();
print(isLoc);
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
}
}
Below is your code modified, pls try it. you forget to ask for geolocation permission
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class GeoLoc extends StatefulWidget {
const GeoLoc({Key? key}) : super(key: key);
#override
State<GeoLoc> createState() => _GeoLocState();
}
class _GeoLocState extends State<GeoLoc> {
#override
void initState() {
super.initState();
getLoc()
.then((value) => print("Location: " + value.toJson().toString()));
}
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(onPressed: () {
getLoc()
.then((value) => print("Location: " + value.toJson().toString()));
},
child: const Text('Get Location'),
),
],
);
}
getLoc() async{
bool serviceEnabled;
LocationPermission permission;
// Test if location services are enabled.
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// Location services are not enabled don't continue
// accessing the position and request users of the
// App to enable the location services.
Geolocator.openLocationSettings();
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
// Permissions are denied, next time you could try
// requesting permissions again (this is also where
// Android's shouldShowRequestPermissionRationale
// returned true. According to Android guidelines
// your App should show an explanatory UI now.
Geolocator.openAppSettings();
}
}
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
// When we reach here, permissions are granted and we can
// continue accessing the position of the device.
return await Geolocator.getCurrentPosition();
}
}
Also make sure you have below permission in your AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
I have been trying to create a backup of Sqflite databases in Flutter. Even after giving permissions, I continue to get the following error message:
E/flutter (23753): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: FileSystemException: Cannot copy file to '/data/user/0/com.maximuzindia.myapp/files/DBBackup.db', path = '/data/user/0/com.maximuzindia.myapp/databases/Database.db' (OS Error: No such file or directory, errno = 2)
I understand that with Android 11, there is a scoped storage permissions and hence have decided to save the file to the app directory itself. However, since it is a backup of the database, I would strongly prefer to store it in an external storage area. But in both the cases, I get the same error.
Below is my code to backup the database:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:maamaka/controllers/loading_controller.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:sqflite/sqflite.dart';
class BackUpDatabase extends StatefulWidget {
const BackUpDatabase({Key? key}) : super(key: key);
#override
State<BackUpDatabase> createState() => _BackUpDatabaseState();
}
class _BackUpDatabaseState extends State<BackUpDatabase> {
String message = '';
#override
void initState() {
super.initState();
//loadingController.backupDatabases();
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(children: [
Text(message),
ElevatedButton(
onPressed: () async {
final dbFolder = await getDatabasesPath();
File source1 = File('$dbFolder/Database.db');
//Option 1 : To store it in external storage area.
/* Directory copyTo = Directory(
"storage/emulated/0/Android/data/com.maximuzindia.myapp/files/Download"); */
//Option 2 : To store it in the app directory in a new folder called files.
Directory copyTo =
Directory("/data/user/0/com.maximuzindia.myapp/files");
if ((await copyTo.exists())) {
print("Path exist");
var status = await Permission.storage.status;
if (!status.isGranted) {
await Permission.storage.request();
}
if (await Permission.storage.request().isGranted) {
print('Permission granted');
}
if (await Permission.manageExternalStorage.request().isGranted) {
print('Permission for External Storage Granted');
}
} else {
print("not exist");
if (await Permission.storage.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
await copyTo.create();
} else if (await Permission.manageExternalStorage.request().isGranted) {
await copyTo.create();
print('Permission for External Storage Granted');
}
else {
print('Please give permission');
}
}
String newPath = "${copyTo.path}/DBBackup.db";
print(copyTo.path.toString());
await source1.copy(newPath);
setState(() {
message = 'Successfully Copied DB';
});
},
child: const Text('Copy DB'),
),
]),
);
}
}
My Android Manifest has the following:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
My build.gradle has : compileSdkVersion 31
Would appreciate a solution for both the options ie., store in external storage or store in the app folder.
I try to display whatsapp Status images from the File directory ('/storage/emulated/0/WhatsApp/Media/.Statuses').
But there do not appear any image. Console showing => "FAIL TO Open File: no Such File or Directory".
also i change The File Path to DCIM ('/storage/emulated/0/DCIM/Camera/'), and it was possible to display the image.
What can be the problem here?
My code:
final Directory _photoDir = new Directory(
'/storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/.Statuses/');
#override
Widget build(BuildContext context) {
if (!Directory("${_photoDir.path}").existsSync()) {
return Container(
child: Center(
child: Text("install WhatsApp\nsee your friends status here!"),
),
);
} else {
print(_photoDir.path);
var imageList = _photoDir
.listSync()
.map((item) => item.path)
.where((item) => item.endsWith(".jpg"))
.toList(growable: false);
print(imageList.length);
if (imageList.length > 0) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: imageList.length,
itemBuilder: (context, index) {
String imgPath = imageList[index];
return Hero(
tag: imgPath,
child: Image.file(
File(imgPath),
fit: BoxFit.fill,
));
},
);
} else {
return Container(
child: Center(
child: Text("Sorry No Status found..!"),
),
);
}
}
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Permissions options for the `storage` group -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Get the Permistion
Future<void> requestLocationPermission() async {
final status = await Permission.storage.request();
Permission.photos.request();
if (status == PermissionStatus.granted) {
print('Permission Granted');
} else if (status == PermissionStatus.denied) {
print('Permission denied');
} else if (status == PermissionStatus.permanentlyDenied) {
print('Permission Permanently Denied');
await openAppSettings();
}
}
#override
void initState() {
super.initState();
requestLocationPermission();
}
I think that. Your selected directory is a hidden file directory. so you cant get that file. I am not sure try another directory.
I need my app to read step count from Google Fit. I'm using health 3.05 package. For now I copied the example code to see if it works and unfortunately it's not. Of course I did every step from this packge readme. I set up OAuth2 Client ID, I changed gradle.properties as they shown and in AndroidManifest.xml I put <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> . However after running app I don't get any permission window and when I click the button to get data I got an error "Authorization not granted" in console. What should I do? Thanks
Here is my code that I copied form package example:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:health/health.dart';
class DailyStepsScreen extends StatefulWidget {
#override
_DailyStepsScreenState createState() => _DailyStepsScreenState();
}
enum AppState {
DATA_NOT_FETCHED,
FETCHING_DATA,
DATA_READY,
NO_DATA,
AUTH_NOT_GRANTED
}
class _DailyStepsScreenState extends State<DailyStepsScreen> {
List<HealthDataPoint> _healthDataList = [];
AppState _state = AppState.DATA_NOT_FETCHED;
#override
void initState() {
super.initState();
}
Future<void> fetchData() async {
/// Get everything from midnight until now
DateTime startDate = DateTime(2020, 11, 07, 0, 0, 0);
DateTime endDate = DateTime(2025, 11, 07, 23, 59, 59);
HealthFactory health = HealthFactory();
/// Define the types to get.
List<HealthDataType> types = [
HealthDataType.STEPS,
HealthDataType.WEIGHT,
HealthDataType.HEIGHT,
HealthDataType.BLOOD_GLUCOSE,
HealthDataType.DISTANCE_WALKING_RUNNING,
];
setState(() => _state = AppState.FETCHING_DATA);
/// You MUST request access to the data types before reading them
bool accessWasGranted = await health.requestAuthorization(types);
int steps = 0;
if (accessWasGranted) {
try {
/// Fetch new data
List<HealthDataPoint> healthData =
await health.getHealthDataFromTypes(startDate, endDate, types);
/// Save all the new data points
_healthDataList.addAll(healthData);
} catch (e) {
print("Caught exception in getHealthDataFromTypes: $e");
}
/// Filter out duplicates
_healthDataList = HealthFactory.removeDuplicates(_healthDataList);
/// Print the results
_healthDataList.forEach((x) {
print("Data point: $x");
steps += x.value.round();
});
print("Steps: $steps");
/// Update the UI to display the results
setState(() {
_state =
_healthDataList.isEmpty ? AppState.NO_DATA : AppState.DATA_READY;
});
} else {
print("Authorization not granted");
setState(() => _state = AppState.DATA_NOT_FETCHED);
}
}
Widget _contentFetchingData() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.all(20),
child: CircularProgressIndicator(
strokeWidth: 10,
)),
Text('Fetching data...')
],
);
}
Widget _contentDataReady() {
return ListView.builder(
itemCount: _healthDataList.length,
itemBuilder: (_, index) {
HealthDataPoint p = _healthDataList[index];
return ListTile(
title: Text("${p.typeString}: ${p.value}"),
trailing: Text('${p.unitString}'),
subtitle: Text('${p.dateFrom} - ${p.dateTo}'),
);
});
}
Widget _contentNoData() {
return Text('No Data to show');
}
Widget _contentNotFetched() {
return Text('Press the download button to fetch data');
}
Widget _authorizationNotGranted() {
return Text('''Authorization not given.
For Android please check your OAUTH2 client ID is correct in Google Developer Console.
For iOS check your permissions in Apple Health.''');
}
Widget _content() {
if (_state == AppState.DATA_READY)
return _contentDataReady();
else if (_state == AppState.NO_DATA)
return _contentNoData();
else if (_state == AppState.FETCHING_DATA)
return _contentFetchingData();
else if (_state == AppState.AUTH_NOT_GRANTED)
return _authorizationNotGranted();
return _contentNotFetched();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.file_download),
onPressed: () {
fetchData();
},
)
],
),
body: Center(
child: _content(),
)
);
}
}
Step 1 use health: 3.0.4
Step 2 do proper set up for OAuth2 Client ID, download new google-service.json
Step 3 From Android 10. you have to add ACTIVITY_RECOGNITION for getting STEP Count permission in AndroidManifest.xml.
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
Step 4 And then using permission_handler ask for permission.
if (Platform.isAndroid) {
final permissionStatus = Permission.activityRecognition.request();
if (await permissionStatus.isDenied ||
await permissionStatus.isPermanentlyDenied) {
showToast(
'activityRecognition permission required to fetch your steps count');
return;
}
}
FINALLY GOT THIS ISSUE SOLVED!!
So the problem doesn't lie in the version I am using 3.4.0 but still got the problem solved
Authorization not granted. And stuck in loading screen
Stuck in authorization request screen
When you create your OAuth 2.0 consent screen try to add at least 2 email addresses to the TEST USER section and make sure to login from that emails.
Add 2 email addresses in Test User
After that make sure to verify your application from Google, it will work until you test your app once you release the application, it will not work
Verify Your Application from Google
Final Result
Step 1 use health: 3.0.4
Step 2 Add permission function
Step 3 Start your function inside of initstate