SDK_UnityMoney/Assets/Editor/PackageExporter.cs

273 lines
10 KiB
C#
Raw Normal View History

2025-11-10 04:31:21 +00:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
public class PackageExporter
{
/// <summary>
/// 导出 UnityPackage支持忽略特定文件
/// </summary>
/// <param name="assetPaths">需要导出的资源路径数组(文件夹或文件)</param>
/// <param name="outputPath">导出文件路径(含.unitypackage扩展名</param>
/// <param name="ignorePatterns">需要忽略的文件/文件夹模式数组</param>
/// <param name="includeDependencies">是否包含依赖资源</param>
/// <param name="recurseFolders">是否递归导出文件夹内的所有内容</param>
/// <returns>导出是否成功</returns>
private static bool ExportUnityPackage(
string[] assetPaths,
string outputPath,
string[] ignorePatterns = null,
bool includeDependencies = true,
bool recurseFolders = true
)
{
// 1. 验证资源路径
if (!ValidateAssetPaths(assetPaths))
{
Debug.LogError("导出失败:无效的资源路径");
return false;
}
// 2. 验证输出路径
if (!ValidateAndPrepareOutputPath(outputPath))
{
Debug.LogError("导出失败:无效的输出路径");
return false;
}
try
{
// 3. 处理需要导出的路径(过滤掉需要忽略的文件)
var temp = ProcessAssetPaths(assetPaths, ignorePatterns, recurseFolders);
var filteredPaths = temp.Where(File.Exists).ToArray();
if (filteredPaths.Length == 0)
{
Debug.LogError("导出失败:所有路径都被过滤掉了");
return false;
}
// 4. 构建导出选项
ExportPackageOptions options = ExportPackageOptions.Default;
// 如果需要递归文件夹,添加 Recurse 选项
if (recurseFolders)
{
options |= ExportPackageOptions.Recurse;
}
// 如果需要包含依赖资源,添加 IncludeDependencies 选项
if (includeDependencies)
{
options |= ExportPackageOptions.IncludeDependencies;
}
// 5. 执行导出
AssetDatabase.ExportPackage(filteredPaths, outputPath, options);
// 6. 验证结果
if (File.Exists(outputPath))
{
Debug.Log($"导出成功:{outputPath}");
return true;
}
Debug.LogError("导出失败:文件未生成");
return false;
}
catch (Exception ex)
{
Debug.LogError($"导出异常:{ex.Message}");
return false;
}
}
/// <summary>
/// 处理资源路径,过滤掉需要忽略的文件
/// </summary>
private static string[] ProcessAssetPaths(string[] assetPaths, string[] ignorePatterns, bool recurseFolders)
{
if (ignorePatterns == null || ignorePatterns.Length == 0)
{
return assetPaths; // 没有需要忽略的模式,直接返回原路径
}
// 收集所有需要导出的文件路径
var allFiles = new System.Collections.Generic.List<string>();
foreach (var path in assetPaths)
{
if (AssetDatabase.IsValidFolder(path))
{
// 如果是文件夹,获取所有文件
var filesInFolder = AssetDatabase.FindAssets("", new[] { path })
.Select(AssetDatabase.GUIDToAssetPath)
.ToArray();
// 根据递归选项和忽略模式过滤文件
allFiles.AddRange(filesInFolder.Where(file => !ShouldIgnore(file, ignorePatterns) && (recurseFolders || Path.GetDirectoryName(file) == path)));
var googleMobileAdsAndroidLib = Directory.GetDirectories(path, "GoogleMobileAdsPlugin", SearchOption.AllDirectories)
.Where(p => p.Replace("\\", "/").StartsWith("Assets/"))
.Select(p => p.Replace("\\", "/"))
.ToArray();
Debug.Log("yangwu firebase:"+googleMobileAdsAndroidLib);
allFiles.AddRange(googleMobileAdsAndroidLib);
}
else if (File.Exists(path))
{
// 如果是文件,检查是否需要忽略
if (!ShouldIgnore(path, ignorePatterns))
{
allFiles.Add(path);
}
}
var androidLibs = Directory.GetDirectories(path, "GoogleMobileAdsPlugin.androidlib", SearchOption.AllDirectories)
.Where(p => p.Replace("\\", "/").StartsWith("Assets/"))
.Select(p => p.Replace("\\", "/"))
.ToArray();
allFiles.AddRange(androidLibs);
}
return allFiles.Distinct().ToArray();
}
/// <summary>
/// 检查文件是否应该被忽略
/// </summary>
private static bool ShouldIgnore(string filePath, string[] ignorePatterns)
{
if (!ignorePatterns.Any(pattern => filePath.Contains(pattern) ||
Path.GetFileName(filePath).Contains(pattern) ||
(pattern.Contains("*") && MatchesWildcard(filePath, pattern)))) return false;
Debug.Log("ShouldIgnore true: " + filePath);
return true;
}
/// <summary>
/// 检查文件路径是否匹配通配符模式(使用正则表达式实现)
/// </summary>
private static bool MatchesWildcard(string filePath, string pattern)
{
try
{
// 将通配符模式转换为正则表达式
var regexPattern = "^" + Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$";
var regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
// 检查文件名和完整路径是否匹配
return regex.IsMatch(Path.GetFileName(filePath)) || regex.IsMatch(filePath);
}
catch
{
return false;
}
}
// 以下为辅助方法
private static bool ValidateAssetPaths(string[] assetPaths)
{
if (assetPaths == null || assetPaths.Length == 0)
{
Debug.LogWarning("未指定任何资源路径");
return false;
}
foreach (var path in assetPaths)
{
if (string.IsNullOrWhiteSpace(path) || !path.StartsWith("Assets/"))
{
Debug.LogWarning($"无效路径格式:{path}(必须以 Assets/ 开头)");
return false;
}
if (AssetDatabase.IsValidFolder(path) || File.Exists(path)) continue;
Debug.LogWarning($"路径不存在:{path}");
return false;
}
return true;
}
private static bool ValidateAndPrepareOutputPath(string outputPath)
{
if (string.IsNullOrWhiteSpace(outputPath) || !outputPath.EndsWith(".unitypackage"))
{
Debug.LogWarning("输出路径必须包含 .unitypackage 扩展名");
return false;
}
var directory = Path.GetDirectoryName(outputPath);
if (Directory.Exists(directory)) return true;
try
{
if (directory == null)
{
return false;
}
Directory.CreateDirectory(directory);
}
catch (Exception ex)
{
Debug.LogError($"无法创建目录:{ex.Message}");
return false;
}
return true;
}
// ------------------------------
// 快捷导出示例(可直接在菜单调用)
// ------------------------------
[MenuItem("Tools/Export UnityPackage")]
public static void ExportExamplePackage()
{
var pathsToExport = new[]
{
"Assets/Adjust",
"Assets/BigoAds",
"Assets/BigoSDK",
"Assets/Editor",
"Assets/Editor Default Resources",
"Assets/ExternalDependencyManager",
"Assets/EFSDK",
"Assets/Firebase",
"Assets/GeneratedLocalRepo",
"Assets/GoogleMobileAds",
"Assets/KwaiAds",
"Assets/MaxSdk",
"Assets/Plugins",
"Assets/Script",
"Assets/ThinkingAnalytics",
"Assets/ThinkupTpnPlugin",
"Assets/UnityPackages"
};
// 定义需要忽略的文件/文件夹模式
var ignorePatterns = new[]
{
"Assets/Plugins/Android/AndroidManifest.xml",
"Assets/Plugins/Android/baseProjectTemplate.gradle",
"Assets/Plugins/Android/gradleTemplate.properties",
"Assets/Plugins/Android/LauncherManifest.xml",
"Assets/Plugins/Android/launcherTemplate.gradle",
"Assets/Plugins/Android/mainTemplate.gradle",
"Assets/Plugins/Android/MessagingUnityPlayerActivity.java",
"Assets/Plugins/Android/settingsTemplate.gradle",
};
// 获取项目根目录Assets文件夹的上级目录
var projectRoot = Path.GetFullPath(Path.Combine(Application.dataPath, ".."));
var outputPath = Path.Combine(projectRoot, $"RushSDK_{RushSDKManager.GetSDKVersion()}_{DateTime.Now:yyyyMMdd_HHmmss}.unitypackage");
// 执行导出(不包含依赖,使用我们定义的忽略模式)
ExportUnityPackage(pathsToExport, outputPath, ignorePatterns, includeDependencies: false);
}
}