首页 >Unity3D频道 >【Unity3D研究院之游戏开发】 > 飞书机器人发送unity手机中日志
2024
04-06

飞书机器人发送unity手机中日志

手机中可以通过 Application.logMessageReceivedThreaded来监听日志的信息,在通过File.AppendAllText来将日志写在手机的Application.persistentDataPath目录中。日志可以按天写入,这样即使游戏闪退也可以把当天产生的日志取出来。

测试机取日志很麻烦,出现问题的时候周围也不一定有电脑可以取,而且测试机上也不一定安装飞书企业微信这种软件,就算安装了使用者也未必会取,未必会发出来。所以我就想是否能利用飞书开发平台的API自动将这个文件发出来。

1.需要在飞书开放平台上创建一个企业自建机器人应用,并且开通上传文件和发送消息权限(需要企业管理员审核)

2.通过app id和app secret 获取token,上传文件,并且发送到指定的群聊中(需要提前将企业自建机器人加入群聊)

string logPath = $"{Application.persistentDataPath}/1.log";
File.WriteAllText(logPath, "unity中产生的日志");


Feishu.Send("appid",
    "appsecret",
    "群聊chatid",
logPath, () =>
{
    Debug.Log("发送成功");
}, (error) =>
{
    Debug.Log("发送失败");
});

群聊的chatid在飞书开发平台中获取。由于日志文件可能比较大,我还做了一次压缩,接口我已经封装好了,使用起来很方便。

using System;
using System.Collections;
using System.IO;
using System.IO.Compression;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

public class Feishu:MonoBehaviour
{
    static Feishu Inst;

    static Feishu()
    {
        Inst = new GameObject().AddComponent<Feishu>();
        GameObject.DontDestroyOnLoad(Inst.gameObject);
    }

    private const string REQUEST_TOKEN_URL =
        "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
    private const string REQUEST_UPLOADFILE_URL = "https://open.feishu.cn/open-apis/im/v1/files";
    private const string REQUEST_SENDCHAT_URL =
        "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id";
        
    /// <summary>
    /// 飞书聊天群发文件
    /// </summary>
    /// <param name="app_id">飞书平台id</param>
    /// <param name="app_secret">飞书平台secret</param>
    /// <param name="groupid">聊天窗口id</param>
    /// <param name="path">文件路径</param>
    /// <param name="success">成功</param>
    /// <param name="error">失败</param>
    public static void Send(string app_id, string app_secret, string groupid, string path, Action success,
        Action<string> error)
    {
        Inst.StartCoroutine(UploadFile(app_id, app_secret, groupid, path, success, error));
    }
        
    static IEnumerator UploadFile(string app_id, string app_secret,string groupid,string path,Action success, Action<string>error)
    {
        string tenant_access_token=null;
        string file_key = null;
        string json = $"{{"app_id":"{app_id}","app_secret":"{app_secret}"}}";
        bool isFinish = false;
        using (UnityWebRequest www = UnityWebRequest.Post(REQUEST_TOKEN_URL, json, ""))
        {
            www.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                error?.Invoke(www.error);
            }
            else
            {
                var token = JsonUtility.FromJson<Token>(www.downloadHandler.text);
                if (token.code == 0)
                {
                    tenant_access_token = token.tenant_access_token;
                }
                else
                {
                    error?.Invoke(www.downloadHandler.text);
                }
            }
        }

        if (!string.IsNullOrEmpty(tenant_access_token))
        {
            WWWForm from = new WWWForm();
            from.AddField("file_type", "stream");
            from.AddField("file_name", Path.GetFileNameWithoutExtension(path)+".zip");
            using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            using (var streamReader = new StreamReader(fileStream))
            {
                var txt = streamReader.ReadToEnd();
                using (var outStream = new MemoryStream())
                {
                    using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
                    {
                        var fileInArchive = archive.CreateEntry(Path.GetFileName(path));
                        using (var entryStream = fileInArchive.Open())
                        using (var fileToCompressStream = new MemoryStream(Encoding.UTF8.GetBytes(txt)))
                        {
                            fileToCompressStream.CopyTo(entryStream);
                        }
                    }
                    from.AddBinaryData("file",outStream.ToArray());
                }
            }
                
            using (UnityWebRequest www = UnityWebRequest.Post(REQUEST_UPLOADFILE_URL, from))
            {
                www.SetRequestHeader("Authorization", $"Bearer {tenant_access_token}");
                yield return www.SendWebRequest();
                if (www.result != UnityWebRequest.Result.Success)
                {
                    error?.Invoke(www.error);
                }
                else
                {
                    var file = JsonUtility.FromJson<FileKey>(www.downloadHandler.text);
                    if (file.code == 0)
                    {
                        Debug.Log(www.downloadHandler.text);
                        file_key = file.data.file_key;
                    }
                    else
                    {
                        error?.Invoke(www.downloadHandler.text);
                    }
                }
            }
        }

        if (!string.IsNullOrEmpty(file_key))
        {
            json = $"{{"receive_id": "{groupid}","content": "{{\"file_key\":\"{file_key}\"}}","msg_type": "file"}}";

            using (UnityWebRequest www = UnityWebRequest.Post(REQUEST_SENDCHAT_URL, json,""))
            {
                www.SetRequestHeader("Authorization", $"Bearer {tenant_access_token}");
                www.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
                yield return www.SendWebRequest();
                if (www.result != UnityWebRequest.Result.Success)
                {
                    error?.Invoke(www.error);
                }
                else
                {
                    var post = JsonUtility.FromJson<Post>(www.downloadHandler.text);
                    if(post.code == 0)
                    {
                        isFinish = true;
                          
                    }else
                        error?.Invoke(www.downloadHandler.text);
                }
            }
        }
        if (isFinish)
        {
            success?.Invoke();
        }
        else
        {
            error?.Invoke("未知");
        }
    }

    [System.Serializable]
    class Token
    {
        public int code;
        public string tenant_access_token;
    }

    [System.Serializable]
    class Data
    {
        public string file_key;
    }
    [System.Serializable]
    class FileKey
    {

        public int code;
        public Data data;
    }
    [System.Serializable]
    class Post
    {
        public int code;
    }
}

从此以后我们和测试、策划之间的沟通就变成了, “把日志发群里” 无论它手机是否出现过报错、闪退,当天的日志都会写在一个文件中发出来,有了这个小工具,极大的提高了我们的开发调Bug的效率。

飞书机器人发送unity手机中日志 - 雨松MOMO程序研究院 - 1

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

飞书机器人发送unity手机中日志》有 4 条评论

  1. Avalon说:

    感谢雨松,我也把流程跑通了,主要有几个问题处理了下
    1.需要注释掉以下代码,这会导致协议错误400
    http://www.SetRequestHeader(“Content-Type”, “application/json; charset=utf-8”);
    2.直接Post会提示属性错误,查了一下可能是URLEncode的问题,对应博主的文章在下面
    https://blog.csdn.net/qq_38721111/article/details/130242496

    • 雨松MOMO说:

      可能是unity版本问题吗? 我用的是unitiy2022.3.20f 目前这段代码在PC和手机上都没有问题。我也在关注下你说的问题。

      • Avalon说:

        我的是2021.3.19,有可能新版本对这些情况进行了处理,毕竟我查下来发现还是不少这个问题的讨论的。而且post的接口也不太一样,你的代码里面多了第三个空字符串的参数,2021里只有两个参数

留下一个回复

你的email不会被公开。 必填项已用 * 标注。