版本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”这个路径。
从此这段代码就正常了。
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方式。
[MenuItem ("Assets/Build AssetBundles")]
static void BuildAllAssetBundles ()
{
BuildPipeline.BuildAssetBundles ("Assets/StreamingAssets",BuildAssetBundleOptions.ChunkBasedCompression,BuildTarget.Android);
AssetDatabase.SaveAssets ();
AssetDatabase.Refresh();
}
然后创建一个3D Sprite 在Hierarchy里 试图把这个ab里的sprite加载上去。
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类 添加如下代码
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程序研究院 发表




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里面读我觉得会快一点。。
有新方法。。 我补充在博客最上面了
这样写有啥子好处么?
坐等效率反馈
我也在等。。。。 哈哈 求测试啊。。
不错不错