DownloadFileAsync on Android in Unity with Mono: NullReferenceException in WebRequestPrefixElement..ctor?

Viewed 114

I'm trying to download something with WebClient and DownloadFileAsync in the Unity3D engine and it works on Desktop, I think on iPhone as well but it fails to do so on Android.

Basically this is what I do:

using (var client = new WebClient())
{
     client.DownloadFileAsync(new Uri(url), path);
}

And this is the exception I get on my Android 12, Google Pixel 4a phone:

System.Net.WebException: An exception occurred during a WebClient request. ---> System.NullReferenceException: Object reference not set to an instance of an object
08-18 18:12:20.138 26647 26666 I Unity   :   at System.Net.WebRequestPrefixElement..ctor (System.String P, System.Type creatorType) [0x00018] in <8bb5d2547dc749eeb8bd52a9eb3b67d1>:0
08-18 18:12:20.138 26647 26666 I Unity   :   at System.Net.WebRequest.PopulatePrefixList () [0x00040] in <8bb5d2547dc749eeb8bd52a9eb3b67d1>:0
08-18 18:12:20.138 26647 26666 I Unity   :   at System.Net.WebRequest.get_PrefixList () [0x00022] in <8bb5d2547dc749eeb8bd52a9eb3b67d1>:0
08-18 18:12:20.138 26647 26666 I Unity   :   at System.Net.WebRequest.Create (System.Uri requestUri, System.Boolean useUriBase) [0x0002e] in <8bb5d2547dc749eeb8bd52a9eb3b67d1>:0
08-18 18:12:20.138 26647 26666 I Unity   :   at System.Net.WebRequest.Create (System.Uri requestUri) [0x00014] in <8bb5d2547dc749eeb8bd52a9eb3b67d1>:0
08-18 18:12:20.138 26647 26666 I Unity   :   at System.Net.WebClient.GetWebRequest (System.Uri address) [0x00000] in <8bb5d2547dc749eeb8bd52a9eb3b67d1>:0
08-18 18:12:20.138 26647 26666 I Unity   :   at System.Net.WebClient.DownloadFileAsync (System.Uri address, System.String fileName, System.Object userToken) [0x00032] in <8bb5d2547dc749eeb8bd52a9eb3b67d1>

Could you help me investigating? Thanks!

UPDATE:

This only seems to happen with Mono scripting backend. Now it works once I switched to IL2CPP and checked the ARM64 checkbox due to Unity's suggestion.

2 Answers

You're using a using block which will call .Dispose() when exited. In the documentation for WebClient.DownloadFileAsync it states the following:

Downloads, to a local file, the resource with the specified URI. This method does not block the calling thread.

This means you have a race condition and it's entirely possible that your WebClient object is being disposed before DownloadFileAsync gets a chance to do what it needs to do.

There's no indication in your post whether this code is executing in a coroutine, a synchronous function, or a task but you should either use DownloadFile which isn't async and will therefore block the thread and allow you to keep your using block or you can use the DownloadFileCompleted event to keep it async, get rid of the using block, and manually dispose the client when it's done.

I'll also add that, since you're using Unity, you might want to 1) look into using UnityWebRequest as it's a bit more simplified API and 2) switch to building with IL2CPP.

Try with something like this:

void DownloadFile()
{
    WebClient client = new WebClient();
    client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler( DownloadFileCompleted );
    client.DownloadFileAsync ((new Uri (url, path));
}

void DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
    if (e.Error == null)
    {
        //Nice!
    }
}

Also if you can specify in your question which is your URL and Path,maybe the error is there, be sure they are consistent across OS, so your path is something like: Application.persistentDataPath + "/" + "file.extension"

Related