UWA Pipeline 使用前的准备工作

发布时间 2023-04-12 15:39:54作者: lac_123_1234

Pipeline1 简介

后面简称为 ppl

ppl 是集合了目前 UWA所有产品功能为一身的工具,可以用很小的成本,从一些真机自动化等机械性重复性劳动中解放出来,如:自动化性能测试、可靠性真机测试等等,当然里面功能很多,如果不了解 ppl,推荐去官网1 了解一下具体功能,或者找 UWA 的工作人员申请一下试用

目前整体使用下来,对我们项目而言,最重要的是解放重复性劳动,以及整体项目的性能把控上。比如在还没有跑 GOT 性能测试之前,我就可以精准预测游戏性能瓶颈到底在什么地方,这种对项目整体心中有数,会让人感觉非常靠得住

目标 & 背景

  • Airtest 调用 GM 指令
  • SDK 动态剔除

老样子,我们还是从需求和背景开始,由于我们游戏目前的限制,需要在自动化测试开始之前,先执行一些游戏框架中的代码,才能开始进行测试,再加上我们游戏中使用的 GM 工具是 IngameDebugConsole2,所以必须要解决代码复用问题

除此之外,在我们正常打包时,仅在自动化性能测试这个场景下才会加载 UWA 相关的代码,普通 dev 并不会,而且在 Release 环境下,UWA 代码和 IngameDebugConsole2 相关代码也需要完全裁剪,因此 SDK 动态剔除也是很有必要的

具体实现

这里非常感谢 UWA 的工程师解答了我接入时遇到的问题,节省了我不少时间~

首先说一下这里的过程,我们需要在 Airtest 中的 py 脚本直接调用 C# 的代码,而两者之间的通讯用到了 Poco3 组件的 rpc 功能,根据我们传入的字符串对执行内容进行分发

这里必须要吐槽一下 Poco3 rpc 的设计,最开始看到 rpc attribute 我以为框架内部已经做了自动扫描,没想到居然还需要手动添加指令,这样我们每增加一个指令都需要入侵 SDK 的源码

那么我们第一个要解决的问题就是现有 Poco3 设计缺陷问题

Poco 事件分发

这里思路也很简单,需要注意的是,我们这里还有 SDK 动态剔除的问题需要解决,那么需要做到只要这个代码被打进这个包,业务逻辑不需要做任何额外的事情,这个 SDK 就可以自动开启,这样就是一个懂事的 SDK,自己管自己

public static class SDKSelfInit
{
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
    private static void _Init()
    {
        EventSystem.Instance.Add(typeof(SDKSelfInit).Assembly);
    }
}

这里我们利用了 ET4 中跨域调用的机制,如果你的项目并没有使用 ET4 自己实现一个回调即可

紧接着我们定义一个从业务逻辑分发的 GMCodeEvent 和 AfterUpdateCheck,在合适的时机对 SDK 具体的逻辑进行初始化

namespace EventType
{
    public struct AfterUpdateCheck
    {
    }
public struct GMCodeEvent
{
    public string command;
}

}

这里的 AfterUpdateCheck 调用时,会对 SDK 进行初始化,如 GM 工具的加载、UWA 的初始化等等,而另一个 GMCodeEvent,作为通用的 GM 指令调用实现,这里特指 Poco 调用 GM 指令

接着我们要对这两个事件写具体的实现,没啥可说的,代码也很简单,主要是 command 要转给 IngameDebugConsole2

public class AfterUpdateCheck_InitPoco : AEvent<EventType.AfterUpdateCheck>
{
    protected override UniTask Run(EventType.AfterUpdateCheck args)
    {
        // 这里可以考虑增加强制验证
        // if(!valid) return;
    var go = new GameObject();

    go.AddComponent&lt;PocoManager&gt;();

    Object.DontDestroyOnLoad(go);

    return UniTask.CompletedTask;
}

}

public class PocoEvent_Handle : AEvent<EventType.GMCodeEvent>
{
protected override UniTask Run(EventType.GMCodeEvent args)
{
DebugLogConsole.ExecuteCommand(args.command);
return UniTask.CompletedTask;
}
}

最后我们需要在 Poco3 源码中增加执行 GM 事件的注册代码,这里也是唯一一处我们需要入侵 SDK 的地方

