之前有说过,Unity中StreamingAssets文件数量超过250个,使用Gradle打包会失败(只有安卓有这个问题,Unity版本是2017.4.7f1)。因此采用的解决方案是将StreamingAssets中的文件打成一个zip包,再解压到持久化目录中,之前临时使用的方案是拷贝文件。项目急需这个需求,只好放下手头不急的事,花了一天的时间来处理。
一开始就不打算用c#来处理,www加载效率低而且占内存,因此这边测试用Java来解压,发现效率不错,200M的文件解压好机子大概只需要2秒,最烂的机子10秒,按最烂的机子来算,每秒也有20M的速度。这边另外一个项目是用www解压的,用最好的机子,650M的文件解压时间为1分30秒多,每秒7M的速度。所以说很多文章说Unity对www加载优化了,其实测一下就知道效率的问题了。
还是在之前写的安卓通用类上加了个解压的接口。先看c#这边的调用:
/// <summary>
/// 调用: AndroidUtility.UnZipFile("test.zip", Application.persistentDataPath + "/Test/");
/// </summary>
/// <param name="zipFile"></param>
/// <param name="newPath"></param>
public static bool UnZipFile(string zipFile, string newPath)
{
#if UNITY_ANDROID && !UNITY_EDITOR
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start(); // 开始监视代码
var activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
var assetManager = activity.Call<AndroidJavaObject>("getAssets");
var javaClass = new AndroidJavaClass("com.zp.utility.api");
var javaObject = javaClass.CallStatic<AndroidJavaObject>("instance");
var result = javaObject.Call<bool>("UnZipFile", assetManager, zipFile, newPath);
stopwatch.Stop(); // 停止监视
System.TimeSpan timeSpan = stopwatch.Elapsed; // 获取总时间
Debug.LogError("解压总时间为: " + timeSpan.TotalSeconds);
return result;
#endif
return false;
}
Java这边的是:
/**
* 从StreamingAssets解压文件到持久化目录
* @param object AssetManager: Unity获取并传过来的
* @param zipFile zipFile:StreamingAssets下的zip文件
* @param newPath
* @return
*/
public boolean UnZipFile(Object object, String zipFile, String newPath)
{
Log.v("ZP", "111111111111111");
AssetManager assetManager = (AssetManager)object;
boolean bIsNull = assetManager == null;
if(bIsNull) {
Log.v("ZP", "AssetManager Is Null");
return false;
}
File desDir = new File(newPath);
if (!desDir.exists())
{
desDir.mkdirs();
}
InputStream input = null;
try
{
input = assetManager.open(zipFile);
if(input == null)
return false;
ZipInputStream zipinputstream = new ZipInputStream(input);
if(null == zipinputstream)
return false;
ZipEntry ze = null;
byte[] buf = new byte[1024];
while((ze = zipinputstream.getNextEntry()) != null){
String dirstr = newPath + ze.getName();
if(ze.isDirectory()){//是文件夹
dirstr = new String(dirstr.getBytes("8859_1"), "GB2312");
File f = new File(dirstr);
if (!f.exists())
f.mkdirs();
zipinputstream.closeEntry();
continue;
}
//是文件
dirstr = new String(dirstr.getBytes("8859_1"), "GB2312");
//Log.v("ZP", "dirstr: "+ dirstr);
File newFlie = new File(dirstr);
if(!newFlie.exists()){
File fileParentDir = newFlie.getParentFile();
if (!fileParentDir.exists()) {
fileParentDir.mkdirs();
}
newFlie.createNewFile();
}
else//重复文件不解压
{
zipinputstream.closeEntry();
continue;
}
OutputStream os = new BufferedOutputStream(new FileOutputStream(dirstr));
int len=0;
while ((len = zipinputstream.read(buf, 0, 1024)) != -1) {
os.write(buf, 0, len);
}
zipinputstream.closeEntry();
os.close();
}
zipinputstream.close();
Log.d("ZP", "finishssssssssssssssssssss");
return false;
}
catch(Exception e)
{
e.printStackTrace();
}
return false;
}
具体的就不解释了,代码很简单。需要注意的是用File和ZipFile是读取不到StreamingAssets中给的文件。而且这个功能也有个缺点就是不好做loading条,因为不好计算文件大小和数量,如果计算的话会有开销不值得,所以做个假的进度条。