介绍

官网介绍:

UWA旨在诊断与优化游戏和VR项目开发过程中潜在的运行性能问题,帮助项研发团队快速检测项目运行时的性能瓶颈,高效定位问题根源,及时反馈针对瓶颈问题的深度分析和解决方法。

UWA 提供两种 SDK,一种用来提交后测试,一种本地测试后提交。但是这两种 SDK 内容不同,打包时不能放在一起,需要分开打包。

另外,由于 UWA 主要用作测试,因此不想将资源放到项目内,否则打包时会有多余资源,增大包体。

因此最终的需求就是可以一键自动打包。

环境

  • macOS 10.14.6
  • Unity 5.6.6f2
  • UWA v1.2.3
  • UWA GOT v1.2.9

手动流程

测试

首先手动打包一次,了解整个流程并测试打出的包是否正常:

  1. 导入 UWA 资源包
  2. 在初始化场景中增加 UWA Prefab
  3. 修改项目设置
  4. 打包

确定好流程后就可以编写编辑器脚本初步集成了。

编辑器脚本

由于需要导入资源包之后再进行集成,尝试使用 AssetDatabase.importPackageCompleted 设置导入完成后回调,结果发现由于 UWA 中带有 DLL,导入时会导致重新编译,因此在导入完成回调没有执行。

尝试将脚本放在 Assets/Plugins/Editor 目录中优先编译不行。

尝试 EditorApplication.LockReloadAssemblies(); 之后处理,等待处理完成后调用 EditorApplication.UnlockReloadAssemblies(); 恢复,测试发现 API 无法阻止导入 Package 之后的编译。

最终需要在构建流程中将其拆分为两步,第一步导入 Package,第二步集成。必须手动点击,等待导入与编译完成之后再执行下一步。

自动流程

需要根据项目需要增加自动打包流程。

导入资源包

Unity Package

UWA 以 Unity Package 发布资源包。

尝试在启动 Unity 时指定 -importpackage path 参数来导入资源,测试后发现未导入资源。

又尝试运行 Unity 后使用 AssetDatabase.ImportPackage API 导入资源包,结果还是无法导入资源。

Zip

最终尝试使用 zip 文件存储 UWA 资源,同时将不需要的 meta 文件删除,如 Plugins.meta Plugins/Android.meta

使用命令行压缩:

1
zip -r ../UWAv1.2.3_Android.zip .

注意:

  1. 不要使用软件压缩完成后再手动打开压缩包删除不用的文件,使用 SharpZipLib 解压时会有报错(如 eZip)。
  2. 不要使用 macOS 右键菜单自带的压缩功能,因为会加入无用的 __MACOSX 目录。

SharpZipLib 推荐使用的 FastZip 无法正确在 macOS 上解压目录,因此需要使用普通方式解压,具体参考:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void ExtractZipFile(string archiveFilenameIn, string outFolder) {
    ZipFile zf = null;
    try {
        var fs = File.OpenRead(archiveFilenameIn);
        zf = new ZipFile(fs);
        foreach (ZipEntry zipEntry in zf) {
            if (!zipEntry.IsFile) {
                continue;			// Ignore directories
            }
            string entryFileName = zipEntry.Name;

            byte[] buffer = new byte[4096];		// 4K is optimum
            var zipStream = zf.GetInputStream(zipEntry);

            // Manipulate the output filename here as desired.
            string fullZipToPath = Path.Combine(outFolder, entryFileName);
            string directoryName = Path.GetDirectoryName(fullZipToPath);
            if (!string.IsNullOrEmpty(directoryName) && directoryName.Length > 0)
                Directory.CreateDirectory(directoryName);

            using (var streamWriter = File.Create(fullZipToPath)) {
                StreamUtils.Copy(zipStream, streamWriter, buffer);
            }
        }
    } finally {
        if (zf != null) {
            zf.IsStreamOwner = true; // Makes close also shut the underlying stream
            zf.Close(); // Ensure we release resources
        }
    }
}

修改配置

按照文档要求直接修改配置即可:

1
2
3
4
5
6
7
8
public static void ChangeBuildSettings()
{
    EditorUserBuildSettings.development = true;
    PlayerSettings.Android.forceSDCardPermission = true;
    PlayerSettings.SetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup,
        ScriptingImplementation.Mono2x);
    AssetDatabase.SaveAssets();
}

撤消导入资源包

在打包完成后需要恢复现场,因此将刚才解压出来的 UWA 资源删除掉,只需要遍历压缩包,将对应的文件删除即可。

正确做法是在解压前先保存要被覆盖的文件,撤消时恢复被覆盖的文件。这里并没有非常严谨,考虑到 UWA 使用的路径几乎不存在同名的其他资源。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void RemoveExtractedFiles(string archiveFilenameIn, string outFolder) {
    ZipFile zf = null;
    try {
        var fs = File.OpenRead(archiveFilenameIn);
        zf = new ZipFile(fs);
        foreach (ZipEntry zipEntry in zf) {
            if (!zipEntry.IsFile) {
                continue;			// Ignore directories
            }

            string entryFileName = zipEntry.Name;
            string fullZipToPath = Path.Combine(outFolder, entryFileName);

            if (File.Exists(fullZipToPath))
            {
                File.Delete(fullZipToPath);
            }
        }
    } finally {
        if (zf != null) {
            zf.IsStreamOwner = true; // Makes close also shut the underlying stream
            zf.Close(); // Ensure we release resources
        }
    }
}

结果

按照以上方式处理后就可以将其集成到打包方法内,可以结合 Jenkins 自动构建,而且可以同时打包 UWA 线上测试包与线下测试包。