Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Path is not taking as given and downloading in Download folder only #533

Open
pratik-7span opened this issue Sep 16, 2021 · 19 comments
Open
Labels
bug Something isn't working

Comments

@pratik-7span
Copy link

I am getting issues while downloading videos from the server. I had given the path for Android as (/storage/emulated/0/Movies/MyApp) but It's downloading video in the "Download" folder only.

Here is my code:

requestDownloadFile(String link, bool isShare) async {
    _permissionReady = await _checkPermission();

    if (_permissionReady) {
      FlutterDownloader.registerCallback(callback);

      var _directory = Platform.isAndroid ? Directory('/storage/emulated/0/Movies/MyApp') : await getApplicationDocumentsDirectory();

      String newPath = _directory.absolute.path;

      print("Absolute Path: $newPath");

      if(Platform.isIOS) {
        newPath += '/MyApp';
      }
      _directory = Directory(newPath);

      bool hasExisted = await _directory.exists();
      if (!hasExisted) {
        _directory.create();
      }

      _localPath = _directory.path;

      print(_localPath);

      String fileName = link.split('/').last;

      print(fileName);

      print(_localPath + '/' + fileName);

      String localFilePath = _localPath + '/' + fileName;

      if (await File(localFilePath).exists() && isShare) {
        Share.shareFiles([localFilePath]);
      } else {
        ReceivePort _port = ReceivePort();
        IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');

        streamSubscription = _port.listen((dynamic data) {
          DownloadTaskStatus status = data[1];
          if (status.value == 3) {
            print(fileName);
            print('Downloaded Path: ${_localPath + ' / ' + fileName}');
            streamSubscription.cancel();
            IsolateNameServer.removePortNameMapping('downloader_send_port');

            // Share only if clicked on share otherwise download
            if (isShare) Share.shareFiles([_localPath + '/' + fileName]);
          }
        });

        print('Path Before Downloading: $_localPath');
        await FlutterDownloader.enqueue(url: link, savedDir: _localPath, showNotification: true, openFileFromNotification: true, fileName: fileName);
      }
    }
  }

Here are the logs:

I/flutter (25574): Absolute Path: /storage/emulated/0/Movies/MyApp
I/flutter (25574): Directory: '/storage/emulated/0/Movies/MyApp'
I/flutter (25574): /storage/emulated/0/Movies/MyApp
I/flutter (25574): gbUG2Ag6LHA4UGoyG2agOeV6Uu03Thn8RVcsTu1Q.mp4
I/flutter (25574): /storage/emulated/0/Movies/MyApp/gbUG2Ag6LHA4UGoyG2agOeV6Uu03Thn8RVcsTu1Q.mp4
I/flutter (25574): Path Before Downloading: /storage/emulated/0/Movies/MyApp

