添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I built an app to upload attachments to Firebase Storage, with the URL saved in Firestore. The upload part works nicely. I also added a download button for downloading the relevant attachment. When clicking the download button, the app should split the last '.' to identify the file type and download the relevant file path. However, unfortunately, when clicking the download button, an error occurs.

error

UI screenshot

A example for the file firestore url

https://firebasestorage.googleapis.com/v0/b/petpulz-93d6f.appspot.com/o/records%2F49785b2d-5bc2-47c1-9ac2-2654627851de3518522212366212285.jpg?alt=media&token=4690a174-c094-4019-a540-17ca8437a69e.jpg

My code

IconButton(
  icon: Icon(Icons.download),
  onPressed: () async {
    // Get the file from _selectedFiles
    final file = _selectedFiles[index];
    // Open the download dialog
    final directory = await getExternalStorageDirectory();
    final savePath = path.join(directory!.path, 'Download', file.path.split('/').last);
    await showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Download'),
        content: Text('Do you want to download ${file.path.split('/').last}'),
        actions: [
          TextButton(
            child: Text('Cancel'),
            onPressed: () => Navigator.pop(context),
          TextButton(
            child: Text('Download'),
            onPressed: () async {
              // Download the file
              await http.get(Uri.parse(file.path)).then((response) async {
                final bytes = response.bodyBytes;
                await File(savePath).writeAsBytes(bytes);
              // Close the dialog
              Navigator.pop(context);
              // Show a message to indicate that the download is complete
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Download complete')),

path provider package

  path_provider: ^2.0.2

how to solve this error ?

** AndroidManifest.xml**

print savepath screenshot

// change Directory and save path like this
final directory = await  Directory('/storage/emulated/0/Download');
final savePath = path.join(directory!.path,file.path.split('/').last);

change directory because an above android 10 version devices not access to use /storage/emulated/0/Android/data directory

thank you for your support ! still same error "/flutter (13275): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: FileSystemException: Cannot open file, path = '/storage/emulated/0/Download' (OS Error: Is a directory, errno = 21)" – Dasun Dola May 6 at 16:54

I solved the error and now file download working for android and ios prefectly.

  IconButton(
                                                icon: Icon(Icons.download),
                                                onPressed: () async {
                                                  // Get the file from _selectedFiles
                                                  final file = oneRecord!.fileUrls[index];
                                                  // Generate a random file name
                                                  final suffix = file.path.split('.').last.split('?').first;
                                                  final randomName = '${randomString(10)}.$suffix';
                                                  // Set the save path based on the platform
                                                  String savePath;
                                                  if (Platform.isIOS) {
                                                    final directory = await getApplicationDocumentsDirectory();
                                                    savePath = '${directory.path}/$randomName';
                                                  } else if (Platform.isAndroid) {
                                                    savePath = '/storage/emulated/0/Download/$randomName';
                                                  } else {
                                                    // Handle other platforms if necessary
                                                    return;
                                                  // Open the download dialog
                                                  await showDialog(
                                                    context: context,
                                                    builder: (context) =>
                                                        AlertDialog(
                                                      title: Text('Download'),
                                                      content: Text(
                                                          'Do you want to download $randomName ?'),
                                                      actions: [
                                                        TextButton(
                                                          child: Text('Cancel'),
                                                          onPressed: () =>
                                                              Navigator.pop(
                                                                  context),
                                                        TextButton(
                                                          child:
                                                              Text('Download'),
                                                          onPressed: () async {
                                                            if (await Permission
                                                                .storage
                                                                .request()
                                                                .isGranted) {
                                                              await http
                                                                  .get(Uri.parse(
                                                                          .path))
                                                                  .then(
                                                                      (response) async {
                                                                final bytes =
                                                                    response
                                                                        .bodyBytes;
                                                                await File(
                                                                        savePath)
                                                                    .writeAsBytes(
                                                                        bytes);
                                                            // Close the dialog
                                                            Navigator.pop(
                                                                context);
                                                            // Show a message to indicate that the download is complete
                                                            ScaffoldMessenger
                                                                    .of(context)
                                                                .showSnackBar(
                                                              SnackBar(
                                                                  content: Text(
                                                                      'Download complete')),

and for the ios path you should import

import 'package:path_provider/path_provider.dart';

for that import you need to install relevant package

path_provider: ^2.0.2

and also specially you need to give permisions in the AndroidManifest.xml file in android and info.plist file in ios folder

info.plist(ios) add these code line

 <key>LSSupportsOpeningDocumentsInPlace</key>
    <true/>
    <key>UIFileSharingEnabled</key>
    <true/>

simply these permissions are for the documents .

AndroidManifest.xml(android) add these permission code lines

  <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

On Android, the downloaded files should be saved to the download folder, and on iOS, they should be saved to the Files app in a separate folder created using the application name.

I should clarify that with this code, any file type can be downloaded to the device, not just PDF files and images.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.