版本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程序研究院 发表




亲自测试(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,不知道为什么。有代码例子吗