前回の記事では、UnityでLive2Dモデルをスクリプトから動的にロードする方法について紹介しましたが、なぜかAndroid実機で確認するとモデルの読み込みが失敗してしまいます。monitor.batでログを確認すると「DirectoryNoFoundException: Counld not find a part of the path “/jar:file:/data/app/***-***/base.apk!/assets/***.***”」というようなエラーが出てしまっています。
調べてみると、どうやらAndroidでは特殊なファイル格納を行っているらしく、ファイルを参照する為にApplication.StreemingAssetsPathだけでは駄目なのだそう。


何だか色々なやり方があるらしい
調べて見た所、
WWWクラスを使ってアクセスする方法その① 参照
private HogeXmlData GetSerializedXmlHoge(string path) { var streamingPath= System.IO.Path.Combine(Application.streamingAssetsPath, path) HogeXmlData hoge = null; #if UNITY_ANDROID && !UNITY_EDITOR //wwwを使用する方法 WWW www = new WWW(streamingPath); while (!www.isDone) { } using (var sr = new StringReader(www.text)) { hoge = (HogeXmlData) serializer.Deserialize(sr); } #else //通常のファイルアクセス using (var fs = File.OpenRead(streamingPath)) { hoge = (HogeXmlData) serializer.Deserialize(fs); } #endif return hoge ; }
WWWクラスを使う方法② 参照
string filePath = Application.streamingAssetsPath + "/Items.json"; string jsonString; if (Application.platform == RuntimePlatform.Android) { WWW reader = new WWW(filePath); while (!reader.isDone) { } jsonString = reader.text; } else { jsonString = File.ReadAllText(filePath); } JsonData itemData = JsonMapper.ToObject(jsonString);
WWWクラスを使う方法③ 参照
void Start () { StartCoroutine(GetPng ()); } public IEnumerator GetPng() { // URLを指定してダウンロード WWW wwwTexture = new WWW ("http://www.test/sample.png"); // ダウンロード完了まで待つ while (!wwwTexture.isDone) { yield return null; } // uGUIのテクスチャに設定 RawImage img = gameObject.GetComponent<RawImage>(); img.texture = wwwTexture.texture; }
WWWクラスを使う方法④ 参照
using UnityEngine; using System.Collections; public class ExampleClass : MonoBehaviour { public string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "MyFile"); public string result = ""; IEnumerator Example() { if (filePath.Contains("://")) { WWW www = new WWW(filePath); yield return www; result = www.text; } else result = System.IO.File.ReadAllText(filePath); } }
UnityWebRequestを使ったやり方 参照
private IEnumerator AndroidMoviePath(){ string filePath = ""; string moviePath = ""; filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "ファイル名"); if(filePath.Contains("://"){ var www = UnityWebRequest.Get(filePath); yield return www.SendWebRequest(); moviePath = www.downloadHandler.text; }else{ moviePath = System.IO.File.ReadAllText(filePath); } }
Application.PersistentDataPathにコピーする?方法 参照
string FilePath; #if UNITY_IPHONE FilePath = Application.dataPath + "/Raw/" + filename; #else string fullPath = "jar:file://" + Application.dataPath + "/!/assets/" + filename; WWW www = new WWW (fullPath); while (!www.isDone) { } FilePath = Application.persistentDataPath + filename; File.WriteAllBytes (toPath,www.bytes); #endif
など色々なやり方が出てきます。
困った事
WWWクラスを使ったやり方が多く出てきますし、Unity公式でもWWWを使ったサンプルを置いてますが、WWWクラスは現在非推奨らしいです。
しかし、現在推奨されるUnityWebRequest でのやり方はコルーチンを使ったやり方しか書かれておらず、その辺あまり詳しくないので(Live2Dのライブラリ内の読み込み部分で勝手にStartCoroutine()やると変な事になりそう)WWWクラスを使う事にしました。
どういう実装にしたか
こちらの記事で紹介したBuiltinLoadAssetAtPath()を以下のようにいじりました。
public object BuiltinLoadAssetAtPath(Type assetType, string absolutePath) { #if UNITY_ANDROID && !UNITY_EDITOR if (assetType == typeof(byte[])) { WWW reader = new WWW(absolutePath); while (!reader.isDone) { } return reader.bytes; } else if (assetType == typeof(string)) { WWW reader = new WWW(absolutePath); while (!reader.isDone) { } return reader.text; } else if (assetType == typeof(Texture2D)) { var texture = new Texture2D(1, 1); WWW reader = new WWW(absolutePath.Replace(defaultCostume, nowCostume)); while (!reader.isDone) { } texture.LoadImage(reader.bytes); return texture; } #else if (assetType == typeof(byte[])) { return File.ReadAllBytes(absolutePath); } else if (assetType == typeof(string)) { return File.ReadAllText(absolutePath); } else if (assetType == typeof(Texture2D)) { var texture = new Texture2D(1, 1); texture.LoadImage(File.ReadAllBytes(absolutePath.Replace(defaultCostume, nowCostume))); return texture; } #endif throw new NotSupportedException(); }
WWWクラスなんて使った事も無かったのですが、Fileクラスを使っているサンプルの方で使われてたReadAllBytes(),ReadAllText()に対応してそうなbytesプロパティとtextプロパティがあったので、それを使ってみると無事にAndroid実機で動きました!
注意点
最初テクスチャ読み込みの部分でwhile(!reader.isDone)を書き忘れていたのですが、この場合読み込み失敗したテクスチャは

のようになります。結果、

モデルがこういう悲惨な事になります。モデルが紅白模様になってしまった場合はテクスチャ読み込み完了をちゃんと待っているか確認しましょう。
コメント