1. 需求
每次将资源打包成Bundle包或者需要将某些文件上传到对象存储桶中,都需要打开腾讯云或是其它第三方平台然后将文件上传到指定目录。上述操作自我感觉比较麻烦于是该工具就诞生了,在打包完资源后在Unity内部就能实现上传。当然你也可以在Unity内部上传任何你想上传的文件,也提供上传文件夹下的所有内容
2. 使用教程
1. 第一次使用需要进行一些基本的配置具体如下
2. 选择文件可以通过拖拽到指定区域或者点击选择文件、选择文件夹都可以实现,选择完成之后要上传的文件信息会在下方的上传文件列表中显示
2.1 如果是Project面板下的文件,点击名称会锁定该文件在Project面板中的具体位置,点击移除按钮则在文件列表删除该文件
3. 选择完文件后点击上传按钮即可,上传完成会弹出提示框
4. 当然你也可以对上传到存储桶中的数据进行操作,点击获取存储桶数据就可以看到你上传的内容,你可以选择单个移除亦或是选择清除该文件夹下的所有数据
3. 示例代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;
public class FileUploader : EditorWindow
{
private readonly List<FileModel> uploadFileList = new List<FileModel>();
private readonly List<FileModel> cloudFileList = new List<FileModel>();
private TencentCloudCosOperation tencentCloudCos;
private bool isUploading = false;
private Vector2 uploadScrollPos = Vector2.zero; // 滚动条位置
private Vector2 cloudScrollPos = Vector2.zero; // 滚动条位置
public bool isSettingData = false;
[MenuItem("Tools/File Uploader")]
public static void ShowWindow()
{
EditorWindow.GetWindow<FileUploader>("Upload Bundle");
}
private void OnEnable()
{
isUploading = false;
isSettingData = EditorPrefs.GetBool("SettingData", false);
if (isSettingData)
{
tencentCloudCos = new TencentCloudCosOperation(
EditorPrefs.GetString("Region"),
EditorPrefs.GetString("BucketName"),
EditorPrefs.GetString("SecretId"),
EditorPrefs.GetString("SecretKey"),
EditorPrefs.GetString("SavePath"));
}
}
private void OnGUI()
{
if (isSettingData)
{
DrawUploadArea();
DrawFileList("上传文件列表", uploadFileList, ref uploadScrollPos, drawOther: DrawUploadListButtons);
DrawFileList("云存储桶文件列表", cloudFileList, ref cloudScrollPos, (file) =>
{
Debug.Log("删除文件:" + file.path);
tencentCloudCos.DeleteObject(file.path);
}, DrawCloudBucketListButtons);
}
else
{
DrawSettingPanel();
}
}
#region 配置数据
private string region = "";
private string bucketName = "";
private string secretId = "";
private string secretKey = "";
private string savePath = "";
/// <summary>
/// 绘制配置面板
/// </summary>
private void DrawSettingPanel()
{
#region 配置数据
GUIStyle loginStyle = new GUIStyle
{
padding = new RectOffset(10, 10, 10, 10),
};
GUIStyle labelStyle = new GUIStyle
{
fontStyle = FontStyle.Bold,
fontSize = 18,
alignment = TextAnchor.MiddleCenter,
padding = new RectOffset(0, 0, 8, 8),
normal = new GUIStyleState
{ textColor = Color.white }
};
GUILayout.Label("配置信息", labelStyle);
GUILayout.BeginVertical(loginStyle);
bucketName = EditorGUILayout.TextField("存储桶名称", bucketName);
region = EditorGUILayout.TextField("所属地域", region);
secretId = EditorGUILayout.TextField("SecretId", secretId);
secretKey = EditorGUILayout.TextField("SecretKey", secretKey);
savePath = EditorGUILayout.TextField("存储路径", savePath);
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace(); // 左侧空白区域
if (GUILayout.Button("保存", GUILayout.Width(150)))
{
// 判断region是否为空
if (region != "" && bucketName != "" && secretId != "" && secretKey != "")
{
EditorPrefs.SetString("Region", region);
EditorPrefs.SetString("BucketName", bucketName);
EditorPrefs.SetString("SecretId", secretId);
EditorPrefs.SetString("SecretKey", secretKey);
EditorPrefs.SetString("SavePath", savePath);
EditorPrefs.SetBool("SettingData", true);
tencentCloudCos = new TencentCloudCosOperation(region, bucketName, secretId, secretKey, savePath);
isSettingData = true;
}
else
{
EditorUtility.DisplayDialog("提示", "请填写完整的配置信息", "确定");
}
}
GUILayout.FlexibleSpace(); // 右侧空白区域
GUILayout.EndHorizontal();
DrawPromptInfo();
GUILayout.EndVertical();
#endregion
}
#endregion
/// <summary>
/// 绘制提示信息
/// </summary>
void DrawPromptInfo()
{
#region 提示信息
GUIStyle tipStyle = new GUIStyle
{
fontStyle = FontStyle.Bold,
fontSize = 14,
alignment = TextAnchor.UpperLeft,
padding = new RectOffset(0, 0, 5, 5),
normal = new GUIStyleState
{ textColor = Color.green },
fixedWidth = 200f,
};
GUILayout.BeginVertical();
if (GUILayout.Button("所属地域:点击获取参考", tipStyle))
{
Application.OpenURL("https://cloud.tencent.com/document/product/436/6224");
}
if (GUILayout.Button("存储桶名称:点击获取参考", tipStyle))
{
Application.OpenURL("https://console.cloud.tencent.com/cos5/bucket");
}
if (GUILayout.Button("SecretId SecretKey:点击获取参考", tipStyle))
{
Application.OpenURL("https://console.cloud.tencent.com/cam/capi");
}
GUILayout.Button("存储路径:将对象上传到指定的文件夹或路径,可通过/实现,例如将 picture.png 上传到 doc/images 文件夹,设置为 doc/images", tipStyle);
GUILayout.Button("最大支持上传5GB文件", tipStyle);
GUILayout.EndVertical();
#endregion
}
/// <summary>
/// 绘制上传区域
/// </summary>
private void DrawUploadArea()
{
#region 上传区域
DrawLabel("上传区域", DrawUploadAreaButtons);
GUILayout.BeginHorizontal("box");
Event evt = Event.current;
Rect dropArea = GUILayoutUtility.GetRect(0.0f, 150.0f, GUILayout.ExpandWidth(true));
DrawUploadAreaIcon(dropArea);
GUI.Box(dropArea, "");
if (evt.type == EventType.DragUpdated)
{
if (dropArea.Contains(evt.mousePosition))
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
evt.Use();
}
}
else if (evt.type == EventType.DragPerform)
{
if (dropArea.Contains(evt.mousePosition))
{
DragAndDrop.AcceptDrag();
foreach (string draggedPath in DragAndDrop.paths)
{
if (Directory.Exists(draggedPath))
{
string[] filesInDirectory = Directory.GetFiles(draggedPath);
foreach (string filePath in filesInDirectory)
{
if (!filePath.EndsWith(".meta"))
{
if (File.Exists(filePath))
{
var model = uploadFileList.Find(m => m.path == filePath);
if (model == null)
{
uploadFileList.Add(new FileModel()
{
name = Path.GetFileName(filePath),
path = filePath,
});
}
}
}
}
}
else if (File.Exists(draggedPath) && !draggedPath.EndsWith(".meta"))
{
var model = uploadFileList.Find(m => m.path == draggedPath);
if (model == null)
{
uploadFileList.Add(new FileModel()
{
name = Path.GetFileName(draggedPath),
path = draggedPath,
});
}
}
}
evt.Use();
}
}
GUILayout.EndHorizontal();
#endregion
}
/// <summary>
/// 绘制上传区域Icon
/// </summary>
/// <param name="dropArea"></param>
private void DrawUploadAreaIcon(Rect dropArea)
{
#region 绘制ICON
Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>($"{GetIconPath($"{nameof(FileUploader)}.cs")}/Icons/UploadIcon.png");
float iconSize = 64f;
float iconX = dropArea.x + (dropArea.width - iconSize) / 2;
float iconY = dropArea.y + (dropArea.height - iconSize) / 2;
GUI.DrawTexture(new Rect(iconX, iconY - 20f, iconSize, iconSize), icon);
// 添加文字
string text = "将文件拖拽到此处";
GUIStyle style = new GUIStyle(GUI.skin.label)
{
alignment = TextAnchor.MiddleCenter,
fontSize = 15,
fontStyle = FontStyle.Bold,
};
float textY = (iconY + iconSize) - 15f;
GUI.Label(new Rect(dropArea.x, textY, dropArea.width, 20f), text, style);
#endregion
}
private string GetIconPath(string scriptFileName)
{
string[] scriptPaths = Directory.GetFiles(Application.dataPath, scriptFileName, SearchOption.AllDirectories);
if (scriptPaths.Length > 0)
{
string absolutePath = scriptPaths[0];
string relativePath = "Assets" + absolutePath.Substring(Application.dataPath.Length);
return Path.GetDirectoryName(relativePath);
}
else
{
return string.Empty;
}
}
/// <summary>
/// 绘制文件列表
/// </summary>
/// <param name="titleName"></param>
/// <param name="fileList"></param>
/// <param name="scrollPos"></param>
/// <param name="removeCallback"></param>
/// <param name="drawOther"></param>
private void DrawFileList(string titleName, List<FileModel> fileList, ref Vector2 scrollPos,
Action<FileModel> removeCallback = null, Action drawOther = null)
{
#region 文件列表
GUIStyle fileListStyle = new GUIStyle(GUI.skin.label)
{
name = "box",
padding = new RectOffset(10, 10, 10, 10)
};
DrawLabel(titleName, drawOther);
GUILayout.BeginHorizontal(fileListStyle);
// 创建可滚动区域
scrollPos =
GUILayout.BeginScrollView(scrollPos, GUILayout.Height(150), GUILayout.ExpandWidth(true));
for (int i = 0; i < fileList.Count; i++)
{
GUILayout.BeginHorizontal("box");
if (GUILayout.Button(
fileList[i].name.Substring(0, Mathf.Min(fileList[i].name.Length, 20)) +
(fileList[i].name.Length > 20 ? "..." : ""), EditorStyles.boldLabel)) // 文件名作为按钮
{
string path = fileList[i].path;
Object obj = AssetDatabase.LoadAssetAtPath<Object>(path);
EditorGUIUtility.PingObject(obj); // 选中文件
}
GUILayout.Label("路径: " + fileList[i].path, EditorStyles.boldLabel);
if (GUILayout.Button("移除", GUILayout.Width(60))) // 设置按钮宽度为60
{
removeCallback?.Invoke(fileList[i]);
RemoveFile(fileList, i);
}
GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
GUILayout.EndHorizontal();
#endregion
}
/// <summary>
/// 绘制上传区域功能按钮
/// </summary>
void DrawUploadAreaButtons()
{
if (GUILayout.Button("上传", GUILayout.Width(100)) && !isUploading)
{
int index = 0;
int fileCount = uploadFileList.Count;
if (tencentCloudCos != null && fileCount > 0)
{
isUploading = true;
EditorApplication.update = () =>
{
if (index < fileCount)
{
tencentCloudCos.PutObject(uploadFileList[index].name, uploadFileList[index].path, (progress) =>
{
bool isCancel =
EditorUtility.DisplayCancelableProgressBar("上传进度", uploadFileList[index].name,
progress / 100f);
if (isCancel || progress >= 100f)
{
EditorUtility.ClearProgressBar();
index++;
if (index >= fileCount)
{
EditorUtility.DisplayDialog("提示", "所有文件上传完成", "确定");
uploadFileList.Clear();
EditorApplication.update = null; // 取消回调函数
isUploading = false;
}
}
});
}
};
}
}
if (GUILayout.Button("选择文件夹", GUILayout.Width(100)))
{
string path = EditorUtility.OpenFolderPanel("选择文件", "", "");
if (!string.IsNullOrEmpty(path))
{
string[] files = Directory.GetFiles(path);
foreach (var file in files)
{
uploadFileList.Add(new FileModel()
{
name = Path.GetFileName(file),
path = file
});
}
}
}
// 选择文件
if (GUILayout.Button("选择文件", GUILayout.Width(100)))
{
string path = EditorUtility.OpenFilePanel("选择文件", "所有文件", "");
if (!string.IsNullOrEmpty(path))
{
uploadFileList.Add(new FileModel()
{
name = Path.GetFileName(path),
path = path
});
}
}
if (GUILayout.Button("清除配置数据", GUILayout.Width(100)))
{
EditorPrefs.DeleteKey("Region");
EditorPrefs.DeleteKey("BucketName");
EditorPrefs.DeleteKey("SecretId");
EditorPrefs.DeleteKey("SecretKey");
EditorPrefs.DeleteKey("SettingData");
EditorPrefs.DeleteKey("SavePath");
isSettingData = false;
}
}
/// <summary>
/// 绘制上传列表功能按钮
/// </summary>
private void DrawUploadListButtons()
{
if (GUILayout.Button("清空上传列表", GUILayout.Width(100)))
{
uploadFileList.Clear();
}
}
/// <summary>
/// 绘制云存储桶列表功能按钮
/// </summary>
void DrawCloudBucketListButtons()
{
if (GUILayout.Button("获取存储桶数据", GUILayout.Width(100)))
{
if (tencentCloudCos != null)
{
tencentCloudCos.GetBucketData(EditorPrefs.GetString("SavePath"), (contentsList) =>
{
if (contentsList.Count > 1)
{
foreach (var item in contentsList.Where(item =>
item.key.Substring(item.key.LastIndexOf("/", StringComparison.Ordinal) + 1) != ""))
{
if (cloudFileList.Find(file =>
file.name ==
item.key.Substring(item.key.LastIndexOf("/", StringComparison.Ordinal) + 1)) ==
null)
{
cloudFileList.Add(new FileModel()
{
name = item.key.Substring(item.key.LastIndexOf("/", StringComparison.Ordinal) + 1),
path = item.key
});
}
}
}
else
{
EditorUtility.DisplayDialog("提示", "没有可访问的数据", "确定");
}
});
}
}
if (GUILayout.Button("清空存储桶", GUILayout.Width(100)))
{
if (tencentCloudCos != null && cloudFileList.Count > 0)
{
bool isConfirm = EditorUtility.DisplayDialog("提示", $"此操作会删除{EditorPrefs.GetString("SavePath")}存储桶下的所有文件,是否确认", "确定","取消");
if (isConfirm)
{
foreach (var file in cloudFileList)
{
tencentCloudCos.DeleteObject(file.path, () =>
{
EditorUtility.DisplayCancelableProgressBar("删除进度", file.name,
100 / 100f);
});
}
cloudFileList.Clear();
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("提示", "所有文件删除完成", "确定");
}
}
}
}
private void RemoveFile(List<FileModel> fileList, int index)
{
fileList.RemoveAt(index);
}
[System.Serializable]
public class FileModel
{
public string name;
public string path;
}
/// <summary>
/// 绘制标签
/// </summary>
/// <param name="titleName">标签名称</param>
/// <param name="drawOther">标签后的内容</param>
void DrawLabel(string titleName, Action drawOther = null)
{
GUIStyle horizontalStyle = new GUIStyle(GUI.skin.label)
{
padding = new RectOffset(10, 10, 10, 10),
alignment = TextAnchor.MiddleCenter,
};
GUIStyle labelStyle = new GUIStyle(GUI.skin.label)
{
fontStyle = FontStyle.Bold,
normal = new GUIStyleState() { textColor = Color.white }
};
GUILayout.BeginHorizontal(horizontalStyle);
GUILayout.Label(titleName, labelStyle);
drawOther?.Invoke();
GUILayout.EndHorizontal();
}
}