Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Unity StreamingAssets on Android

I wrote some code to get all the folders inside a folder inside the StreamingAssets and then to get all the files in that folder. It works well on Windows but I can't get it to work on Android.

Here is the code :

foreach (string s in Directory.GetDirectories(model.path + "/Levels")) {
        GameObject el = (GameObject)Instantiate(listButton, Vector3.zero, Quaternion.identity);
        el.transform.SetParent(grid1.transform);
        string[] words = s.Split('/');
        #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
                            words = s.Split('\\');
        #endif
        el.GetComponentInChildren<Text>().text = words[words.Length - 1];
        el.GetComponent<Button>().onClick.AddListener(() => {
            MapSizeButtonClick(Int32.Parse(el.GetComponentInChildren<Text>().text));
        });
    }

I had to add the #if UNITY_STANDALONE_WIN for windows because of the '\'.

Then for the files inside that folder I wrote this :

foreach (string s in Directory.GetFiles(model.path + "/Levels/" + model.mapSize + "/" + model.colorNumber)) {
        string[] words = s.Split('/');
        #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
                    words = s.Split('\\');
        #endif
        words = words[words.Length - 1].Split('.');
        if (words[1] == "json") {
            GameObject el = (GameObject)Instantiate(listButton, Vector3.zero, Quaternion.identity);
            el.transform.SetParent(grid3.transform);
            el.GetComponentInChildren<Text>().text = words[0];
            el.GetComponent<Button>().onClick.AddListener(() => {
                levelButtonClick(Int32.Parse(el.GetComponentInChildren<Text>().text));
            });
        }
    }

I'm using UnityEngine.UI.Directory but I read that it can't be use on Android and I must use WWW instead. Something like this :

string xmlSetUpPath = "jar:file://" + Application.dataPath + "!/assets/xml/xmlSetUp.xml";

        WWW book1WWW = new WWW(book1Path);
        yield return book1WWW;
        if(!File.Exists(Application.persistentDataPath + "/xml/book1.xml"))
        {
            File.WriteAllBytes(Application.persistentDataPath + "/xml/book1.xml", book1WWW.bytes); 
        }

However I couldn't find anything like Directory.getFiles() or Directory.getFolder(). So I thought I could use WWW to check if the file exists (as the file names are 1.json, 2.json, 3.json) and iterate until a file doesn't exist.

But I would also need to check if a folder exists for the 1st part of the script and I can't find how to check if a folder exists with WWW. (My folders names are also 1,2,3,4...)

So how to check if a folder exists with WWW ?

Or what else can I do ?

UPDATE :

I updated the code, now it looks like this :

for (int i = 0; i < 100; i++) {
        if (Directory.Exists(Path.Combine(model.path, "Levels/" + i.ToString()))){
            GameObject el = (GameObject)Instantiate(listButton, Vector3.zero, Quaternion.identity);
            el.transform.SetParent(grid1.transform);
            el.GetComponentInChildren<Text>().text = i.ToString();
            el.GetComponent<Button>().onClick.AddListener(() => {
                MapSizeButtonClick(Int32.Parse(el.GetComponentInChildren<Text>().text));
            });
        }
    }

I use path.combine() and check every folder from 0 to 100. It works on Windows but it still doesn't work in Android.

The path is set like this :

#if UNITY_IPHONE
        path = Application.dataPath + "/Raw";
    #endif

    #if UNITY_ANDROID
        path = "jar:file://" + Application.dataPath + "!/assets";
    #endif

    #if UNITY_STANDALONE || UNITY_EDITOR
        path = Application.dataPath + "/StreamingAssets";
    #endif

QUESTION UPDATE

