版本Unity5.3.3
Android 小米pad1
首先非常感谢 @守着阳光 同学在下面的留言。让我解决了一个大的谜团。。
开始我知道 StreamingAssets 路径是这个 path = “jar:file://” + Application.dataPath + “!/assets/”;
文档在这里: http://docs.unity3d.com/Manual/StreamingAssets.html
后来我知道了一个新API Application.streamingAssetsPath
Application.streamingAssetsPath 其实就等于 “jar:file://” + Application.dataPath + “!/assets/”;
然而问题就出现在这个路径上。我打印了一下LOG
Application.streamingAssetsPath = jar:file:///data/app/com.xxx.xxx-1.apk!/assets
Application.dataPath+”!assets” = /data/app/com.xxx.xxx-1.apk!assets
也就是说Application.streamingAssetsPath 多了一个 jar:file://
那么如果想在Android上同步方法AssetBundle.LoadFromFile 就得用 Application.dataPath+”!assets”这个路径。
从此这段代码就正常了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using UnityEngine; using System.Collections; public class NewBehaviourScript : MonoBehaviour { public SpriteRenderer spriteRenderer; void Start () { // /data/app/com.xxx.xxx-1.apk!assets/yusong.unity3d string path = Application.dataPath+"!assets/yusong.unity3d"; AssetBundle assetbundle = AssetBundle.LoadFromFile(path); Sprite sprite = assetbundle.LoadAsset<Sprite>("0"); spriteRenderer.sprite =sprite; } } |
Unity的坑啊~ 55555555555555555555
还有这个路径只能用来AssetBundle.LoadFromFile 。如果想用File类操作。 比如File.ReadAllText 或者 File.Exists Directory.Exists 这样都是不行的。
———————————-!!从今天以后下面的代码已经可以作废了!!—————————
streamingAssets 这个目录在IOS下是可以同步读取的,但是在Android下必须用www来异步读取。。这就很恶心了~所以最近我就在想办法如何能在Android下也能同步读取。如下图所示,我把一个sprite打成assetbundle并且放在StreamingAssets目录下。
assetbundle的压缩格式 ,我使用的是unity5.x的lz4方式。
1 2 3 4 5 6 7 8 | [MenuItem ("Assets/Build AssetBundles")] static void BuildAllAssetBundles () { BuildPipeline.BuildAssetBundles ("Assets/StreamingAssets",BuildAssetBundleOptions.ChunkBasedCompression,BuildTarget.Android); AssetDatabase.SaveAssets (); AssetDatabase.Refresh(); } |
然后创建一个3D Sprite 在Hierarchy里 试图把这个ab里的sprite加载上去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | using UnityEngine; using System.Collections; public class NewBehaviourScript : MonoBehaviour { public SpriteRenderer spriteRenderer; void Start () { //注释掉的代码是 unity自己的同步方式, 但是在Android上不行, 可是在IOS上可以 // AssetBundle assetbundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath +"/yusong.unity3d"); // // Sprite sprite = assetbundle.LoadAsset<Sprite>("0"); // // spriteRenderer.sprite =sprite; //以下代码通过JAVA代码来同步读取并且返回给unity AndroidJavaClass m_AndroidJavaClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject m_AndroidJavaObject = null; if (m_AndroidJavaClass != null) { m_AndroidJavaObject = m_AndroidJavaClass.GetStatic<AndroidJavaObject>("currentActivity"); } byte[] s = m_AndroidJavaObject.Call<byte[]>("LoadAB","yusong.unity3d"); AssetBundle assetbundle = AssetBundle.LoadFromMemory(s); Sprite sprite = assetbundle.LoadAsset<Sprite>("0"); spriteRenderer.sprite =sprite; } } |
然后,把unity导出成android工程。。
用eclipse打开刚刚导出的工程。找到UnityPlayerActivity.java类 添加如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | package com.yusong.momo; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import com.unity3d.player.*; import android.app.Activity; import android.content.res.AssetManager; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; public class UnityPlayerActivity extends Activity { protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code protected AssetManager assetManager; // Setup activity layout @Override protected void onCreate (Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); getWindow().setFormat(PixelFormat.RGBX_8888); // <--- This makes xperia play happy mUnityPlayer = new UnityPlayer(this); setContentView(mUnityPlayer); mUnityPlayer.requestFocus(); assetManager = getAssets(); } private byte[] readtextbytes(InputStream inputStream) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); //长度这里暂时先写成1024 byte buf[] = new byte [1024]; int len; try { while ((len = inputStream.read(buf)) != -1) { outputStream.write(buf, 0, len); } outputStream.close(); inputStream.close(); } catch (IOException e) { } return outputStream.toByteArray(); } //读取assetbund并且返回字节数组 public byte[] LoadAB(String path) { InputStream inputStream = null ; try { inputStream = assetManager.open(path); } catch (IOException e) { Log.v ("unity", e.getMessage()); } return readtextbytes(inputStream); } // Quit Unity @Override protected void onDestroy () { mUnityPlayer.quit(); super.onDestroy(); } // Pause Unity @Override protected void onPause() { super.onPause(); mUnityPlayer.pause(); } // Resume Unity @Override protected void onResume() { super.onResume(); mUnityPlayer.resume(); } // This ensures the layout will be correct. @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mUnityPlayer.configurationChanged(newConfig); } // Notify Unity of the focus change. @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); mUnityPlayer.windowFocusChanged(hasFocus); } // For some reason the multiple keyevent type is not supported by the ndk. // Force event injection by overriding dispatchKeyEvent(). @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_MULTIPLE) return mUnityPlayer.injectEvent(event); return super.dispatchKeyEvent(event); } // Pass any events not handled by (unfocused) views straight to UnityPlayer @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } } |
OK 大功告成, 我的sprite已经可以同步加载了。
如下图所示,那么实际上unity把已经把streamingAssets目录下的资源放在了android的assets目录下。
那么我们同步加载的原理也是利用Android的AssetManager这个类来读取的。
刚和同事讨论了一下,如果有效率的问题,我们可以在ndk里读取assets下的资源。 比如向这样~ c# 调用 ndk 读取完直接返回给c# 这样就可以不通过java这一层。。
http://www.cppblog.com/johndragon/archive/2012/12/28/196754.html
最后希望大家可以帮忙多多测试看看,谢谢啦~~
- 本文固定链接: http://www.xuanyusong.com/archives/4033
- 转载请注明: 雨松MOMO 2016年04月28日 于 雨松MOMO程序研究院 发表