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

Get URL of downloaded file #27

Closed
JoshuaNovak919 opened this issue Jul 20, 2016 · 5 comments
Closed

Get URL of downloaded file #27

JoshuaNovak919 opened this issue Jul 20, 2016 · 5 comments

Comments

@JoshuaNovak919
Copy link

How can I get the url of the downloaded file or the path that it is downloading to by default?

@SimonSimCity
Copy link
Owner

SimonSimCity commented Jul 20, 2016

Sorry, I forgot to mention that and neither created an example for it as I promised in the documentation.

On iOS, I'd always set the property, as the recommended option shows (https://github.com/SimonSimCity/Xamarin-CrossDownloadManager#recommended-option---custom-location), because the system anyways just copies the file after the download is done. If you don't want this behavior, please extend UrlSessionDownloadDelegate and overwrite the method DidFinishDownloading in https://github.com/SimonSimCity/Xamarin-CrossDownloadManager/blob/master/DownloadManager/Plugin.DownloadManager.iOS/UrlSessionDownloadDelegate.cs#L64

On Android, you have to ask the native DownloadManager after the file finished downloading. Here's an example of how to copy the file to a private destination (something that isn't possible when setting the path in the native download manager). This code should be called quite early, before any of the downloads is started.

    var downloadManager = CrossDownloadManager.Current;

    var itemStatusChanged = new System.Action<IDownloadFile, string> ((file, methodName) => {
        switch (methodName) {
        case "Status":
            switch (file.Status) {
            case DownloadFileStatus.COMPLETED:
                var nativeDownloadManager = (Android.App.DownloadManager)ApplicationContext.GetSystemService (Context.DownloadService);

                var source = nativeDownloadManager.GetUriForDownloadedFile (((DownloadFileImplementation)file).Id);
                var destination = Mvx.Resolve<IStorageManager> ().DefaultStorage.GetUrlByFile (file);
                using (Stream stream = ApplicationContext.ContentResolver.OpenInputStream (source)) {
                    using (var dest = File.OpenWrite (destination)) {
                        stream.CopyTo (dest);
                    }
                }
                nativeDownloadManager.Remove (((DownloadFileImplementation)file).Id);

                break;
            }
            break;
        }
    });

    downloadManager.Queue.CollectionChanged += (sender, e) => {
        if (e.NewItems != null) {
            foreach (var item in e.NewItems) {
                ((IDownloadFile)item).PropertyChanged += (sender2, e2) => itemStatusChanged ((IDownloadFile)sender2, e2.PropertyName);
            }
        }
    };

    foreach (var item in downloadManager.Queue) {
        item.PropertyChanged += (sender, e) => itemStatusChanged ((IDownloadFile)sender, e.PropertyName);
    }

@JoshuaNovak919
Copy link
Author

I'm a bit confused with the Android code you gave. Where are you getting IStorageManager? Also, i'm not using Mvx and i'm using Xamarin.Forms, so i'm a bit confused how I would make this work.

@SimonSimCity
Copy link
Owner

Here you need platform-specific code. I don't know if and how easy that's possible with Xamarin.Forms - I've never used it. But it shouldn't be as hard, as you also have an Application class in your Android project, right?

IStorageManager is something I wrote on my own to have a more flexible implementation for storing data than what the PCLStorage package provides me. The rest of the code is in no way bound to MvvmCross (here I use the Mvx class of this package). the call for Mvx.Resolve<IStorageManager> ().DefaultStorage.GetUrlByFile() just returns a string to a location I can copy the file-stream of my downloaded file to.

But as you just wanted to know the destination of the temporary file, you'll have it in the variable source in the 10th line of the example.

@JoshuaNovak919
Copy link
Author

For some reason i'm getting things like this content://downloads/my_downloads/65 for source. It's not using the file name, but showing the number. Is there a way to get the actual url to the file so I can open it with PCL Storage?

@SimonSimCity
Copy link
Owner

SimonSimCity commented Jul 21, 2016

It isn't that easy to get the native path, as Android likes to have an abstraction overlay for your app. This pays off for them and you, as you don't have to care about paths when the user, even while having the app running in the background, chooses to move it from the internal to the external storage.

I would stick to using Android.Content.ContentResolver.OpenInputStream() to get the System.IO.Stream of the file and move it to a folder at your control, like I did in the sample code.

If you still need it, I guess you could find a solution here http://stackoverflow.com/questions/19985286/convert-content-uri-to-actual-path-in-android-4-4 until Android again changes the implementation.

At the end, every Android installation has a native Download app, where you see all files, downloaded by the native download manager. To remove your download from that list, don't forget to call Android.App.DownloadManager.Remove(). This will also delete the file from the content resolver and the file system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants