Device not caching addressable assets

Hi all,

I’m using Firebase to load addressable assets remotely, and that loading is working with no issues - however, I seem to be unable to get the device to cache the assets - it doesn’t seem to save anything to local storage, and every time I restart the app, it re-downloads the files. This is without updating or rebuilding the addressables in any way.

Everything I’ve read suggests that caching should happen automatically, but that’s not been the case for me with Android or StandaloneWindows64 builds.

Attached are pictures of my addressable group settings, AddressableAssetsSettings, and the CacheInitializationSettings I’ve added (have attempted this with and without the CacheInitializationSettings).

Any ideas would be much appreciated. Thanks in advance!

Group Settings:

AddressableAssetsSettings:

CacheInitializationSettings
5064155--497678--upload_2019-10-14_13-5-43.png

Does firebase change the URL in any way? AFAIK caching identifies bundles by checking the last ‘segment’ of the url.

Thanks for the reply! It does append a couple of query params, but as far as I can tell the values of those params remain constant per file - though it’s a promising lead.

I’m using the very helpful Firebase Storage with Addressables library from @robinryf : Storage/Addressables · master · RobinBird Studios / Libraries / Unity Plugins / Firebase Tools · GitLab

Having investigated that code myself, it looked like the decision for whether or not something should be cached happens before it reaches Firebase code, but I could be wrong there.

Can you show me an example of an endpoint?

Sure thing!

The actual download URL for the file is:

https://firebasestorage.googleapis.com/v0/b/accountname.appspot.com/o/addressables%2Fandroid%2Fbundlename.bundle?alt=media&token=11781671-8b9f-4262-87c2-778c68cc14f5

Where that token appears to be constant.

However, the RemoteLoadPath is configured as:

gs://accountname.appspot.com/Addressables/[BuildTarget]

so what it’s actually trying to resolve is something like:

gs://accountname.appspot.com/Addressables/Android/bundlename.bundle

Which is then converted by the selected FirebaseAssetBundleProvider into the proper HTTPS download URL above.

Ran some tests on this, it appears as long as the last segment of the url contains the last segment of assetbundle url that was passed in the previous time it should find it in cache. I can append and prepend bogus parameters to the last segment and it’ll still successfully find the bundle in cache. ’

So I think we can rule out the parameter part, if you’re sure the name of the last segment doesn’t change the next suspect would be that hash that’s passed in. I haven’t looked at the firebase implementation but I assume it just uses UnityWebrequest.GetAssetbundle after resolving the right url, which takes a hash and crc as parameters.

The way it’s implemented, once it knows the HTTPS download URL it creates a new ResourceLocationBase with that resolved URL, specifying AssetBundleProvider as the provider type - see line 42 here:

so in theory, the hash is calculated the same way as it usually is by “normal” remote asset bundles.

Can you verify loading assetbundles to cache outside of the addressables environment works as expected?

Just attach below script, this works on my end:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class AssetBundleDownloader : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Caching.ClearCache();
        StartCoroutine(DownloadBundle("https://s3-eu-west-1.amazonaws.com/nils.mysmilez.nl/Android/packedassets_assets_assets/vrworlds/loft/loftvr.prefab_2cf8877c87095e8687e16fe0d13d105f.bundle"));
    }

    // Update is called once per frame
    void Update()
    {
       
    }

    IEnumerator DownloadBundle(string link)
    {
        UnityWebRequest download = UnityWebRequestAssetBundle.GetAssetBundle(link + "?statictoken=123", Hash128.Parse("123456789"));

        download.SendWebRequest();

        while(!download.isDone)
        {
            Debug.Log(download.downloadProgress);
            yield return null;
        }

        if(!(download.isNetworkError || download.isHttpError))
        {
            Debug.Log("First download is done, this one should have taken quite a long time");
            //bundle should now be cached

            if(Caching.IsVersionCached(link  + "?statictoken=456&extraparam=hello", Hash128.Parse("123456789")))
            {
                UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle("https://s3-eu-west-1.amazonaws.com/beng.mysmilez.nl/content/loftvr.prefab_2cf8877c87095e8687e16fe0d13d105f.bundle" + "?statictoken=456", Hash128.Parse("123456789"));
                request.SendWebRequest();

                while(!request.isDone)
                {
                    Debug.Log(request.downloadProgress);
                    yield return null;
                }

                if(!(request.isNetworkError || request.isHttpError))
                {
                    Debug.Log("Second download is done, this one should have finished immediately");
                }
            }
               
            else
                Debug.LogError("bundle is not cached");
        }
    }
}

Trying that now. Thanks again for the support!

Can confirm, worked as expected - long first download, instant second.

Very strange, would have to set up a firebase account to help you further.

If you load it a second time in the same app run, does the cache persist?

Can you post the output of this function after loading a bundle via addressables Unity - Scripting API: Caching.GetCachedVersions?

  1. If I run it a second time, the cache seems to persist.
  2. Trying the https:// full URL, the gs:// URL, the name of the bundle with .bundle at the end and without, I wasn’t able to see any cached versions for any of those keys.

Additionally, I put breakpoints on all calls to Caching.* within the Addressables and Firebase Addressables packages, and none got any hits at all.

EDIT: I now see that AssetBundleProvider calls UnityWebRequestAssetBundle.GetAssetBundle, which eventually gets down to an extern DownloadHandlerAssetBundle.CreateCached_Injected, so presumably there’s some under-the-hood caching magic being attempted there.

I updated the Firebase Storage plugin with this PR: Resolve "Caching not working for Firebase-hosted Addressables" (!4) · Merge requests · RobinBird Studios / Libraries / Unity Plugins / Firebase Tools · GitLab
to also support caching. I missed to pass the Hash and CRC data onto the Unity related code. Could you please test and check if it works for you? In my tests it worked out fine :slight_smile:

Cheers,
Robin

1 Like

Perfect, thanks for reacting so quickly! I’m testing it out now and will let you know ASAP.

Can confirm, works great!

Hey @robinryf ,

I think I am having trouble getting the addressables from firebase to to the right spot. Unless I am missing something, should my addressables downloads be in the cache and not the data to initialize?

5592523--578050--Screenshot_20200315-171149_Settings.jpg

Since the Addressables Firebase Storage plugin uses normal Addressables APIs there is no custom saving location or something. Please check the Addressable documentation/settings for the save location. But, yes. I think it should be saved in the Cache. Although it would also be possible to be in Data which is not cleared by the OS when storage gets short.

You can use

Debug.Log($"Current cache: {Caching.defaultCache.path}");

var cachePaths = new List<string>();
Caching.GetAllCachePaths(cachePaths);
foreach (var cachePath in cachePaths)
{
     Debug.Log($"Cache path: {cachePath}");
}

To find out the caching paths on your system/OS/Device and check them with adb/itunes/etc.

1 Like

awesome thankz.

Hi everyone!

I’ve tried this package and that worked great for me. Caching works fine as well. The only thing I want to mention is the lost internet connection on the device (I use the catalog in addressables). In that case, the tool should use the local cache, but it doesn’t. I’ve tried to workaround that using the saved hash string (link below), but it’s not so simple and needs more time to understand how to modify the code. Any help?

Shared with Zight