In android we use getFileDir() and getCacheDir() for accessing the Internal Storage. I can see that there's a path_provider plugin that I can use but I can only figure out getTemporaryDirectory() which is analogous to getCacheDir() of android. So is there any alternative way of doing what getFileDir() does in Android.
Is there any other way to do this that I'm aware of, or I'm missing something.
From Flutter sources:
/// Examples:
///
/// * iOS: `NSDocumentsDirectory`
/// * Android: The AppData directory.
static Future<Directory> getApplicationDocumentsDirectory() async {
return new Directory((await _pathProviderProxy.ptr.applicationDocumentsDirectory()).path);
To get internal storage directory path:
For Legacy Use these flutter plugin that provides external storage path and external public storage path,
ext_storage: ^latest_ver
String path = await ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOWNLOADS);
Details:https://pub.dev/packages/ext_storage
external_path:^latest_ver,
For NullSafety external_path is a flutter plugin that provides internal, external storage path and external public storage path,
String path=await ExternalPath.getExternalStoragePublicDirectory(
ExternalPath.DIRECTORY_DOWNLOADS);
Details:https://pub.dev/packages/external_path
Use this dart package: https://pub.dev/packages/path_provider_ex#-example-tab-
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:path_provider_ex/path_provider_ex.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<StorageInfo> _storageInfo = [];
#override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
List<StorageInfo> storageInfo;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
storageInfo = await PathProviderEx.getStorageInfo();
} on PlatformException {}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_storageInfo = storageInfo;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Internal Storage root:\n ${(_storageInfo.length > 0) ? _storageInfo[0].rootDir : "unavailable"}\n'),
Text(
'Internal Storage appFilesDir:\n ${(_storageInfo.length > 0) ? _storageInfo[0].appFilesDir : "unavailable"}\n'),
Text(
'Internal Storage AvailableGB:\n ${(_storageInfo.length > 0) ? _storageInfo[0].availableGB : "unavailable"}\n'),
Text(
'SD Card root: ${(_storageInfo.length > 1) ? _storageInfo[1].rootDir : "unavailable"}\n'),
Text(
'SD Card appFilesDir: ${(_storageInfo.length > 1) ? _storageInfo[1].appFilesDir : "unavailable"}\n'),
Text(
'SD Card AvailableGB:\n ${(_storageInfo.length > 1) ? _storageInfo[1].availableGB : "unavailable"}\n'),
],
) ,
),
);
}
}
Add path_provider to pubspec.yaml
import 'package:path_provider/path_provider.dart';
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
final directory = await _localPath;
Related
Preface:
I'm using the Screenshot package. In this package, there is a method captureAndSave() which saves a widget as an image to a specific location, however, when I call this function, my image is not being saved. Why?
Complete Code Example:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:screenshot/screenshot.dart';
class QrCodeScreen extends StatefulWidget {
const QrCodeScreen({Key? key}) : super(key: key);
#override
State<QrCodeScreen> createState() => _QrCodeScreenState();
}
class _QrCodeScreenState extends State<QrCodeScreen> {
final _screenshotController = ScreenshotController();
Image? image;
var doesTheImageExist = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (image == null)
TextButton(
child: Text("Save QR Code"),
onPressed: () async {
await _captureAndSaveQRCode();
image = await _loadImage();
setState(() {});
},
)
else
image!,
Text("Is the QR Code saved to your device? ${doesTheImageExist}"),
if (image == null)
Screenshot(
controller: _screenshotController,
child: _buildQRImage('_authProvider.user!.uid')),
],
),
);
}
Widget _buildQRImage(String data) {
return QrImage(
data: data,
size: 250.0,
gapless: false,
foregroundColor: Colors.black,
backgroundColor: Colors.white,
);
}
Future<String> get imagePath async {
final directory = (await getApplicationDocumentsDirectory()).path;
return '$directory/qr.png';
}
Future<Image> _loadImage() async {
return imagePath.then((imagePath) => Image.asset(imagePath));
}
Future<void> _captureAndSaveQRCode() async {
final path = await imagePath;
await _screenshotController.captureAndSave(path);
// It always returns false, although I'm saving the file using `captureAndSave` .
doesTheImageExist = File(path).existsSync();
}
}
The Question:
In the code above, when I click on the TextButton() that says "Save QR Code" it then calls _captureAndSaveQRCode() and _loadImage(). Hence my image should successfully be saved to my (Android) phone. However, I get an error:
Unable to load asset: /data/user/0/com.example.qr/app_flutter/qr.png
Full Traceback:
======== Exception caught by image resource service ================================================
The following assertion was thrown resolving an image codec:
Unable to load asset: /data/user/0/com.example.qr/app_flutter/qr.png
When the exception was thrown, this was the stack:
#0 PlatformAssetBundle.load (package:flutter/src/services/asset_bundle.dart:237:7)
<asynchronous suspension>
#1 AssetBundleImageProvider._loadAsync (package:flutter/src/painting/image_provider.dart:675:14)
<asynchronous suspension>
Image provider: AssetImage(bundle: null, name: "/data/user/0/com.example.qr/app_flutter/qr.png")
Image key: AssetBundleImageKey(bundle: PlatformAssetBundle#5986d(), name: "/data/user/0/com.example.qr/app_flutter/qr.png", scale: 1.0)
====================================================================================================
Why isn't my image being saved to the device when calling _captureAndSaveQRCode()?
Side note:
I recently posted an answer (currently in Bounty) with (almost) the same code as in this question which does work correctly, so, what's the difference?
The problem was that I had an empty setState:
onPressed: () async {
await _captureAndSaveQRCode();
image = await _loadImage();
setState(() {});
},
)
So to solve the problem, I removed the setState and also got rid of the _loadImage() function.
And then updated the image variable within the TextButton():
TextButton(
child: Text("Save QR Code"),
onPressed: () async {
await _captureAndSaveQRCode();
setState(() {
doesTheImageExist = true;
image = image;
});
},
)
Complete working example:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:screenshot/screenshot.dart';
class QrCodeScreen extends StatefulWidget {
const QrCodeScreen({Key? key}) : super(key: key);
#override
State<QrCodeScreen> createState() => _QrCodeScreenState();
}
class _QrCodeScreenState extends State<QrCodeScreen> {
final _screenshotController = ScreenshotController();
Image? image;
var doesTheImageExist = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (image == null)
TextButton(
child: Text("Save QR Code"),
onPressed: () async {
await _captureAndSaveQRCode();
setState(() {
doesTheImageExist = true;
image = image;
});
},
)
else
image!,
Row(children: [
Text('hi'),
Text("Is the QR Code saved to your device? ${doesTheImageExist}")
]),
if (image == null)
Screenshot(
controller: _screenshotController,
child: _buildQRImage('_authProvider.user!.uid')),
],
),
);
}
Widget _buildQRImage(String data) {
return QrImage(
data: data,
size: 250.0,
gapless: false,
foregroundColor: Colors.black,
backgroundColor: Colors.white,
);
}
Future<String> get imagePath async {
final directory = (await getApplicationDocumentsDirectory()).path;
return '$directory/qr.png';
}
// Future<Image> _loadImage() async {
// return imagePath.then((imagePath) => Image.asset(imagePath));
// }
Future<void> _captureAndSaveQRCode() async {
final path = await imagePath;
await _screenshotController.captureAndSave(path);
// It always returns false, although I'm saving the file using `captureAndSave` .
doesTheImageExist = File(path).existsSync();
}
}
load image with Image.file(File(imagePath))
Image.Asset is for loading images defined in pubspec.yaml
Edit:
the path in captureAndSave is directory path. it takes another optional argument fileName.
// previous code
// i create new getter for directory
Future<String> get dirPath async {
final directory = (await getApplicationDocumentsDirectory()).path;
return directory;
}
Future<String> get imagePath async {
final directory = await dirPath;
return '$directory/qr.png';
}
Future<Image> _loadImage() async {
return imagePath.then((imagePath) => Image.file(File(imagePath)));
}
Future<void> _captureAndSaveQRCode() async {
final path = await dirPath;
await _screenshotController.captureAndSave(path, fileName: "qr.png");
// It always returns false, although I'm saving the file using `captureAndSave` .
doesTheImageExist = File(path).existsSync();
}
// the rest of the code
I am trying to share a file using SharePlus. However, I get the following error:
The task is to generate a PDF file and share it through ios and android. I see that share_plus is able to share the file. However, I am unable to share by saving it in the applicationDocumentDirectory.
Update: I have attached a demo repo with codes from below. The error is showing in my app even when the repo is working without permissions fine. share_plus complains with below issues.
Repo: Link
Error:
Unhandled Exception: PlatformException(error, Failed to find configured root that contains /data/user/0/com.example.flutter_share_demo/app_flutter/someRandom.pdf, null, java.lang.IllegalArgumentException: Failed to find configured root that contains /data/user/0/com.example.flutter_share_demo/app_flutter/someRandom.pdf
The code is as follows:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:permission_handler/permission_handler.dart';
import 'package:share_plus/share_plus.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Share files')),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: TextButton(
child: const Text('Generate and Share PDF'),
onPressed: () async {
final pdf = pw.Document();
pdf.addPage(pw.Page(
build: (context) =>
pw.Center(child: pw.Text('Hello, World!')),
));
final Directory storageDir = getApplicationDocumentDirectory();
try {
File file = File('${storageDir.path}/someRandom.pdf');
await file.writeAsBytes(await pdf.save());
print(file.path);
print('File exists: ${await file.exists()}');
Share.shareFiles([file.path], subject: 'Shared file');
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Permission denied')));
}
} on PlatformException catch (ex) {
print(ex);
} catch (ex) {
print(ex);
}
},
),
),
],
));
}
}
I am currently working on Notification Feature so when a new Update is availible the User gets a Dialog where he can choose to Update or not. I'm doing it with Firebase Remote Config where i have a Parameter called "force_update_current_version" where i then add the Value for the Version for checking. But I do get following errors.
Thanks for your help and i wish you a healty start into the new Year.
Main.dart Code
import 'checkUpdate.dart';
#override
void initState() {
try {
versionCheck(**context**);
} catch (e) {
print(e);
}
**super**.initState();
}
context error: Undefined name 'context'.
Try correcting the name to one that is defined, or defining the name.
super error: Invalid context for 'super' invocation.
checkUpdate.dart Code
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:package_info/package_info.dart';
import 'package:flutter/cupertino.dart';
const APP_STORE_URL = 'https://apps.apple.com/us/app/appname/idAPP-ID';
const PLAY_STORE_URL =
'https://play.google.com/store/apps/details?id=APP-ID';
versionCheck(context) async {
//Get Current installed version of app
final PackageInfo info = await PackageInfo.fromPlatform();
double currentVersion = double.parse(info.version.trim().replaceAll(".", ""));
//Get Latest version info from firebase config
final RemoteConfig remoteConfig = await RemoteConfig.instance;
try {
// Using default duration to force fetching from remote server.
await remoteConfig.fetch(expiration: const Duration(seconds: 0));
await remoteConfig.activateFetched();
remoteConfig.getString('force_update_current_version');
double newVersion = double.parse(remoteConfig
.getString('force_update_current_version')
.trim()
.replaceAll(".", ""));
if (newVersion > currentVersion) {
_showVersionDialog(context);
}
} on FetchThrottledException catch (exception) {
// Fetch throttled.
print(exception);
} catch (exception) {
print('Unable to fetch remote config. Cached or default values will be '
'used');
}
}
//Show Dialog to force user to update
_showVersionDialog(context) async {
await showDialog<String>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
String title = "New Update Available";
String message =
"There is a newer version of app available please update it now.";
String btnLabel = "Update Now";
String btnLabelCancel = "Later";
return Platform.isIOS
? new CupertinoAlertDialog(
title: Text(title),
content: Text(message),
actions: <Widget>[
FlatButton(
child: Text(btnLabel),
onPressed: () => _launchURL(**Config**.APP_STORE_URL),
),
FlatButton(
child: Text(btnLabelCancel),
onPressed: () => Navigator.pop(context),
),
],
)
: new AlertDialog(
title: Text(title),
content: Text(message),
actions: <Widget>[
FlatButton(
child: Text(btnLabel),
onPressed: () => _launchURL(**Config**.PLAY_STORE_URL),
),
FlatButton(
child: Text(btnLabelCancel),
onPressed: () => Navigator.pop(context),
),
],
);
},
);
}
_launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
Config Error for App and Play Store: Undefined name 'Config'.
Try correcting the name to one that is defined, or defining the name.
In checkUpdate.dart we need to import the firebase_remote_config package that exposes the RemoteConfig class:
import 'package:firebase_remote_config/firebase_remote_config.dart';
Make sure to install it before.
The versionCheck() function shall be invoked from a StatefulWidget, hence, a good place to call it would be inside the first screen Widget, for example:
class FirstScreen extends StatefulWidget {
const FirstScreen({ Key key }) : super(key: key);
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => versionCheck(context));
}
#override
Widget build(BuildContext context) {
return Container(color: const Color(0xFFFFE306));
}
}
I am trying to make an app which opens up a PPT, PDF or Docx file using the default application on the device by tapping on a button in my application. If there is no default app, it should open the "Open With" menu.
I tried to use open_file. But it didn't work. I also tried a few other methods I saw on StackOverflow, but none of them worked for me.
To open file on Internet you can use package https://pub.dev/packages/url_launcher
code snippet for url_launcher
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(Scaffold(
body: Center(
child: RaisedButton(
onPressed: _launchURL,
child: Text('Open File'),
),
),
));
}
_launchURL() async {
const url = 'https://yoursite/sample.pdf';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
To open file in local path
You can see working demo and full code below
code snippet
final filePath = '/sdcard/Download/sample.pdf';
print('${filePath}');
final message = await OpenFile.open(filePath);
full code
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:open_file/open_file.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _openResult = 'Unknown';
Future<void> openFile() async {
final filePath = '/sdcard/Download/sample.pdf';
print('${filePath}');
final message = await OpenFile.open(filePath);
setState(() {
_openResult = message;
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('open result: $_openResult\n'),
FlatButton(
child: Text('Tap to open file'),
onPressed: openFile,
),
],
),
),
),
);
}
}
Emulator SDCard Download directory has a pdf file
working demo
I want to get all file in listview with flutter project but how to access the external folder.
I have created a folder with name 'MyFile' and it is created at "/storage/emulated/0/MyFile",
but below code pointing at "/storage/emulated/0/Android/data/com.example.demo/MyFile".
I don't know why below code is not working
Directory externalDirectory = await getExternalStorageDirectory();
print('External Storage:$externalDirectory');
// External storage: /storage/emulated/0/Android/data/com.example.demo/MyFile
When using Flutter Official path_provider package, getExternalStorageDirectory() will always return path to /storage/emulated/0/your-package-name/files.
To get /storage/emulated/0/, you can used a Third-party package ext_storage. Below code will return your desired Directory path
var externalDirectoryPath = await ExtStorage.getExternalStorageDirectory();
print(path); // /storage/emulated/0
Now to create a Folder, you can use the below function:
//this will create a Folder in the storage/emulated/0
new Directory(externalDirectoryPath +'/YourfolderName')
.create()
.then((Directory directory)
{
print(directory.path);
});;
'
Edit post picture 2 to prove it work.
code snippet to create directory , file
new Directory('/storage/emulated/0/MyFile').create()
// The created directory is returned as a Future.
.then((Directory directory) {
print(directory.path);
});
new File('/storage/emulated/0/MyFile/test.txt').create(recursive: true)
.then((File file) {
// Stuff to do after file has been created...
print('${file.path}');
});
var dir = Directory('/storage/emulated/0/MyFile');
print('${dir.path}');
print('${dir.list().toList()}');
full code for create directory and file
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:simple_permissions/simple_permissions.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 Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
new Directory('/storage/emulated/0/MyFile').create()
// The created directory is returned as a Future.
.then((Directory directory) {
print(directory.path);
});
new File('/storage/emulated/0/MyFile/test.txt').create(recursive: true)
.then((File file) {
// Stuff to do after file has been created...
print('${file.path}');
});
var dir = Directory('/storage/emulated/0/MyFile');
print('${dir.path}');
print('${dir.list().toList()}');
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
SimplePermissions.requestPermission(Permission.WriteExternalStorage);
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
please use package flutter_file_manager https://pub.dev/packages/flutter_file_manager
I have tested with real device, it works fine
full code
// framework
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
// packages
import 'package:flutter_file_manager/flutter_file_manager.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:simple_permissions/simple_permissions.dart';
void main() => runApp(new MyApp());
#immutable
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
//SimplePermissions.requestPermission(Permission.ReadExternalStorage);
SimplePermissions.requestPermission(Permission.WriteExternalStorage);
return new MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Flutter File Manager Demo"),
),
body: FutureBuilder(
future: _files(), // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return Text('Awaiting result...');
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
return snapshot.data != null
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) => Card(
child: ListTile(
title: Column(children: [
Text('Size: ' +
snapshot.data[index]
.statSync()
.size
.toString()),
Text('Path: ' +
snapshot.data[index].path.toString()),
Text('Date: ' +
snapshot.data[index]
.statSync()
.modified
.toUtc()
.toString())
]),
subtitle: Text(
"Extension: ${p.extension(snapshot.data[index].absolute.path).replaceFirst('.', '')}"), // getting extension
)))
: Center(
child: Text("Nothing!"),
);
}
return null; // unreachable
},
)),
);
}
_files() async {
var root = await getExternalStorageDirectory();
var files = await FileManager(root: root).walk().toList();
for(var i = 0;i<files.length;i++) {
print("${files[i].path} ");
}
return files;
}
}
working demo in emulator
I had the same problem, while Android SDK version >30 or 31 doesn't allow to read from other directories but you definitely read from your directory without any permission.
Add '//' + directory path & your problem will be resolved
So it means that your path will be '//'+ getExternalStorageDirectory())!.path
This is the code to save and retrieve the file work on both SDK > 30 and SDK =< 30.
final directory = (await getExternalStorageDirectory())!.path;
ByteData? byteData =
await (image.toByteData(format: ui.ImageByteFormat.png));
Uint8List pngBytes = byteData!.buffer.asUint8List();
File imgFile = new File('$directory/screenshot${rng.nextInt(2000)}.png');
await imgFile.writeAsBytes(pngBytes);
setState(() {
_imageFile = imgFile;
});
// Add '//' + directory path & your problem will be resolved
return '//'+imgFile.path;
First I'm saving the image in the directory then I'm reading it.