SimonSimCity / Xamarin-CrossDownloadManager

A cross platform download manager for Xamarin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Get URL of downloaded file

JoshuaNovak919 opened this issue · comments

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

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);
    }

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.

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.

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?

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.