cancel
Showing results for 
Search instead for 
Did you mean: 

DownloadManager?

pseudoscience
Explorer
Hi fellow devs,

We're pretty much done with our app, but it involves a download of a large video file. We've got it working using 'httpwebrequest', but this requires the user to keep the app open - and because it's such a large file, it seems unlikely anyone would keep the app open that long. So we're trying to figure out how to invoke android.app.DownloadManager so it can download in the background.

We see plenty of apps in the Oculus Store that use it, some of these apps are definitely built in Unity.

Our best guess is that it requires building a Java plugin, but considering how common this problem probably is there's little documentation about it - we were hoping someone on the forum has a solution?

Thanks!
11 REPLIES 11

RemiL
Explorer
You can also use AndroidJavaObject,AndroidJavaClass and AndroidJavaProxy class instead of implementing a whole plugin.
I will probably have the same problem soon..

By the way, I think it's better to use UnityWebRequest than httpwebrequest.

vrdaveb
Oculus Staff
You can also use AndroidJavaObject,AndroidJavaClass and AndroidJavaProxy class 
Yes, see http://docs.unity3d.com/Manual/PluginsForAndroid.html.

pseudoscience
Explorer
Thanks Dave/RemiL - we're still struggling with this. We initial got Toast messages working, so we tried to elaborate with DownloadManager per the below, but it's not working:









Sample Code:

currentActivity.Call ("runOnUiThread", new AndroidJavaRunnable (() => {


            try {


                AndroidJavaClass uriClass = new AndroidJavaClass ("android.net.Uri");


                AndroidJavaObject uriObject = uriClass.CallStatic<AndroidJavaObject> ("parse", "http://website.com/video.mp4");


                AndroidJavaObject request = new AndroidJavaObject ("android.app.DownloadManager$Request", uriObject);


        


                AndroidJavaObject downloadManager = new AndroidJavaClass ("android.app.DownloadManager");


                downloadManager = currentActivity.Call<AndroidJavaObject> ("getSystemService", "DOWNLOAD_SERVICE");




                long downloadID = downloadManager.CallStatic<long> ("enqueue", request);




                _text.GetComponent<UnityEngine.UI.Text>().text = downloadID.ToString();




            } catch (System.Exception e) {


                _text.GetComponent<UnityEngine.UI.Text>().text = e.ToString();


            }






            AndroidJavaObject toast = new AndroidJavaObject("android.widget.Toast",currentActivity);


            toast.CallStatic<AndroidJavaObject>("makeText",currentActivity,"good",(1)).Call("show");




        }));


    }  


We know this code is wrong, any suggestions? We're assuming it's in the AndroidJavaObject downloadManager line, but the request line could be wrong as well, and we seem to have no way to debug.


pseudoscience
Explorer
Bumping out of desperation?

kolor
Honored Guest
removed

RemiL
Explorer
I don't know if you're code is wrong or not, as I've don't really have the time to test it.. 
Have you try to use the download manager in a simple Android project first (without unity), to see what the code look like before implementing it in Unity ? It sometimes can help to find what you're missing.

TomG
Explorer

Hi There,

made this work by changing:

"DOWNLOAD_SERVICE" to "download"

CallStatic ("enqueue", request); to Call("enqueue", request);

Have you made any progress on this script? i would really like a robust script that allow you to set the filename, path and get some feedback on the download progress.

Thx Tom

Anonymous
Not applicable
It's actually not too hard to create a plugin for this. Open Android Studio, create a new project and then add a new module. In the module, create a new class:
package com.yourcompany.modulename;
import android.content.Context;
import android.app.DownloadManager;
import android.database.Cursor;
import android.net.Uri;
public class DownloadHelper
{
private Context mContext;
private DownloadManager manager;
public DownloadHelper(Context mContext) {
this.mContext = mContext;
}
private int downloadProgress;
public int GetDownloadProgress(long downloadId)
{
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = manager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
return (int) ((bytes_downloaded * 100L) / bytes_total);
}
public long StartDownload(String downloadUrl, String destination, String title)
{
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
request.setTitle(title);
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationUri(Uri.parse(destination));
manager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
return manager.enqueue(request);
}
public void CancelDownload(long downloadId)
{
manager.remove(downloadId);
}
}


Build -> Make Module 'modulename' -> Go to your output folder, modulename/build/outputs/aar/modulename-debug.aar -> Open with winrar or similar and extract classes.jar

Put classes.jar (You can rename it to DownloadHelper.jar or whatever) in your Unity projects Plugins/Android folder.

In Unity, you can use the plugin like this:

using UnityEngine;
using System.Collections;
public class AndroidDownloader : MonoBehaviour {

AndroidJavaObject downloadHelper;
private const string ACTIVITY_NAME = "com.unity3d.player.UnityPlayer";
private const string CONTEXT = "currentActivity";
private const string DOWNLOAD_HELPER = "com.yourcompany.modulename.DownloadHelper";

void Start()
{
AndroidJavaObject context = new AndroidJavaClass(ACTIVITY_NAME).GetStatic(CONTEXT);
downloadHelper = new AndroidJavaObject(DOWNLOAD_HELPER, context);
}

public long Download(string url, string destination, string title)
{
return downloadHelper.Call("StartDownload", url, "file://" + destination, title);
}

public int GetDownloadProgress(long downloadId)
{
if (downloadHelper != null)
{
return downloadHelper.Call("GetDownloadProgress", downloadId);
}
return 0;
}

public void CancelDownload(long downloadId)
{
downloadHelper.Call("CancelDownload", downloadId);
}
}


Edit: Sorry about the messy code, no matter what I do I can't seem to get the correct formatting on this forum.
Edit 2: Fixed! Seems the WYSIWYG editor adds in erroneous extras...

EgilSandfeld
Honored Guest
Thanks so much for the precious help, gconvergen!

I just had to adapt small things in your examples, as it would otherwise give me errors:

private Cursor cursor;

public int GetDownloadProgress(long downloadId)
{
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
cursor = manager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
cursor.close();
return (int) ((bytes_downloaded * 100L) / bytes_total);

}

and in the Unity C# code:

AndroidJavaObject context = new AndroidJavaClass(ACTIVITY_NAME).GetStatic<AndroidJavaObject>(CONTEXT);
downloadHelper = new AndroidJavaObject(DOWNLOAD_HELPER, context);

public long Download(string url, string destination, string title)
{
return downloadHelper.Call<long>("StartDownload", url, "file://" + destination, title);
}

public int GetDownloadProgress(long downloadId)
{
if (downloadHelper != null)
{
return downloadHelper.Call<int>("GetDownloadProgress", downloadId);
}
return 0;
}

public void CancelDownload(long downloadId)
{
downloadHelper.Call("CancelDownload", downloadId);
}