Silvering Silvering - 1 month ago 7
C# Question

Load file downloaded iOS app created in Unity

I'm trying to load a json file downloaded and saved in the persistentDataPath of an iOS device. The download and save works great. However I think I have big issues to load the file. In fact when I try to compile the project in Xcode I have some errors messages.

First here is my C# code :

using UnityEngine;
using System.Collections;
using System.IO;
using System.Net;
using UnityEngine.UI;

public class ReadJson : MonoBehaviour
{
public Text City;
public Text Temperature;
public Image Weather;
public Text WeatherUrl;

[System.Serializable]
public class CityInfo
{
public string name;
}

[System.Serializable]
public class CurrentCondition
{
public string date;
public string hour;
public int tmp;
public int wnd_spd;
public int wnd_gust;
public string wnd_dir;
public double pressure;
public int humidity;
public string condition;
public string icon;
public string icon_big;
}

[System.Serializable]
public class RootObject
{
public CityInfo city_info;
public CurrentCondition current_condition;
}

void Start () {

WebClient client = new WebClient();
File.Delete(Path.Combine (Application.persistentDataPath, "myjson.json"));
client.DownloadFile ("http://www.myjsonurl", Path.Combine (Application.persistentDataPath, "myjson.json"));

TextAsset asset = Resources.Load (Path.Combine (Application.dataPath + "/Documents", "myjson")) as TextAsset;

RootObject m = JsonUtility.FromJson<RootObject> (asset.text);

City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();

}
}


And now the xcode console :

2016-10-21 17:01:20.766001 json[1404:516674] [DYMTLInitPlatform] platform initialization successful

2016-10-21 17:01:20.929950 json[1404:516508] -> registered mono modules 0xb95f70
2016-10-21 17:01:21.356590 json[1404:516508] You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist.
-> applicationDidFinishLaunching()
2016-10-21 17:01:21.452967 json[1404:516508] Metal GPU Frame Capture Enabled
2016-10-21 17:01:21.453369 json[1404:516508] Metal API Validation Enabled
-> applicationDidBecomeActive()
Init: screen size 750x1334
Initializing Metal device caps
Initialize engine version: 5.3.4f1 (fdbb5133b820)
UnloadTime: 1.705875 ms
Salut/var/mobile/Containers/Data/Application/51A2490E-94EB-4904-9F2E-112AD5632A98/Documents

(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)

NullReferenceException: A null value was found where an object instance was required.


(Filename: currently not available on il2cpp Line: -1)

Setting up 1 worker threads for Enlighten.
Thread -> id: 19f17000 -> priority: 1


If someone has an idea. Thanks a lot in advance.

Answer

The problem with your code is on this line:

TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;

I don't think you understand how and when to use Resources.Load. If you want to use the Resources.Load function, you must create a special folder from the Editor. This folder should be at <ProjectDirectory>/Assets/Resources. You can only put/write stuff into this folder from the Editor. You can't do it after build on iOS. It becomes read only after you build it. This special folder can then be read with the Resources.Load function.

Replacing:

TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;

with

string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));
RootObject m = JsonUtility.FromJson<RootObject>(text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();

Should solve your problem.

Another API that should not be using is WebClient. Unless you have a good reason to use that, you shouldn't. You should either use the WWW or UnityWebRequest(newer and recommended) API.

This is what your code should look like without WebClient:

void Start()
{
    StartCoroutine(DownloadAndloadJson());
}

IEnumerator DownloadAndloadJson()
{
    string url = "http://www.myjsonurl";

    UnityWebRequest www = UnityWebRequest.Get(url);
    yield return www.Send();

    if (www.isError)
    {
        Debug.Log(www.error);
    }
    else
    {
        //Sucessfully downloaded the Json File
        Debug.Log("Json: " + www.downloadHandler.text);

        string jsonFile = www.downloadHandler.text;

        //Delete old json file. Don't know why but this was in your original code
        File.Delete(Path.Combine(Application.persistentDataPath, "myjson.json"));

        //Save the downloaded data as File
        File.WriteAllText(Path.Combine(Application.persistentDataPath, "myjson.json"), jsonFile);

        //Load the downloaded data 
        string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));

        Debug.Log(text);
        RootObject m = JsonUtility.FromJson<RootObject>(text);
        City.text = m.city_info.name;
        Temperature.text = (m.current_condition.tmp).ToString();
    }
}

If you have problems please update to Unity 5.4. The UnityWebRequest API should be used for this and it was introduced in 5.3 but bugs were fixed in 5.4. You need using UnityEngine.Networking; to use UnityWebRequest.

Comments