public class PocoManager : MonoBehaviour
{
    void Awake()
    {
        // ...
        rpc.addRpcMethod("Publish", Publish);
        // ...
    }
// 我不理解这个 RPC 的 attribute 到底是干嘛的
// 为了保持一致还是加上吧
[RPC]
private object Publish(List&lt;object&gt; param)
{
    EventSystem.Instance.Publish(new EventType.GMCodeEvent {command = param[0] as string}).ForgetLog(&quot;Poco&quot;);

    return param[0];
}

}

Airtest 调用

首先我们将如下代码写在 UWA.py 脚本中,作为一个项目标准实现

@sync_wrapper
def PublishGM(pocoHdl, command):
    # 此处 Publish 对应的就是 PocoManager 中的 Publish 函数
    return pocoHdl.agent.c.call("Publish", command)

具体调用方式如下

# 导入UWA模块
from UWA import *
poco = UnityPoco()

这里的 GM 指令就和 IngameDebugConsole 的调用保持一致了

比如你有一个名为 test 的指令,包含一个参数 int a

那么此时填写 "test 1" 即可

command=PublishGM(poco, "GM指令")
log(command)

这样我们就打通了从 python 直接调用项目中现有 GM 指令的整体流程,既保证对 SDK 入侵较小、方便扩展的同时,也完全利用了目前 GM 指令的所有设计,如果 Poco3 自己实现了扫描,我们连代码都不需要侵入,我这也是懒得写扫描,用最小成本先实现功能

SDK 动态剔除

动态剔除的原理非常简单,根据打包参数在指定目录名追加 ~ 即可,或者从外部拷入、内部删除等方案都是可以的,这里我们项目使用的方案就是追加 ~

但是无论哪种我们都需要对目录进行规划,下方为我们当前目录规划的参考:

Plugins/DynamicSDK
# GM 的原生代码
├── IngameDebugConsole
├── IngameDebugConsole.meta
├── Custom.SDK
        # GM 的初始化等
│   ├── IngameDebugConsole
│   ├── IngameDebugConsole.meta
│   ├── Custom.SDK.asmdef
│   ├── Custom.SDK.asmdef.meta
        # Poco 的初始化等
│   ├── Poco
│   ├── Poco.meta
        # 动态 SDK 自启代码
│   ├── SDKSelfInit.cs
│   ├── SDKSelfInit.cs.meta
        # UWA 的初始化等
│   ├── UWA
│   ├── UWA.meta
├── Custom.SDK.meta
# Poco 的原生代码
├── Poco
├── Poco.meta
# SDK 中需要动态加载的资源
├── Res
        # GM Prefab 存放位置
│   ├── IngameDebugConsole
│   └── IngameDebugConsole.meta
├── Res.meta
# UWA 的原生代码
├── UWA
└── UWA.meta

按照这个规划,我们需要对如下三个目录进行动态剔除

  • Assets/Plugins/DynamicSDK
  • Assets/Plugins/DynamicSDK/Custom.SDK
  • Assets/Plugins/DynamicSDK/Res

剩下的实现过程就非常简单了,根据参数判断是否存在,然后改名即可

在具体实现时,我们碰到一个问题,GOT 并不支持安卓 29~30,而切换时,需要手动点一下 UWA 提供的工具,才可以打包

适配 uwa.aar

这里我们需要用到如下命令

unzip uwa.aar -d tempFolder
# 修改文件后,重新打回 aar
jar cvf new-uwa.aar -C tempFolder/ .

把 AndroidManifest.xml 最后的 application 修改一下即可

<application>
    <service
        android:name="com.uwa.uwascreen.CaptureScreenService"
        android:enabled="true" />
</application>

最后

这样我们就完成了 ppl 针对 GOT 自动化的前期准备工作,更具体的 ppl 使用后续会开新的文章进行介绍

参考

  1. ppl 官网地址:https://www.uwa4d.com/pipeline/UWAPipeline.html 2

  2. IngameDebugConsole: https://github.com/yasirkula/UnityIngameDebugConsole 2 3

  3. Poco: https://github.com/AirtestProject/Poco-SDK 2 3 4 5

  4. ET: https://github.com/egametang/ET 2