/*
* <资源打包介绍>
* 首先会根据已经建好的文件进行遍历,找到所有预制物并设置AssetBundleName,因为是遍历Resources下面的文件夹,
* 所以可以将每个文件夹里的所有预制物打成一个包,然后打包到StreamingAssets 下面,并会生成一个配置文件,这个
* 配置文件是以Resources下的文件夹命名的,一个文件夹一个配置文件,方便后面的更新资源,这个配置文件是根据打包
* 好的包文件生成的,每行都记录了单个包的路径+;+.manifest文件里的crc码,当每次打包预制物有改变时,crc码会重新
* 生成,更新资源时会通过配置文件里每个包路径后面的crc码来判断这个包是否需要更新。
*
*
* 所有需要打包的预制物需要放入文件夹 AssetBundleResources/Resources 下进行打包.
* 打包出来的文件会在 Assets/StreamingAssets(没有该文件夹会自动创建) 文件夹下生成.
*
* 路径供阅读下面代码参考
* 完整的需要打包路径:Assets\AssetBundleResources\Resources\Prefad\UI\XXX.prefab
* 完整的打包好的路径(安卓):Assets\StreamingAssets\Android\resources\prefad\ui\XXX.unity3d
* 完整的配置文件路径:Assets\StreamingAssets\Android\configuration\prefad\ui.txt
*
*
* 因为unity5.X不需要我们来管理引用, 所以其实大部分代码都是针对文件夹的处理,打包的代码也就两行
* 1:设置AssetBundleName
*:2:根据平台设置进行打包
*
* 该段代码打包流程
* 清除已设置的AssetBundleName -→ 找到要打包的资源并设置 AssetBundleName -→ 进行打包 -→ 创建文本并写入配置信息
*
*/
public
class
Builder :
Editor
{
///
<
summary
>
/// 需要打包的文件夹路径
///
</
summary
>
static
string OriginalPath =
Application.
dataPath +
"/AssetBundleResources/Resources";
///
<
summary
>
/// 打包出来的文件夹路径
///
</
summary
>
const
string StreamingAssets =
@"Assets\StreamingAssets";
///
<
summary
>
/// 配置文件名
///
</
summary
>
const
string ConfigurationFilesName =
"configuration";
[
MenuItem(
"打包/热更新打包")]
public
static
void
BuildAssetBundleAll()
{
#if UNITY_ANDROID &&
UNITY_EDITOR
BuildResource(
BuildTarget.
Android);
#endif
#if UNITY_IOS &&
UNITY_EDITOR
BuildResource(
BuildTarget.
iOS);
#endif
}
///
<
summary
>
/// 资源打包
///
</
summary
>
///
<
param
name
=
"target"
>
打包平台
</
param
>
static
void
BuildResource(
BuildTarget target)
{
//清除所有之前设置过的AssetBundleName
ClearAssetBundlesName();
//代码中给资源设置AssetBundleName
SetAssetBundelsName(
OriginalPath);
//因为要根据平台打包,为了方便分类,所以在Assets\StreamingAssets目录下创建一个
//以平台名字命名的文件夹来放置各平台打出来的包和其他相关的文件,以方便管理
//例如安卓平台: 处理路径为Assets\StreamingAssets\Android
string outputPath =
Path.
Combine(
StreamingAssets,
target.
ToString());
//查找Assets\StreamingAssets路径下有没有当前平台名字的文件夹,没有的话就创建
if (!
Directory.
Exists(
outputPath))
{
Directory.
CreateDirectory(
outputPath);
}
//刷新
AssetDatabase.
Refresh();
//根据平台设置进行打包
BuildPipeline.
BuildAssetBundles(
outputPath,
0,
target);
//生成配置文档(配置文档以游戏文件夹进行分类,一个游戏文件夹一个配置文档,方便管理)
ConfigurationFiles(
target);
//刷新
AssetDatabase.
Refresh();
}
///
<
summary
>
/// 清除之前设置过的AssetBundleName
/// 因为只要设置过AssetBundleName就会打包,所以这里一定要清理干净,防止重复打包
///
</
summary
>
static
void
ClearAssetBundlesName()
{
string[] strArr =
AssetDatabase.
GetAllAssetBundleNames();
for (
int i =
0;
i <
strArr.
Length;
i++)
{
AssetDatabase.
RemoveAssetBundleName(
strArr[
i],
true);
}
AssetDatabase.
RemoveUnusedAssetBundleNames();
}
///
<
summary
>
/// 在代码中给资源设置AssetBundleName
///
</
summary
>
static
void
SetAssetBundelsName(
string folderName)
{
//首先遍历需要打包的文件夹,找到所有需要打包的文件
//AssetBundleResources/Resources/Prefad/UI 因为我的要打包的文件
//都是放在Prefad下的文件夹里面也就是UI文件里所以我需要遍历到UI文件夹里面
DirectoryInfo folder =
new
DirectoryInfo(
folderName);
FileSystemInfo[] files =
folder.
GetFileSystemInfos();
for (
int i =
0;
i <
files.
Length;
i++)
{
if (
files[
i]
is
DirectoryInfo)
{
SetAssetBundelsName(
files[
i].
FullName);
}
else
{
//过滤.meta文件,并给遍历到的资源设置AssetBundleName,以路径的形式命名
//这里是一个资源一个包,也可以把多个资源打一个包中
//最好是对资源进行分类,将一些有共有资源的预制物打进一个包中
if (!
files[
i].
Name.
EndsWith(
".meta"))
{
//处理前的路径C:\Users\Administrator\Desktop\DynamicLoadResource\Assets\AssetBundleResources\Resources\Prefad\UI\XXX.prefab
//处理后的路径Resources/Prefad/UI/XXX.unity3d
//这个处理后的路径会拿来设置AssetBundleName
string str1 =
files[
i].
FullName.
Replace(
@"\",
"/");
string path =
"Assets" +
str1.
Substring(
Application.
dataPath.
Length);
AssetImporter ass =
AssetImporter.
GetAtPath(
path);
string str2 =
str1.
Substring(
Application.
dataPath.
Length +
1);
str2 =
str2.
Substring(
str2.
IndexOf(
"/") +
1);
string assetName =
str2.
Replace(
Path.
GetExtension(
str2),
".unity3d");
//这里设置AssetBundleName,AssetBundleName相同的文件会打到一个包中
ass.
assetBundleName =
assetName;
//ass.assetBundleName = "Resources/Prefad/UI/测试UI——没有相同图片引用打出来的总包.unity3d";
}
}
}
}
///
<
summary
>
/// 生成配置文件,
///
</
summary
>
static
void
ConfigurationFiles(
BuildTarget target)
{
//查找Assets\StreamingAssets\Android 下是否有 configuration(该文件用于放置生成的配置文件)文件夹
//有的话就删掉该文件夹(把文件夹下已存在的配置文件一起删除),然后重新创建该文件夹
string str =
StreamingAssets +
"/" +
target.
ToString() +
"/" +
ConfigurationFilesName;
if (
Directory.
Exists(
str))
{
Directory.
Delete(
str,
true);
}
Directory.
CreateDirectory(
str);
//处理包路径
string resourcesStr =
OriginalPath.
Substring(
OriginalPath.
LastIndexOf(
"/") +
1);
string streamingAssetsStr =
StreamingAssets.
Substring(
StreamingAssets.
LastIndexOf(
"\\") +
1);
string packetPath =
Application.
dataPath +
"/" +
streamingAssetsStr +
"/" +
target.
ToString() +
"/" +
resourcesStr.
ToLower();
//遍历 Assets\StreamingAssets\Android\resources 下的文件夹
//因为打出来的包并没有直接放在resources下,都是放在该文件夹里面的各个文件夹下
//所以需要再遍历resources下的各个文件夹
DirectoryInfo folder =
new
DirectoryInfo(
packetPath);
FileSystemInfo[] files =
folder.
GetFileSystemInfos();
for (
int i =
0;
i <
files.
Length;
i++)
{
Debug.
Log(
files[
i].
FullName);
if (
files[
i]
is
DirectoryInfo)
{
DirectoryInfo folder1 =
new
DirectoryInfo(
files[
i].
FullName);
FileSystemInfo[] files1 =
folder1.
GetFileSystemInfos();
for (
int n =
0;
n <
files1.
Length;
n++)
{
if (
files1[
n]
is
DirectoryInfo)
{
string configurationPath =
str +
"/" +
files1[
i].
Name +
".txt";
SetCon(
files1[
i].
FullName,
configurationPath);
}
}
}
}
}
///
<
summary
>
/// 向配置文件中写入ab包路径与标识 这里的标识是打包出来的.manifest文件里的CRC
///
</
summary
>
///
<
param
name
=
"path"
></
param
>
///
<
param
name
=
"textPath"
></
param
>
static
void
SetCon(
string path,
string textPath)
{
string content =
"";
string[] assetPath =
Directory.
GetFiles(
path,
"*.manifest",
SearchOption.
AllDirectories);
for (
int i =
0;
i <
assetPath.
Length;
i++)
{
content +=
assetPath[
i].
Replace(
Application.
dataPath.
Replace(
"/",
"\\") +
"\\",
"").
Replace(
".manifest",
"");
content +=
";";
content +=
File.
ReadAllLines(
assetPath[
i])[
1].
Replace(
"CRC:",
"").
Trim();
content +=
System.
Environment.
NewLine;
}
File.
WriteAllText(
textPath,
content);
}
}