版本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
最后希望大家可以帮忙多多测试看看,谢谢啦~~
- 本文固定链接: https://www.xuanyusong.com/archives/4033
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
我按照上面说的,导出一个android项目,然后改代码,但是编译的时候报错,我把android版本改成了6.0又报下面这些错,这个要怎么弄
Description Resource Path Location Type
error: Error: String types not allowed (at ‘configChanges’ with value ‘mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density’). AndroidManifest.xml /UnityPlayerActivity line 5 Android AAPT Problem
我新建了一个unity项目,然后导出为Android项目,UnityPlayerActivity.java也改了,但是导出为jar的时候总是报错,编译是报错AndroidManifest.xml:5: error: Error: String types not allowed (at ‘configChanges’ with value ‘mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density’).
我修改了AndroidBuildTarget为Android6.0也一样报错,6.0在SDKmanager里面是完全安装了的,导出jar是报错JAR creation failed. See details for additional information.
java/com/zhourui/test [in UnityPlayerActivity] is not on its project’s build path
Unable to get package fragment root: UnityPlayerActivity/java/com/zhourui/test/UnityPlayerActivity.java
java/com/zhourui/test [in UnityPlayerActivity] is not on its project’s build path
java/com/zhourui/test [in UnityPlayerActivity] is not on its project’s build path
Unable to get package fragment root: UnityPlayerActivity/java/com/zhourui/test/UnityPlayerActivity.java
java/com/zhourui/test [in UnityPlayerActivity] is not on its project’s build path
很是头疼啊,网上都查不到解决方法的
而我的问题是用lua框架,正好需要File
File.ReadAllBytes
正在找其他解决方案
亲自测试(windows和android) 新版API, Application.streamingAssetsPath 可以使用。
Unity5.3.4 亲测这样写也能用了AssetBundle.LoadFromFile(Application.streamingAssetsPath +”/yusong.unity3d”);
最近也在用直接读取apk里的ab来减轻把ab复制出去的麻烦,但有很大的问题,loadasset内容时,最少卡半分钟以上。。。这种读法效率这么差?
原来是导出到eclipse后,eclipse编译出来的包在读取apk目录时会有问题
那请问有办法解决么
那么不能用File进行操作了,那怎样读取Manifest里面的内容啊?怎样获取依赖关系呢?
Android 同步读取文件用 ZipFile
测试了雨松的方法 可以用。http://blog.ihaiu.com/unity-load_android_StreamingAssets
http://www.bkjia.com/Androidjc/972936.html像这种方式的 同步加载是不是 不科学。我测试是行不通的。 因为他把主线程卡死了,而WWW也用的是主线程,WWW就没机会执行了
AssetBundle.LoadFromFile 读取失败路径:Application.dataPath “!assets/”版本:5.4.1not find resouce:Background/background_4.assetbundle(/data/app/com.max.test-1/base.apk!assets/nico/background/background_4.assetbundle)
AssetBundle.LoadFromFile 读取失败路径:Application.dataPath + “!assets/”版本:5.4.1not find resouce:Background/background_4.assetbundle(/data/app/com.max.test-1/base.apk!assets/nico/background/background_4.assetbundle)
请问这是什么原因…
AssetBundle.LoadFromFile 加载Application.persistentDataPath里的assetbundle路径是什么格式,我总是加载不成功
有可能是读取SD卡权限没打开
“Application.streamingAssetsPath = jar:file:///data/app/com.xxx.xxx-1.apk!/assetsApplication.dataPath ”!assets” = /data/app/com.xxx.xxx-1.apk!assets区别在于有没有jar:file://”真的吗????难道不是在.apk!/assets和.apk!assets那个“/”的区别吗?
“Application.streamingAssetsPath = jar:file:///data/app/com.xxx.xxx-1.apk!/assetsApplication.dataPath+”!assets” = /data/app/com.xxx.xxx-1.apk!assets区别在于有没有jar:file://”真的吗????难道不是在.apk!/assets和.apk!assets那个“/”的区别吗?
也有你说的这个区别。。
bgm.unity3d 看下路径对不对 改成 string path = Application.streamingAssetsPath “/bgm”; 可以加载
5.3.4版本调用LoadFromFile 路径里不能有感叹号直接用Application.dataPath /assets/xxx.ab
5.3.4版本调用LoadFromFile 路径里不能有感叹号直接用Application.dataPath+/assets/xxx.ab
安卓安装包,安装在安卓上后streamingassets下的html文件怎样读取到
AssetBundle.LoadFromFile是不是5.3的API,我项目5.2.3,没有这个方法
有吧,unity5以后都是这个api
专门去下了5.3.0,升级了测试项目,还真是,直接提示createfromflie过期,直接换成loadfromfile了,看来有必要把现在做的项目升级到5.3咯,O(∩_∩)O谢谢啦
这个办法unity4.0可以用吗?
你是试试吧, 我觉得应该可以
请问 如果我第一个工程有stream asset. 打包apk. 下一次打包前工程删掉streamasset目录重新打一个apk包覆盖安装。原来的apk下streamasset的资源会被删除吗?
会的, 因为streamasset这个目录在apk里。
string path = Application.dataPath “!/assets/bgm.unity3d”;AssetBundle asset = AssetBundle.LoadFromFile(path);这些代码我在安卓上测试根本不能去读。。。即便是txt文件,用LoadFromFile也无法读取,只能用www,不知道为什么。有代码例子吗
string path = Application.dataPath + “!/assets/bgm.unity3d”;AssetBundle asset = AssetBundle.LoadFromFile(path);这些代码我在安卓上测试根本不能去读。。。即便是txt文件,用LoadFromFile也无法读取,只能用www,不知道为什么。有代码例子吗
!/assets/改成!assets/
.TXT文件有这个方法试,怎么不行啊。说文件未找到。
LoadFromFile 只能读assetbundle 读不了txt.
求救,为什么我的加载不了。 string path = Application.dataPath “!assets/bgm.unity3d”; AssetBundle asset = AssetBundle.LoadFromFile(path);确定文件名以及文件没问题;5.3,4P5
求救,为什么我的加载不了。 string path = Application.dataPath + “!assets/bgm.unity3d”; AssetBundle asset = AssetBundle.LoadFromFile(path);确定文件名以及文件没问题;5.3,4P5
我测试是没问题的。。
bgm.unity3d 看下路径对不对 改成 string path = Application.streamingAssetsPath + “/bgm”; 可以加载
后面更新的方法,果然把之前的不优雅的做法干掉了。~~
我项目用的是assetmanager效率还可以,也不算太慢
可以不用这个了。。 直接AssetBundle.LoadFromFile 我补充在文章里了。。
5.3之前的版本 CreatFormFile 在IOS上有文件打开数量限制,请问新的接口,还有同样的限制吗
Android可以用AssetBundle.LoadFromFile,只是路径问题
string path = Application.datePath+”!assets/test.ab”; 试试
真是非常感谢啊。 我印象里以前我测试过这个方法,是不行了。 但是看见留言里还有别人也在说这个。。我就抱着试试看的心态试验了一下。。 果然成功了。。。。万分感谢!!!!
加载不成功,路径和文件确定OK。untiy3d版5.3,4P5,测试手机小米4
string path = Application.datePath “!assets/test.ab”; 试试
三种方法:http://blog.csdn.net/gy373499700/article/details/49249169
我们之前也确实是这样实现的通过java直接读取byte[]。但是后边需要在后台线程加载资源 就必须用NDK去直接去数据,就你后边提到的ndk读取asset 目前有什么好的方案吗?
ndk里也可以直接访问AssetManager 来读取 assetbundle
AssetBundle assetbundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath “/yusong.unity3d”);这个在android 上不行,不是因为路径的原因吗?? Application.streamingAssetsPath 在android 下的路径格式是 jar:///****用 Application.dataPath 拼一下路径, 再加载应该就可以了~
AssetBundle assetbundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath +”/yusong.unity3d”);这个在android 上不行,不是因为路径的原因吗?? Application.streamingAssetsPath 在android 下的路径格式是 jar:///****用 Application.dataPath 拼一下路径, 再加载应该就可以了~
LoadFromFile需要访问文件系统
他说的是正确的。。。我补充在博客最上面了。。。
先赞一个
AssetBundle.LoadFromMemory(s); 依然会产生WebStream ,AssetBundle.CreatFromFile还是不能用啊 你用LoadFromMemory 大ab包占内存,小的还行。
是的。要小的ab
我先默哀三分钟
你好,请问这个方法比用AssetBundle.CreatFromFile好在哪儿
AssetBundle.CreatFromFile 在android 上不能同步读取 StreamingAssets文件夹下的ab
为何不直接放到 persist 目录呢? 这样也统一
Application.persistentDataPath 安装完包以后才有这个目录。。 没法提前放进去啊。。
我知道的一般做法是,运行第一次的时候把所有Assetbundle拷贝到这个目录,后续更新也放到这个目录下
我是把原始资源放在resources下。 加载资源的策略是优先查看assetbundle如果没有则去resources下加载。这样就不需要拷贝的。。 可是android平台下resources文件夹会被切割成很多份。感觉影响安装的速度, 所以准备用这种方式试试。。
雨凇大大 既然StreamingAssets这个目录下可以用AssetBundle.LoadFromFile读取了,为什么还要拷贝到Application.persistentDataPath这个目录下呢?用AssetBundle.CreatFromFile 这个方式读取这两个目录 有什么区别呀?最后确认一个问题就是IOS和Android 都能用AssetBundle.LoadFromFile读取是吗?IOS:AssetBundle assetbundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath +”/yusong.unity3d”); Android :AssetBundle assetbundle = AssetBundle.LoadFromFile( Application.dataPath + “!assets/yusong.unity3d”);
雨凇大大 既然StreamingAssets这个目录下可以用AssetBundle.LoadFromFile读取了,为什么还要拷贝到Application.persistentDataPath这个目录下呢?用AssetBundle.CreatFromFile 这个方式读取这两个目录 有什么区别呀?最后确认一个问题就是IOS和Android 都能用AssetBundle.LoadFromFile读取是吗?IOS:AssetBundle assetbundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath “/yusong.unity3d”); Android :AssetBundle assetbundle = AssetBundle.LoadFromFile( Application.dataPath “!assets/yusong.unity3d”);
话说雨凇大大 mac下用的啥编辑器哇?
这样用蛮久了,效率ok的就是文章中您说用NDK里面替换? 看了那个文章介绍,有必要么? 和 android的am管理有啥区别
放在C里面读我觉得会快一点。。
有新方法。。 我补充在博客最上面了
这样写有啥子好处么?
坐等效率反馈
我也在等。。。。 哈哈 求测试啊。。
不错不错