D/DownloadWorker(25574): DownloadWorker{url=https://example.com/gbUG2Ag6LHA4UGoyG2agOeV6Uu03Thn8RVcsTu1Q.mp4,filename=gbUG2Ag6LHA4UGoyG2agOeV6Uu03Thn8RVcsTu1Q.mp4,savedDir=/storage/emulated/0/Movies/MyApp,header=,isResume=false

But after downloading its printing (from the library) as below:

D/DownloadWorker(25574): File downloaded (/storage/emulated/0/Download/gbUG2Ag6LHA4UGoyG2agOeV6Uu03Thn8RVcsTu1Q.mp4)
D/DownloadWorker(25574): Setting an intent to open the file /storage/emulated/0/Download/gbUG2Ag6LHA4UGoyG2agOeV6Uu03Thn8RVcsTu1Q.mp4

Can you please tell me why it's downloading the video in the Download folder only? Why it's not taking the path I have given?

@pratik-7span pratik-7span changed the title Path is not taking as given and saving in /Download folder Path is not taking as given and downloading in Download folder only Sep 16, 2021
@abeyshiferaw0
Copy link

i am also facing the same issue, i wanted to download a file to private storage by path provided by getApplicationSupportDirectory but the package keeps downloading to downloads folder in the external storage

@DpkPatil05
Copy link

Same issue here

@abeyshiferaw0
Copy link

abeyshiferaw0 commented Sep 17, 2021

i have checked the native android implementation, this isn't a bug don't know why but the path provided is ignored and is replaced by downloads media folder intentionally,

@RequiresApi(Build.VERSION_CODES.Q)
private Uri addFileToDownloadsApi29(String filename) {
    Uri collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
    try {
        ContentValues values = new ContentValues();
        values.put(MediaStore.Downloads.DISPLAY_NAME, filename);
        ContentResolver contentResolver = getApplicationContext().getContentResolver();
        return contentResolver.insert(collection, values);
    } catch (Exception e) {
        e.printStackTrace();
        log("Create a file using MediaStore API failed ");
    }
    return null;
}

its in DownloadWorker.java

@abeyshiferaw0
Copy link

For any one who wants to the downloaded files to private or local storage

1.go to the android implementation and look for DownloadWorkder.java file

2.look for this function addFileToDownloadsApi21 and replace its content with this
File newFile = new File(getApplicationContext().getFilesDir(), filename);
return newFile;

  1. also comment this
    // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    // uriApi29 = addFileToDownloadsApi29(filename);
    // if (isResume) {
    // outputStream = context.getContentResolver().openOutputStream(uriApi29, "wa");
    // } else {
    // outputStream = context.getContentResolver().openOutputStream(uriApi29, "w");
    // }
    // } else {
    // fileApi21 = addFileToDownloadsApi21(filename);
    // outputStream = new FileOutputStream(fileApi21, isResume);
    // }

and add this to bottom

fileApi21 = addFileToDownloadsApi21(filename);
outputStream = new FileOutputStream(fileApi21, isResume);

Also comment out a big chunk of code in => if (status == DownloadStatus.COMPLETE) {}. condition

seems reckless but its a fix, you can file your files in the local storage

@ReaganRealones
Copy link

Thank you @abeyshiferaw0 , works perfectly. Though I was wondering when this can be fixed in the master repo

@AbdulrhmanBazrto
Copy link

having same issue here, how you solve it? @abeyshiferaw0 please can you explain how to go to "go to the android implementation" ? I'm still having same problem I can't store the files into subfolder of downlad directory

@yelkamel
Copy link

yelkamel commented Oct 1, 2021

Same issue here, can someone do a fork with the fix ? ^^'

@JeremyGashu
Copy link

Also comment out a big chunk of code in => if (status == DownloadStatus.COMPLETE) {}. condition

Does it really work for you?

@abeyshiferaw0
Copy link

Also comment out a big chunk of code in => if (status == DownloadStatus.COMPLETE) {}. condition

Does it really work for you?

yes it does work, if you only want the downloaded file to be saved on the local private storage only

@abeyshiferaw0
Copy link

abeyshiferaw0 commented Oct 1, 2021

having same issue here, how you solve it? @abeyshiferaw0 please can you explain how to go to "go to the android implementation" ? I'm still having same problem I can't store the files into subfolder of download directory

if your using android studio double click shift and search for downloadWorker.java, open the file and you can edit the changes

@abeyshiferaw0
Copy link

abeyshiferaw0 commented Oct 1, 2021

Same issue here, can someone do a fork with the fix ? ^^'

https://github.com/abeyshiferaw0/flutter_downloader.git

this is the fork that i used, but it is only for downloading to internal storage only

just pass your desired location starting from getApplicationSupportDirectory() and it will work on both android and ios

e.g
`
/// to get downloaded file save path
Future getSaveDir() async {
Directory directory = await getApplicationSupportDirectory();
Directory saveDir = Directory("${directory.absolute.path}${Platform.pathSeparator}SUB_FOLDER");
bool exists = await saveDir.exists();
if (!exists) {
await saveDir.create(recursive: true);
}
return saveDir.path;
}

/// start download with path from getSaveDir()
FlutterDownloader.enqueue(
url: URL,
savedDir: getSaveDir(),
fileName: FILE_NAME,
showNotification: true,
openFileFromNotification: false,
);

`

@Cyp
Copy link

Cyp commented Oct 7, 2021

This may be duplicate of #525.

@franklink
Copy link

This is an epic fail. I have code in the field that is now downloading to the wrong directory. What in the world would make you change this behavior!!!???

@hnvn
Copy link
Member

hnvn commented Oct 9, 2021

I know this issue, it comes from updates in Android implementation due to support Scoped Storage model in Android 11. In Android 11, app can no longer create dedicated and app-specific directories with external storage. It causes savedDir broken and confused. I am in process to re-design this plugin with new strategy to manage file download location. It is still in triage and discussion so it's very appreciated to have contribution and feedback from developers for this PR

P/S: for temporary solution, I publish v1.7.1 to fix the issue in case of internal storage. Use-case of external storage in Android 11, savedDir will be ignored and downloaded files are always saved to Downloads folder (config by setting saveToPublicStorage to true)

@swarupbc
Copy link

@hnvn you can ask for this permission to create the folder
await requestPermission(Permission.manageExternalStorage);

@Amanullahgit
Copy link

addFileToDownloadsApi21

where can i find this file ?

@jr24jr
Copy link

jr24jr commented May 29, 2022

Had the same problem and fixed it.

flutter_downloader: 1.7.0
permission_handler: 8.1.5
external_path: 1.0.1

and replace it with:

flutter_downloader: 1.5.2
permission_handler: 8.1.5
external_path: 1.0.1

to be able to write you must have permissions: storage, manageExternalStorage, requestInstallPackages.
in AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

@digambernegi
Copy link

I guess removing or changing "SaveInPublicStorage" to false would save the file to your required directory.

final id = await FlutterDownloader.enqueue(
url: url,
savedDir: externalDir.path,
showNotification: true,
openFileFromNotification: true,
saveInPublicStorage: false);

@Ali-Kheiri
Copy link

@abeyshiferaw0
Is changing download worker java file currently working ? (api v 33)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests