Search code examples
c#unity-game-engine

Get file/AssetBundle size from http request before downloading file


Question:

I want to get the size of assetBundle before finishing download the file. And I can show the remaining time to user. In Unity2018.2 , can we get the file size or downloaded file size that let me multiply by progress? Or there is other ways to calculate the remaining time?

I know WWW.responseHeaders contain the information, but it seems need to finish downloading.

Here is my code currently.

    using (WWW downloadPackageWWW = new WWW(pkg.url))
    {
        while (!downloadPackageWWW.isDone)
        {
            print("progress: " + downloadPackageWWW.progress * 100 + "%");    
            yield return null;
        }

        if (downloadPackageWWW.error != null)
            print("WWW download had an error:" + downloadPackageWWW.error);
        if (downloadPackageWWW.responseHeaders.Count > 0) 
            print(pkg.fileName + ": " + downloadPackageWWW.responseHeaders["Content-Length"]+" byte");

        byte[] bytes = downloadPackageWWW.bytes;
        File.WriteAllBytes(pkgPath, bytes);

    }

--

Update:

To get the remaining time, I come up a ideal that calculate by Time.deltaTime, and we don't need to know the total file size and download speed.

float lastProgress = 0;
while (!www.isDone)
{  
     float deltaProgress = www.progress - lastProgress;
     float progressPerSec = deltaProgress / Time.deltaTime;
     float remaingTime = (1 - www.progress) / progressPerSec;
     print("Remaining: " + remaingTime + " sec"); 
     lastProgress = www.progress;
     yield return null;
}

Solution

  • You should be using Unity's UnityWebRequest API to make we requests. In your current Unity version the WWW API is now implemented on top of UnityWebRequest under the hood but it's still lacking many features.

    You can get the size of your file without downloading or waiting for it to finish downloading in two ways:

    1.Make a HEAD request with UnityWebRequest.Head. You can then use UnityWebRequest.GetResponseHeader("Content-Length") to get the size of the data.

    IEnumerator GetFileSize(string url, Action<long> resut)
    {
        UnityWebRequest uwr = UnityWebRequest.Head(url);
        yield return uwr.SendWebRequest();
        string size = uwr.GetResponseHeader("Content-Length");
    
        if (uwr.isNetworkError || uwr.isHttpError)
        {
            Debug.Log("Error While Getting Length: " + uwr.error);
            if (resut != null)
                resut(-1);
        }
        else
        {
            if (resut != null)
                resut(Convert.ToInt64(size));
        }
    }
    

    Usage:

    void Start()
    {
        string url = "http://ipv4.download.thinkbroadband.com/5MB.zip";
        StartCoroutine(GetFileSize(url,
        (size) =>
        {
            Debug.Log("File Size: " + size);
        }));
    }
    

    2. Another option is to use UnityWebRequest with DownloadHandlerScript then override the void ReceiveContentLength(int contentLength) function. Once you call the SendWebRequest function, The ReceiveContentLength function should give you the download size in the contentLength parameter. You should then abort the UnityWebRequest request. Here is one example on how to use DownloadHandlerScript.

    I would go with the first solution since it's simpler, easier and requires less resources to work.