I made a script that generate the file paths. The paths are always the same : "FolderNumerotedFromYToX/FolderNumerotedFromYToX/FileNumerotedFrom1ToX.json". The generation works but the writing to JSON doesn't. It outputs "{}".

        // Generate level list
    List<KeyValuePair<int, List<KeyValuePair<int, List<int>>>>> l;
    l = new List<KeyValuePair<int, List<KeyValuePair<int, List<int>>>>>();
    for (int i = 1; i < 100; i++) {
        if (Directory.Exists(Path.Combine(Path.Combine(Application.dataPath, "StreamingAssets"), "Levels/" + i.ToString()))) {
            l.Add(new KeyValuePair<int, List<KeyValuePair<int, List<int>>>>(i, new List<KeyValuePair<int, List<int>>>()));
            for (int j = 1; j < 100; j++) {
                if (Directory.Exists(Path.Combine(Path.Combine(Application.dataPath, "StreamingAssets"), "Levels/" + i + "/" + j))) {
                    l[l.Count - 1].Value.Add(new KeyValuePair<int, List<int>>(j, new List<int>()));
                    int k = 1;
                    while (true) {
                        if (File.Exists(Path.Combine(Path.Combine(Application.dataPath, "StreamingAssets"), "Levels/" + i + "/" + j + "/" + k + ".json"))) {
                            l[l.Count - 1].Value[l[l.Count - 1].Value.Count - 1].Value.Add(k);
                        }
                        else
                            break;
                        k++;
                    }
                }
            }
        }
    }
    string ljson = JsonUtility.ToJson(l);
    var lsr = File.CreateText("Assets/StreamingAssets/levels.json");
    lsr.WriteLine(ljson);
    lsr.Close();

Can you help me finding a way to store this to a file ?

like image 207
Elbbard Avatar asked Feb 23 '16 15:02

Elbbard


2 Answers

It may sound hard, but you really have to use the WWW class to access your files from StreamingAssets on Android.

And you have to keep a list of your filenames, to be able to access them, as there seems to be no way to use something like File.Exists or Directory.GetFiles.

Example:

WWW www = new WWW(source);
yield return www;

if (string.IsNullOrEmpty(www.error))
{
    // make sure the destination directory exists
    File.WriteAllBytes(destination, www.bytes); 
}
else
{
    // error handling
}

Your source files (base) path should look like this: jar:file://" + Application.dataPath + "!/assets/


From the docs:

Note that on Android, the files are contained within a compressed .jar file (which is essentially the same format as standard zip-compressed files). This means that if you do not use Unity’s WWW class to retrieve the file then you will need to use additional software to see inside the .jar archive and obtain the file.

Source: http://docs.unity3d.com/Manual/StreamingAssets.html

like image 54
d4Rk Avatar answered Sep 21 '22 01:09

d4Rk


To solve this problem I created pre-compilation script which will run before the compilation; this script will list the names of the files you want to access later in text file

 #if UNITY_EDITOR
 using UnityEditor.Build;
 using UnityEditor;
 using System.IO;

 public class BM_AndroidBuildPrepartion : IPreprocessBuild
 {
     public int callbackOrder { get { return 0; } }
     public void OnPreprocessBuild(BuildTarget target, string path)
     {
         // Do the preprocessing here
         string[] fileEntries = Directory.GetFiles("Assets/Resources/Prefabs/alphabet", "*.prefab");
         System.IO.Directory.CreateDirectory("Assets/StreamingAssets/");
         using (StreamWriter sw = new StreamWriter("Assets/StreamingAssets/alphabet.txt", false))
         {

         foreach (string filename in fileEntries) {
                 sw.WriteLine(Path.GetFileNameWithoutExtension(filename));
         }

         }
     }
 }
 #endif

then I read the text file and you can access the files in same way but you have to put them inside your project in Assets/StreamingAssets/

#if UNITY_ANDROID
        string  path = "jar:file://" + Application.dataPath + "!/assets/alphabet.txt";
          WWW wwwfile = new WWW(path);
          while (!wwwfile.isDone) { }
          var filepath = string.Format("{0}/{1}", Application.persistentDataPath, "alphabet.t");
          File.WriteAllBytes(filepath, wwwfile.bytes);

          StreamReader wr = new StreamReader(filepath);
              string line;
              while ((line = wr.ReadLine()) != null)
              {
              //your code
              }
   #endif
like image 22
Shady Mohamed Sherif Avatar answered Sep 19 '22 01:09

Shady Mohamed Sherif