///
///通过tomcat服务器进行下载ab包
///
using
System;
using
System.
Collections;
using
System.
Collections.
Generic;
using
System.
IO;
using
UnityEngine;
public
class
UpdateAssetBundles :
MonoBehaviour
{
///
<
summary
>
/// 配表路径
///
</
summary
>
List<
string> mainPath;
///
<
summary
>
/// 配表信息
///
</
summary
>
Dictionary<
string,
List<
string>> tablePath;
///
<
summary
>
/// 进入游戏进行资产更新
///
</
summary
>
public
void
FirstUpdateAB()
{
StartCoroutine(
IEFirstUpdateAB());
}
IEnumerator
IEFirstUpdateAB()
{
//进入游戏先检测persistent目录下是否有文件,没有则表示为第一次进游戏,
//需要将streaming目录下的文件拷贝到该目录下。
if (!
Directory.
Exists(
AssetPath.
persistentPath))
{
Debug.
Log(
"解压本地文件!(该步骤不需要流量)");
//注意,在Android中,StreamingAssets中的文件包含在一个.jar压缩文件(基本上与标准的zip为统一格式)中,所以只能用
//WWW读取,否则要使用第三方软件来读取,不能用C#的文件读取方法。
List<
string> streamList =
new
List<
string>();
yield
return
StartCoroutine(
IECStomcat(
AssetPath.
streamingPath +
"/" +
IP.
preloadedPath,
streamList));
string tableStr =
"";
for (
int i =
0;
i <
streamList.
Count;
i++)
{
tableStr +=
streamList[
i];
tableStr +=
Environment.
NewLine;
string relativePath =
"/" +
streamList[
i].
Split(
';')[
0];
yield
return
StartCoroutine(
IEUpdateAssetBundle(
Application.
streamingAssetsPath +
relativePath.
Replace(
'
\\
',
'/'),
Application.
persistentDataPath +
relativePath.
Replace(
'
\\
',
'/')));
}
Debug.
Log(
"解压完成!");
CreadTextFile(
AssetPath.
persistentPath +
"/" +
IP.
preloadedPath,
tableStr);
yield
return
new
WaitForSeconds(
0);
}
//获取主配表
Debug.
Log(
"获取服务器列表!(建议在WiFi下更新)");
mainPath =
new
List<
string>();
yield
return
StartCoroutine(
IECStomcat(
IP.
ResoucelsIP +
AssetPath.
_Android +
"/" +
IP.
ResoucelsTablePath,
mainPath));
Debug.
Log(
"检测是否需要更新!");
if (
mainPath !=
null)
{
tablePath =
new
Dictionary<
string,
List<
string>>();
for (
int i =
0;
i <
mainPath.
Count;
i++)
{
List<
string> list =
new
List<
string>();
tablePath.
Add(
mainPath[
i],
list);
yield
return
StartCoroutine(
IECStomcat(
IP.
ResoucelsIP +
mainPath[
i],
list));
}
}
else
{
Debug.
Log(
"服务器更新失败!找不到主配置文件!");
}
List<
string> updateTable =
ContrastDetection(
tablePath);
Debug.
Log(
"检测到有" +
updateTable.
Count +
"个文件需要更新!");
yield
return
new
WaitForSeconds(
0.5f);
if (
updateTable.
Count >
0)
{
Debug.
Log(
"开始更新资源文件!");
for (
int i =
0;
i <
updateTable.
Count;
i++)
{
string serverPathAB =
IP.
ResoucelsIP +
updateTable[
i].
Split(
';')[
0];
string localPathAB =
Application.
persistentDataPath +
"/" +
updateTable[
i].
Split(
';')[
0];
yield
return
StartCoroutine(
IEUpdateAssetBundle(
serverPathAB.
Replace(
'
\\
',
'/'),
localPathAB.
Replace(
'
\\
',
'/')));
}
Debug.
Log(
"资源文件已更新完毕!");
Debug.
Log(
"开始更新配置文件!");
readText(
tablePath);
yield
return
new
WaitForSeconds(
0.5f);
Debug.
Log(
"配置文件已更新完成!");
}
Debug.
Log(
"进入游戏!");
}
///
<
summary
>
/// 在安卓平台下判断该条路径是否为 "jar:file"开头(返回true为是)
///
</
summary
>
///
<
returns
></
returns
>
public
bool
jarFilePath(
string path)
{
if (
Application.
platform ==
RuntimePlatform.
Android &&
path.
Substring(
0,
AssetPath.
jarHead.
Length) ==
AssetPath.
jarHead)
{
return
true;
}
return
false;
}
///
<
summary
>
/// 判断该条路径是否为"http"开头(返回true为是)
///
</
summary
>
///
<
param
name
=
"path"
></
param
>
///
<
returns
></
returns
>
public
bool
httpPath(
string path)
{
if (
path.
Substring(
0,
AssetPath.
httpHead.
Length) ==
AssetPath.
httpHead)
{
return
true;
}
return
false;
}
///
<
summary
>
/// 获取配表,并把每行的信息写入列表中
///
</
summary
>
///
<
param
name
=
"path"
></
param
>
///
<
returns
></
returns
>
IEnumerator
IECStomcat(
string path,
List<
string> mainPath)
{
string[] pathAll;
if (
jarFilePath(
path) ||
httpPath(
path))
{
//这里有个问题,加了时间戳只有第一个链接能访问到
//if (httpPath(path))
//{
// string nn = DateTime.Now.Ticks.ToString();
// path = path + "?a=" + nn.Substring(nn.ToString().Length - 6);
//}
WWW www =
new
WWW(
path);
yield
return
www;
if (
www.
error !=
null)
{
Debug.
Log(
www.
error+
" "+
path);
yield
break;
}
pathAll =
www.
text.
Split(
Environment.
NewLine.
ToCharArray());
}
else
{
pathAll=
File.
ReadAllText(
path).
Split(
Environment.
NewLine.
ToCharArray());
}
for (
int i =
0;
i <
pathAll.
Length;
i++)
{
if (
pathAll[
i] !=
"")
{
mainPath.
Add(
pathAll[
i]);
}
}
}
///
<
summary
>
/// 服务器配表与本地配表进行检测比对
///
</
summary
>
///
<
param
name
=
"d"
></
param
>
public
List<
string>
ContrastDetection(
Dictionary<
string,
List<
string>> d)
{
string path =
"";
List<
string> listPath =
new
List<
string>();
if (
Application.
platform ==
RuntimePlatform.
WindowsEditor)
{
path =
Application.
dataPath +
"/" +
AssetPath.
StreamingAssets;
}
else
if (
Application.
platform ==
RuntimePlatform.
Android ||
Application.
platform ==
RuntimePlatform.
IPhonePlayer)
{
path =
Application.
persistentDataPath;
}
//遍历配表
foreach (
var item
in
d)
{
string file =
"";
string localPath =
path +
"/" +
item.
Key;
//检测本地配表是否存在
if (
File.
Exists(
localPath))
{
//本地有该配表就将路径进行比对添加到列表中
file =
File.
ReadAllText(
localPath);
}
for (
int i =
0;
i <
item.
Value.
Count;
i++)
{
if (!
file.
Contains(
item.
Value[
i]))
{
listPath.
Add(
item.
Value[
i]);
}
}
}
return
listPath;
}
///
<
summary
>
/// 从服务器上下载ab包到本地,(注意斜杠,一定要把所有的反斜杠转成斜杠)
///
</
summary
>
///
<
param
name
=
"path"
>
服务器路径
</
param
>
///
<
param
name
=
"localPath"
>
本地路径
</
param
>
///
<
returns
></
returns
>
IEnumerator
IEUpdateAssetBundle(
string path,
string localPath)
{
if (
httpPath(
path))
{
string nn =
DateTime.
Now.
Ticks.
ToString();
path =
path +
"?" +
nn.
Substring(
nn.
ToString().
Length -
6);
}
WWW www =
new
WWW(
path);
yield
return
www;
if (
www.
error !=
null)
{
Debug.
Log(
"错误信息:" +
www.
error);
yield
break;
}
else
{
string headLocalPath =
pathRoundOff(
localPath);
if (!
Directory.
Exists(
headLocalPath))
{
Directory.
CreateDirectory(
headLocalPath);
}
if (
File.
Exists(
localPath))
{
File.
Delete(
localPath);
}
FileStream steam =
File.
Create(
localPath);
steam.
Close();
File.
WriteAllBytes(
localPath,
www.
bytes);
}
}
///
<
summary
>
/// 更新配表
///
</
summary
>
///
<
param
name
=
"dateList"
></
param
>
public
void
readText(
Dictionary<
string,
List<
string>> dateList)
{
string directoryPath =
Application.
persistentDataPath +
"/" +
AssetPath.
_Android +
"/" +
AssetPath.
ConfigurationFilesName;
//清除所有配表
if (
Directory.
Exists(
directoryPath))
Directory.
Delete(
directoryPath,
true);
Directory.
CreateDirectory(
directoryPath);
//创建新的配表
foreach (
var item
in
dateList)
{
string loaclPath =
Application.
persistentDataPath +
"/" +
item.
Key;
string str =
"";
for (
int i =
0;
i <
item.
Value.
Count;
i++)
{
str +=
item.
Value[
i];
str +=
Environment.
NewLine;
}
CreadTextFile(
loaclPath,
str);
}
}
///
<
summary
>
/// 创建文档文件
///
</
summary
>
///
<
param
name
=
"path"
></
param
>
///
<
param
name
=
"str"
></
param
>
public
void
CreadTextFile(
string path,
string str)
{
string headPath =
pathRoundOff(
path);
if (!
Directory.
Exists(
headPath))
Directory.
CreateDirectory(
headPath);
File.
WriteAllText(
path,
str);
}
///
<
summary
>
/// 截取文件的文件夹路径
///
</
summary
>
///
<
param
name
=
"path"
></
param
>
///
<
returns
></
returns
>
public
string
pathRoundOff(
string path)
{
string[] newPath =
path.
Split(
'
\\
');
if (
newPath.
Length <=
1)
{
newPath =
path.
Split(
'/');
}
return
path.
Substring(
0,
path.
Length -
newPath[
newPath.
Length -
1].
Length -
1);
}
}
public
class
AssetPath
{
///
<
summary
>
/// 需要打包的文件夹路径
///
</
summary
>
public
static
string OriginalPath =
Application.
dataPath +
"/AssetBundleResources/Resources";
///
<
summary
>
/// 打包出来的文件夹路径
///
</
summary
>
public
const
string StreamingAssetsPath =
@"Assets/StreamingAssets";
///
<
summary
>
/// 配置文件夹
///
</
summary
>
public
const
string ConfigurationFilesName =
"configuration";
///
<
summary
>
/// 资源文件夹
///
</
summary
>
public
const
string ResourcesFilesName =
"resources";
///
<
summary
>
/// 资源文件后缀名
///
</
summary
>
public
const
string unity3dSuffix =
".unity3d";
///
<
summary
>
/// .meta后缀名
///
</
summary
>
public
const
string metaSuffix =
".meta";
///
<
summary
>
/// 打包目录
///
</
summary
>
public
const
string StreamingAssets =
"StreamingAssets";
///
<
summary
>
/// Android
///
</
summary
>
public
const
string _Android =
"Android";
///
<
summary
>
/// IPhonePlayer
///
</
summary
>
public
const
string _IPhonePlayer =
"IPhonePlayer";
///
<
summary
>
/// 移动端本地压缩包路径
///
</
summary
>
public
static
string streamingPath =
Application.
streamingAssetsPath +
"/" +
Application.
platform;
///
<
summary
>
/// 移动端资产放置路径
///
</
summary
>
public
static
string persistentPath =
Application.
persistentDataPath +
"/" +
Application.
platform;
///
<
summary
>
/// 预留物配表相对路径
///
</
summary
>
public
const
string scheduledFileName =
"/"+
ConfigurationFilesName+
"/prefad/scheduled.txt";
///
<
summary
>
/// "jar:file"
///
</
summary
>
public
const
string jarHead =
"jar:file";
///
<
summary
>
/// "http"
///
</
summary
>
public
const
string httpHead =
"http";
///
<
summary
>
/// 配置物
///
</
summary
>
public
const
string source =
"source";
}