I'm working on an iOS app on Unity. Eventually, the app should be able to download, import and load .obj files saved on my website server. But I'm currently developing locally so the files are saved in my laptop file system (local server side of my website).
My question is what I should use to access those files. I used WWW to access it but it seems not working. Please see my code below.
public void OnClick()
{
StartCoroutine(ImportObject());
}
IEnumerator ImportObject (){
Debug.Log("being called");
WWW www = new WWW("http://localhost:8080/src/server/uploads/user-id/file name");
Debug.Log("being called");
yield return www;
Debug.Log("NOT BEING CALLED !");
**//Everything below here seems not being called...**
if (string.IsNullOrEmpty(www.error)) {
Debug.Log("Download Error");
} else {
string write_path = Application.dataPath + "/Objects/";
System.IO.File.WriteAllBytes(write_path, www.bytes);
Debug.Log("Success!");
}
GameObject spawnedPrefab;
Mesh importedMesh = objImporter.ImportFile(Application.dataPath + "/Objects/");
spawnedPrefab = Instantiate(emptyPrefabWithMeshRenderer);
spawnedPrefab.transform.position = new Vector3(0, 0, 0);
spawnedPrefab.GetComponent<MeshFilter>().mesh = importedMesh;
}
I tried multiple solutions from the internet and finally find the correct method to download and save the file by using the code below:
IEnumerator DownloadFile(string url) {
var docName = url.Split('/').Last();
var uwr = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET);
string modelSavePath = Path.Combine(Application.dataPath, "Objects");
modelSavePath = Path.Combine(modelSavePath, docName);
//Create Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(modelSavePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(modelSavePath));
}
var dh = new DownloadHandlerFile(modelSavePath);
dh.removeFileOnAbort = true;
uwr.downloadHandler = dh;
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
Debug.LogError(uwr.error);
else
Debug.Log("File successfully downloaded and saved to " + modelSavePath);
}
Related
I'm using ASP.NET 4.6 MVC. I'm saving an xml file as a byte array in my SQL db. I want to allow my user to download the file from the browser. I'm not getting any errors and no file is getting downloaded. I know there are plenty of these issues out there but I haven't seen one where a file isn't being downloaded (not even a corrupted one).
public ActionResult DownloadScript(int id) {
try {
var script = _db.PortalScripts.FirstOrDefault(i = >i.Id == id);
if (script != null) {
return File(script.ScriptBytes, "text/xml", script.Name);
}
}
catch(Exception e) {
FlashMessage.Danger("Error downloading script");
}
return RedirectToAction("Scripts");
}
[HttpPost]
public ActionResult UploadScript(HttpPostedFileBase file) {
try {
if (file.ContentLength > 0) {
var newScript = new PortalScript {
Name = Path.GetFileName(file.FileName),
Version = "190.161",
Description = "This is a placeholder",
Displayed = true
};
using(MemoryStream ms = new MemoryStream()) {
file.InputStream.CopyTo(ms);
newScript.ScriptBytes = ms.ToArray();
}
var existingScripts = _db.PortalScripts.FirstOrDefault(s = >s.ScriptBytes == newScript.ScriptBytes);
if (existingScripts == null) {
_db.PortalScripts.AddOrUpdate(newScript);
_db.SaveChanges();
FlashMessage.Confirmation(newScript.Name + " successfully uploaded");
}
else FlashMessage.Warning(newScript.Name + " already exists. Duplicate upload ignored.");
}
}
catch(Exception ex) {
FlashMessage.Danger("Upload failed: " + ex.Message);
}
return RedirectToAction("Scripts");
}
In my download method, my script variable is returning a properly filled out model. Not going into the catch either. Just getting redirected back to my original view with no file. Any suggestions??
I am downloading assetBundle from server using UnityWebRequest and it is working good in unity editor but in andriod it gives null value can someone help
public IEnumerator DownloadAsset(string url, string assetName)
{
using (UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(url))
{
yield return www.SendWebRequest();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
if (bundle != null)
{
AGUIMisc.ShowToast("Not Null");
GameObject temp = bundle.LoadAsset(assetName) as GameObject;
var newobjj = Instantiate(temp);
newobjj.transform.parent = maleparent.transform;
}
else
{
AGUIMisc.ShowToast("Null");
}
}
}
Target-platform Android:
The AssetBundles need to be built in the target-platform where they are going to be used at later.
Since you want to use the AssetBundles in Android, the target-platform should also be Android when you build your AssetBundles.
Please also check:
You should set UnityWebRequest.downloadHandler first before call UnityWebRequest.SendWebRequest() to use DownloadHandlerAssetBundle.
public System.Collections.IEnumerator DownloadAsset(string url, string assetName)
{
using (var uwr = new UnityEngine.Networking.UnityWebRequest(url, UnityEngine.Networking.UnityWebRequest.kHttpVerbGET))
{
uwr.downloadHandler = new UnityEngine.Networking.DownloadHandlerAssetBundle(url, 0);
yield return uwr.SendWebRequest();
AssetBundle bundle = UnityEngine.Networking.DownloadHandlerAssetBundle.GetContent(uwr);
if (bundle != null)
{
AGUIMisc.ShowToast("Not Null");
GameObject temp = bundle.LoadAsset<GameObject>(assetName);
var newobj = GameObject.Instantiate(temp);
newobj.transform.parent = maleparent.transform;
}
else
{
AGUIMisc.ShowToast("Null");
}
}
}
I connect to Firebase from Unity, and get simple image from it. But I want to know how can I save this image for example in Assets folder of unity project?
void Start()
{
FirebaseStorage storage = FirebaseStorage.DefaultInstance;
Firebase.Storage.StorageReference path_reference = storage.GetReference("background/1.jpg")
"SavetoAssets = storage.GetReference("background/1.jpg")" // something like that.
}
This post is almost what you need. I just expanded it with the FileIO part using FileStream.WriteAsync and used UnityWebRequestTexture instead of WWW:
private void Start()
{
FirebaseStorage storage = FirebaseStorage.DefaultInstance;
Firebase.Storage.StorageReference path_reference = storage.GetReference("background/1.jpg");
path_reference.GetValueAsync().ContinueWith(
task =>
{
Debug.Log("Default Instance entered");
if (task.IsFaulted)
{
Debug.Log("Error retrieving data from server");
}
else if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
string data_URL = snapshot.GetValue(true).ToString();
//Start coroutine to download image
StartCoroutine(DownloadImage(data_URL));
}
}
);
}
private IEnumerator DownloadImage(string url)
{
using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url))
{
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
Debug.Log(uwr.error);
}
else
{
// Instead of accessing the texture
//var texture = DownloadHandlerTexture.GetContent(uwr);
// you can directly get the bytes
var bytes = DownloadHandlerTexture.GetData(uwr);
// and write them to File e.g. using
using (FileStream fileStream = File.Open(filename, FileMode.OpenOrCreate))
{
fileStream.WriteAsync(bytes, 0, bytes.Length);
}
}
}
}
Note: I don't use Firebase, Android nor iOs so I couldn't test this
I'm trying to Load AssetBunddle form Android Folder from in Unity.
but it doesn't work...
I thought URL is wrong.
Changed URL many time, recommended or specification of Unity document but every case failed
Here is My Code.
public string BundleURL;
public int version;
void Start()
{
CleanCache();
BundleURL = "file://"+Application.persistentDataPath + " /BundleTest";
StartCoroutine(LoadAssetBundle(BundleURL));
version = 0;
}
I thought BundleURL is wrong or has problem
IEnumerator LoadAssetBundle(string BundleURL)
{
//BundleURL = "file://" + path ;
GameObject obj;
//ARLog.d ("LoadAssetBundle" + BundleURL);
while (!Caching.ready)
yield return null;
using (WWW www = WWW.LoadFromCacheOrDownload(BundleURL, version))
{
yield return www;
AssetBundle bundle = www.assetBundle;
String[] mPath = bundle.GetAllAssetNames();
String bundleName = null;
if (bundleName != null)
{
AssetBundleRequest request = bundle.LoadAssetAsync(bundleName, typeof(GameObject));
yield return request;
obj = Instantiate(request.asset) as GameObject;
bundle.Unload(false);
www.Dispose();
}
}
}
}
I want Instance Model in my Scene(from BundelTest Folder in Androind)
You have an additional space there in
BundleURL = "file://"+Application.persistentDataPath + " /BundleTest";
in " /BundleTest"!
For paths in general you allways rather should use Path.Combine instead of manually concatenating strings:
BundleURL = Path.Combine(Application.persistentDataPath,"BundleTest");
this makes sure that in the resulting path automatically the correct path separator (/ or \) for the according atrget system is used.
Than note that WWW is obsolete and not that fast → you should have a look at AssetBundle.LoadFromFileAsync there is an example of how to use it
public void IEnumerator LoadBundle()
{
var bundleLoadRequest = AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, "BundleTest"));
yield return bundleLoadRequest;
var myLoadedAssetBundle = bundleLoadRequest.assetBundle;
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
yield break;
}
var assetLoadRequest = myLoadedAssetBundle.LoadAssetAsync<GameObject>("MyObject");
yield return assetLoadRequest;
GameObject prefab = assetLoadRequest.asset as GameObject;
Instantiate(prefab);
myLoadedAssetBundle.Unload(false);
}
If you prefer synchronous loading checkout AssetBundle.LoadFromFile instead.
Another note in general: if you are using
using (WWW www = WWW.LoadFromCacheOrDownload(BundleURL, version))
{
....
}
you don't have to use Dispose as it is disposed at the and of the using block automatically.
This question already has an answer here:
You are using download over http. Currently Unity adds NSAllowsArbitraryLoads to Info.plist to simplify transition
(1 answer)
Closed 4 years ago.
I am uploading data to database using WWW.
I have two data classes for data object.
[Serializable]
public class pushdatawrapper{
public string email;
public pushdata[] shotsArray=new pushdata[1];
}
[Serializable]
public class pushdata{
public string timehappened;
public string clubtype;
public pushdata(string timestamp_,string clubtype_)
{
timehappened = timestamp_;
clubtype = clubtype_;
}
}
Loading Json array of data object to database, I tried two approaches.
The first one was ok, but the second one is always failed at calling StartCoroutine function.
First approach
public class BLEBridge : MonoBehaviour {
void Start () {
pushdata_ pdata = new pushdata_("123123123123.0","15","123.0","123.0", "123.0", "123.0","123.0", "123.0","123.0","123.0","123.0","123.0", "First");
pushdatawrapper_ pw = new pushdatawrapper_ ();
pw.email = "test#gmail.com";
pw.shotsArray[0] = pdata;
StartCoroutine (PushData_ (pw));
}
private IEnumerator PushData_(pushdatawrapper_ pdata){
WWW www;
Hashtable postHeader = new Hashtable();
postHeader.Add("Content-Type", "application/json");
string dataToJason = JsonUtility.ToJson(pdata);
Debug.Log ("dataToJason " + dataToJason);
// convert json string to byte
var formData = System.Text.Encoding.UTF8.GetBytes(dataToJason);
www = new WWW("http://rmotion.rapsodo.com/api/push/new", formData, postHeader);
StartCoroutine(WaitForRequest(www));
return www;
}
IEnumerator WaitForRequest(WWW data)
{
yield return data; // Wait until the download is done
if (data.error != null)
{
Debug.Log("There was an error sending request: " + data.text);
}
else
{
Debug.Log("WWW Request: " + data.text);
}
}
}
This first method is always ok.
But in actual implementation, I need to upload data from a static function. Those private IEnumerator PushData_(pushdatawrapper_ pdata) and IEnumerator WaitForRequest(WWW data) can't be static.
So what I did was
I made a separate class as
public class UploadData: MonoBehaviour{
public void uploadindividualshot(pushdatawrapper pw){
StartCoroutine (PushData (pw));
}
private IEnumerator PushData(pushdatawrapper pdata){
WWW www;
Hashtable postHeader = new Hashtable();
postHeader.Add("Content-Type", "application/json");
string dataToJason = JsonUtility.ToJson(pdata);
Debug.Log ("dataToJason " + dataToJason);
// convert json string to byte
var formData = System.Text.Encoding.UTF8.GetBytes(dataToJason);
Debug.Log ("before www ");
www = new WWW("http://rmotion.rapsodo.com/api/push/new", formData, postHeader);
Debug.Log ("after new ");
StartCoroutine(WaitForRequest(www));
Debug.Log ("after WaitForRequest ");
return www;
}
IEnumerator WaitForRequest(WWW data)
{
Debug.Log ("start pushing ");
yield return data; // Wait until the download is done
if (data.error != null)
{
Debug.Log("There was an error sending request: " + data.text);
}
else
{
Debug.Log("WWW Request: " + data.text);
}
}
}
Then call the instance of the class from static method as
public class BLEBridge : MonoBehaviour {
void Start(){}
public unsafe static void GetGolfREsult()
{
pushdata pdata = new pushdata("123123123123.0","15","123.0","123.0", "123.0", "123.0","123.0", "123.0","123.0","123.0","123.0","123.0", "First");
pushdatawrapper pw = new pushdatawrapper();
pw.email = Login.loginName;
pw.shotsArray[0] = pdata;
UploadData up = new UploadData ();
up.uploadindividualshot (pw);
}
}
I always have error as
after new
UploadData:PushData(pushdatawrapper)
BLEBridge:GetGolfREsult()
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/DebugBindings.gen.cpp Line: 51)
libc++abi.dylib: terminating with uncaught exception of type Il2CppExceptionWrapper
2018-04-29 17:25:25.565292+0800 RMotion[270:7241] You are using download over http. Currently Unity adds NSAllowsArbitraryLoads to Info.plist to simplify transition, but it will be removed soon. Please consider updating to https.
The program has error at StartCoroutine(WaitForRequest(www));
What is wrong with second approach?
In unity calling this line of code automatically start http request
WWW www = new WWW("url");
yield is just the convenience way to tell the coroutine to wait for the process to finish. Don't separate your calls in 2 IEnumerator.
private IEnumerator PushData_(pushdatawrapper_ pdata){
WWW www;
Hashtable postHeader = new Hashtable();
postHeader.Add("Content-Type", "application/json");
string dataToJason = JsonUtility.ToJson(pdata);
Debug.Log ("dataToJason " + dataToJason);
// convert json string to byte
var formData = System.Text.Encoding.UTF8.GetBytes(dataToJason);
www = new WWW("http://rmotion.rapsodo.com/api/push/new", formData, postHeader)
Debug.Log ("start pushing ");
yield return www; // Wait until the download is done
if (www.error != null)
{
Debug.Log("There was an error sending request: " + www.text);
}
else
{
Debug.Log("WWW Request: " + www.text);
}
}
And I don't see any use of pointer in your static method so why did you use the unsafe keyword?