- Home /
The question is answered, right answer was accepted
Write Downloaded AssetBundle to Local Storage
Hello! I am attempting something I haven't seen on the forum or answers before...
I want to be able to upload assetbundles to my server and players be able to download and use them... easy enough. However, since it is a mobile game, I am trying to make it so that after you download it once, it saves it to Application.persistantDataPath/bundles
so that I can load from there instead... I can make it detect if the bundle is downloaded or not, and pull from the right locations, I just can't figure out how to make it copy the downloaded bundle...
I'd love any input you guys have... I'm using UnityScript.
Thanks!
Answer by Graham-Dunnett · Apr 12, 2013 at 10:20 PM
See: http://docs.unity3d.com/Documentation/Manual/iphone-Downloadable-Content.html
This is an iOS documentation page, but the same approach should work for other mobile devices.
Answer by TobyKaos · Jul 07, 2015 at 08:26 AM
Not a good idea: Unity do it for you and store assetbundles in a cache location.
use: WWW.LoadFromCacheOrDownload (url, version)
You MUST maintains a bundle version. For instance you add in your ftp a text file with the version number of your assetBundles. When you update an assetbundle and save it on your ftp, then increase your assetbundle version in those text file.
When you use LoadFromCacheOrDownload then you replace version parameter by yours. And unity will donwload it if version is greater than the last downloaded.
In this way you do not have to deal with copy in a particular folder.
Look at this unity doc: http://docs.unity3d.com/Manual/keepingtrackofloadedassetbundles.html
You will find a AssetBundleManager sample code. I use it.
hi, the link is no longer available. and it seems that I can't even load my assetbundles using the recommended WWW.LoadFromCacheOrDownload (url, version).
using UnityWebRequest, I'm able to load the bundles and was able to check if it is cached by using CAching.IsVersionCached, however, I have no idea where to retreived this 'cached' version of the bundle....seriously... I am running around in circles...
seems like the only solution i have right now is to save it to local...which is not recommended.
Answer by JotaRata · Jul 07, 2015 at 07:27 AM
You can use System.IO.File.WriteAllBytes()
using System.IO;
(...)
public string url = "myweb.com/myAsset";
public string saveTo = "/folder/myAsset";
public bool alreadyDownloaded = false;
IEnumerator SaveAndDownload(){
WWW www = new WWW(url)
yield return www;
byte[] bytes = www.bytes;
File.WriteAllBytes(saveTo,bytes);
}
and you're ready
Answer by SAEM2710 · Jul 07, 2015 at 12:11 PM
And what's about a dlc ? If the user cleans the cache or if the cache is too small to store the asset bundle ? If the user doesn't know how to cleans the cache ?
I'm looking for the same idea : put my assetbundle on a webserver and then my application can download it and copy inside the internal memory of my device.
Well I put my code here, it works perfectly on my pc but on Android I always got the same and boring error "Asset Bundle header is too small". Indeed the file is created internally but it isn't filled with the data.
I've been looking for many problems and solutions : - Version of Android : Kitkat 4.4 prohibits writing, so I have upgraded my version - Assetbundle which is compressed while AssetBundle.CreateFromFile needs an uncompressed assetbundle, so I have made an uncompressed bundle - Assetbundle is different according to platforms, so I have made an assetbundle for Android (+uncompressed as well) - And now I'm looking for C# managed array (byte array here) can't be interpreted by Android ?
Here is the code :
public GameObject cible;
public Scrollbar progressbar;
public Text displayedtext;
public GameObject progress;
static WWW objSERVER;
static string pathURL;
static string pathLOCAL;
//IEnumerator allows yield so the information is not accessed
//before it finished downloading
IEnumerator Start ()
{
pathURL = "www.mywebsite.net/file"; //location of the file on the server
pathLOCAL = Application.persistentDataPath + "/../assetbundles/"+"test" +".unity3d"; //location of the file on the device
objSERVER = new WWW(pathURL);
// Wait for download to finish
yield return objSERVER;
// Save it to disk
SaveDownloadedAsset(objSERVER);
Debug.Log ("------------------- HERE THE PATH -------------------" + "\n" + Application.persistentDataPath);
AssetBundle objLOCAL = AssetBundle.CreateFromFile (pathLOCAL);
yield return objLOCAL;
// Instantiate the asset bundle
GameObject Model3D = Instantiate (objLOCAL.mainAsset) as GameObject;
// Parenting
Model3D.transform.parent = cible.transform;
// Positioning
Model3D.transform.localPosition = new Vector3 (0.62f, -0.98f, 0.94f);
// Resize it
Model3D.transform.localScale = new Vector3 (0.10f, 0.10f, 0.10f);
objLOCAL.Unload (false);
}
public void SaveDownloadedAsset(WWW objSERVER)
{
// Create the directory if it doesn't already exist
if (!Directory.Exists(Application.persistentDataPath + "/../assetbundles/"))
{
Directory.CreateDirectory(Application.persistentDataPath + "/../assetbundles/");
}
// Initialize the byte string
byte[] bytes = objSERVER.bytes;
// Creates a new file, writes the specified byte array to the file, and then closes the file.
// If the target file already exists, it is overwritten.
File.WriteAllBytes(pathLOCAL, bytes);
}
}
DLC change nothing. If user bought it and clean cache, then unity will download it again.
Your bug seems to be plateform specific. You must create Android AssetBundles to.
For instance in an editor script
[$$anonymous$$enuItem("Resources/AssetsBundles/Build Asset Bundles/Android")]
static void BuildAndroid ()
{
Build (BuildTarget.Android, "AssetBundles/Android");
}
// Build specific target
static void Build(BuildTarget target, string path)
{
BuildPipeline.BuildAssetBundles(path,
BuildAssetBundleOptions.None,
target);
}
I'm using Unity 4.6.5f1, and that's the way how I create my asset bundle :
[$$anonymous$$enuItem("Assets/Build AssetBundle From Selection - No dependency tracking")]
static void ExportResourceNoTrack ()
{
// Bring up save panel
string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
if (path.Length != 0)
{
// Build the resource file from the active selection.
BuildPipeline.BuildAssetBundle(Selection.activeObject, Selection.objects, path, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.Android);
}
}
This is the same technique that you've suggested to me, isn't it ?
Otherwise, http://docs.unity3d.com/$$anonymous$$anual/abfaq.html here we can see that a bundle created while the Android build target was active would be compatible with the editor and with apps built for Android platforms. That's what I've made and this perfectly works on editor but not on Android ? Why ? I'm trying to resolve this problem for couple of days now. Thanks
Yes I am using Unity 5.x. But seems to be same process (more easy on 5)
What contains Selection ?
Do you set your editor plateforme to Android? As this you can test Android assetBundles in Editor.
Can't use Unity 5.x because it's not compatible with Vuforia
$$anonymous$$y editor plateform is set to Android and Selection contains the active object on which I click on the editor to package it
What error have you got on Android? Can you launch eclipse to retrieve logcat. (or command line)