Downloading Asset Bundle on Android and Saving to File

Just a little bit of background on this issue: I am trying to download an asset bundle from a server on android (Oculus Quest to be specific) and save that asset bundle as an OBB to the respective OBB folder for the application. Key piece of information: This asset bundle contains a bunch of 360 videos, and it seems that video is the only piece of media that Android has difficulties unpacking from a bundle.

Approaches that have not been successful:

I have tried the approach of using UnityWebRequest.Get() with a download handler to get the data, and then File.WriteAllBytes() to save the data and AssetBundle.LoadFromFile() to load the bundle. This works beautifully on PC in the editor, but causes the application to crash on the Quest due to what seem to be memory issues.

Trying a different approach, I used UnityWebRequestAssetBundle.GetAssetBundle() with a version identifier for caching, which again worked beautifully on PC in the editor, but could not load the videos on the Quest. This seems to be related to an issue with videos being loaded from the cache on Android rather than from a save location on the disk.

This led me to combine the two approaches based on research I did online to use UnityWebRequestAssetBundle.GetAssetBundle() to download the asset bundle, and AssetBundle.LoadFromFile() pointing to the folder that the bundle was cached in. Unsurprisingly, this returned the same error as before relating to the bundle / videos being cached rather than saved to storage.

This brings me to my question: Is there actually a way to download an asset bundle containing video files, save them to storage on Android (preferably in the OBB folder), and load the videos for playback in an app?

Below is a small sample of what I have been working with:

loadingScreen.SetActive(true);
		webRequest = UnityWebRequestAssetBundle.GetAssetBundle(downloadURL, 1, 0);
		webRequest.SendWebRequest();

		while (webRequest.downloadProgress < 1.0f)
		{
			loadingSlider.value = webRequest.downloadProgress;
			yield return null;
		}

		if (webRequest.isNetworkError || webRequest.isHttpError)
		{
			Debug.Log($"Error thrown while communicating with server: {webRequest.error}");
		}
		else
		{
			Debug.Log("Download successful, hiding UI and playing next clip");

			loadingScreen.SetActive(false);

			if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor)
			{
				myLoadedAssetBundle = DownloadHandlerAssetBundle.GetContent(webRequest);
			}
			else if (Application.platform == RuntimePlatform.Android)
			{
				myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.persistentDataPath, androidBundleFileName));
			}

			PlayNextClip();
		}

Hola, mira soy muy nuevo en la programación de juegos, pero seguro te puedo ayudar: Si programas que hayan comportamientos diferentes al trabajar en Windows o Android, seguramente puede ocurrir que te funcione en uno y no en el otro. Por ello te recomiendo no hacerlo. Mira, tomé tu código y le hice unos pequeños arreglos para poder usarlo, a la función solo debes llamarla con la URL de descarga como la variable WWW y el nombre del prefabricado como Name. Haciendo eso, seguro te funcionará.

using System.Collections;
using UnityEngine.Networking;
using System;
using UnityEngine;
using UnityEngine.UI;



// https://drive.google.com/uc?id=XXXXAquíVaElIdentificadorXXXXX&export=download&authuser=0

public class DescargarMaterialNecesario : MonoBehaviour
{
    public string BundleURL;
    public string NombreDelMódulo;

    public Slider loadingSlider;
    public GameObject loadingScreen;

    public Text MensajeTexto;

    public GameObject PrefatAsset;
    public AssetBundle BundleAsset;
    public AssetBundleRequest request;


    private UnityWebRequest webRequest;
    private void Start()
    {
        loadingScreen.SetActive(false);
    }

    public void DescargarEscenas( )
    {
        BundleURL = "https://drive.google.com/uc?export=download&id=1iomecdt9VG0KvDc_qeS_GepHcqe8oV5j";
        NombreDelMódulo = "F_Obj Sistema de Biblioteca";
        StartCoroutine(DownloadAndCache(BundleURL, NombreDelMódulo));

    }

    public IEnumerator DownloadAndCache(String WWW, String Name) {
        // Activamos la pestaña de carga
        loadingScreen.SetActive(true);
        /*Hacemos la solicitud, enviamos la página URL guardada 
        como "WWW", la versión que es la "1" y la entrada de sistem32 "0"*/
        webRequest = UnityWebRequestAssetBundle.GetAssetBundle(WWW, 1, 0);
        //Solicitamos que nos envíen el asset
        webRequest.SendWebRequest();

        //Mientras se descarga el Asset, miramos el avance en nuestra LoadingSlider
        while (webRequest.downloadProgress <= 0.99f)
        {
            loadingSlider.value = webRequest.downloadProgress;
            yield return null;
        }

        //Notificamos si hubo algún error, y si no lo hubo, pasamos adelante
        if (webRequest.isNetworkError || webRequest.isHttpError)
        {
            MensajeTexto.text = "Error al descargarlo";
        }
        // Si ni tenemos error alguno, escribimos que ya lo tenemos listo
        else
        {   //Mandamos mensaje al usuario diciendo que ya lo tenemos
            MensajeTexto.text = "Ya lo tenemos descargado!!!";
            
            
            //Identificamos si estamos en Windows o Android
            if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor)
            {
                //Cargamos el Asset
                BundleAsset = DownloadHandlerAssetBundle.GetContent(webRequest);
                MensajeTexto.text = "Compilando para Windows";
            }
            if (Application.platform == RuntimePlatform.Android)
            {
                //Cargamos el Asset
                BundleAsset = DownloadHandlerAssetBundle.GetContent(webRequest);
                MensajeTexto.text = "Compilando para Android";

            }

            // Convertimos nuestro asset Bundle en una request
            request = BundleAsset.LoadAssetAsync<GameObject>(Name);
            // Convertimos nuestra request en un prefat
            PrefatAsset = request.asset as GameObject;
            // Instanciamos el prefat
            Instantiate(PrefatAsset);

            //Desactivamos la pantalla de carga
            loadingScreen.SetActive(false);

        }
    }

}

Lo único que debes hacer, es llamar la función, ponerle tu link y el nombre de tu asset.
Un abrazo

Kent_Engel

Espero que a alguien más le pueda servir… me tomó muchos días tener el código.