diff --git a/Assets/Editor/PackageExporter.cs b/Assets/Editor/PackageExporter.cs new file mode 100644 index 0000000..a7830c5 --- /dev/null +++ b/Assets/Editor/PackageExporter.cs @@ -0,0 +1,273 @@ +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 + { + /// + /// 导出 UnityPackage(支持忽略特定文件) + /// + /// 需要导出的资源路径数组(文件夹或文件) + /// 导出文件路径(含.unitypackage扩展名) + /// 需要忽略的文件/文件夹模式数组 + /// 是否包含依赖资源 + /// 是否递归导出文件夹内的所有内容 + /// 导出是否成功 + 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; + } + } + + /// + /// 处理资源路径,过滤掉需要忽略的文件 + /// + 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(); + + 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(); + } + + /// + /// 检查文件是否应该被忽略 + /// + 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; + } + + /// + /// 检查文件路径是否匹配通配符模式(使用正则表达式实现) + /// + 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); + } + } \ No newline at end of file diff --git a/Assets/Editor/PackageExporter.cs.meta b/Assets/Editor/PackageExporter.cs.meta new file mode 100644 index 0000000..084df16 --- /dev/null +++ b/Assets/Editor/PackageExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f63a53a7744c14d5a9c6a3a3f0e36524 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/google-services-desktop.json.meta b/Assets/StreamingAssets/google-services-desktop.json.meta index ef9c43e..52ff557 100644 --- a/Assets/StreamingAssets/google-services-desktop.json.meta +++ b/Assets/StreamingAssets/google-services-desktop.json.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 35de05bb934f64861beae2647b59f730 +guid: 9074cef3c9d994f619d5ae12dea4e19c DefaultImporter: externalObjects: {} userData: diff --git a/UserSettings/Layouts/default-2022.dwlt b/UserSettings/Layouts/default-2022.dwlt index 6144cba..db41fe3 100644 --- a/UserSettings/Layouts/default-2022.dwlt +++ b/UserSettings/Layouts/default-2022.dwlt @@ -141,7 +141,7 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 831 + width: 978 height: 841 m_MinSize: {x: 100, y: 100} m_MaxSize: {x: 8096, y: 16192} @@ -165,8 +165,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 831 - height: 185.5 + width: 978 + height: 319.5 m_MinSize: {x: 201, y: 221} m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 12} @@ -191,9 +191,9 @@ MonoBehaviour: m_Position: serializedVersion: 2 x: 0 - y: 185.5 - width: 831 - height: 655.5 + y: 319.5 + width: 978 + height: 521.5 m_MinSize: {x: 231, y: 271} m_MaxSize: {x: 10001, y: 10021} m_ActualView: {fileID: 14} @@ -217,9 +217,9 @@ MonoBehaviour: m_Children: [] m_Position: serializedVersion: 2 - x: 831 + x: 978 y: 0 - width: 212 + width: 176 height: 841 m_MinSize: {x: 202, y: 221} m_MaxSize: {x: 4002, y: 4021} @@ -243,9 +243,9 @@ MonoBehaviour: m_Children: [] m_Position: serializedVersion: 2 - x: 1043 + x: 1154 y: 0 - width: 427 + width: 316 height: 841 m_MinSize: {x: 641, y: 601} m_MaxSize: {x: 4001, y: 4021} @@ -296,7 +296,7 @@ MonoBehaviour: m_CachedPref: 226 m_ControlHash: -371814159 m_PrefName: Preview_InspectorPreview - m_LastInspectedObjectInstanceID: -1 + m_LastInspectedObjectInstanceID: 22576 m_LastVerticalScrollValue: 0 m_GlobalObjectId: m_InspectorMode: 0 @@ -325,8 +325,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 95 - width: 830 - height: 164.5 + width: 977 + height: 298.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1014,9 +1014,9 @@ MonoBehaviour: m_Pos: serializedVersion: 2 x: 0 - y: 280.5 - width: 830 - height: 634.5 + y: 414.5 + width: 977 + height: 500.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1038,26 +1038,7 @@ MonoBehaviour: m_SkipHidden: 0 m_SearchArea: 1 m_Folders: - - Assets/Adjust - - Assets/BigoAds - - Assets/BigoSDK - - Assets/Editor - - Assets/Editor Default Resources - - Assets/EFSDK - - Assets/ExternalDependencyManager - - Assets/Firebase - - Assets/GeneratedLocalRepo - - Assets/GoogleMobileAds - - Assets/KwaiAds - - Assets/MaxSdk - - Assets/Plugins - - Assets/Resources - - Assets/Scenes - - Assets/Script - - Assets/StreamingAssets - - Assets/ThinkingAnalytics - - Assets/ThinkupTpnPlugin - - Assets/UnityPackages + - Assets/Plugins/Android m_Globs: [] m_OriginalText: m_ImportLogFlags: 0 @@ -1073,7 +1054,7 @@ MonoBehaviour: scrollPos: {x: 0, y: 0} m_SelectedIDs: da400000 m_LastClickedID: 16602 - m_ExpandedIDs: 00000000846c0000866c0000886c00008a6c00008c6c00008e6c0000906c0000926c0000946c0000966c0000986c00009a6c00009c6c00009e6c0000a06c0000a26c0000a46c0000a66c0000a86c0000aa6c0000ac6c0000ae6c0000 + m_ExpandedIDs: m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1098,10 +1079,10 @@ MonoBehaviour: m_Icon: {fileID: 0} m_ResourceFile: m_AssetTreeState: - scrollPos: {x: 0, y: 0} + scrollPos: {x: 0, y: 113.99658} m_SelectedIDs: m_LastClickedID: 0 - m_ExpandedIDs: ffffffff00000000846c0000866c0000886c00008a6c00008c6c00008e6c0000906c0000926c0000946c0000966c0000986c00009a6c00009e6c0000a06c0000a26c0000a46c0000a66c0000a86c0000aa6c0000ac6c0000ae6c0000 + m_ExpandedIDs: ffffffff0000000064410000dc4100008c420000 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1153,7 +1134,7 @@ MonoBehaviour: m_Icon: {fileID: 0} m_ResourceFile: m_NewAssetIndexInList: -1 - m_ScrollPosition: {x: 0, y: 0} + m_ScrollPosition: {x: 0, y: 186.5} m_GridSize: 16 m_SkipHiddenPackages: 0 m_DirectoriesAreaWidth: 82 @@ -1178,9 +1159,9 @@ MonoBehaviour: m_Pos: serializedVersion: 2 x: 0 - y: 280.5 - width: 611 - height: 634.5 + y: 414.5 + width: 977 + height: 500.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -1211,9 +1192,9 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 831 + x: 978 y: 95 - width: 210 + width: 174 height: 820 m_SerializedDataModeController: m_DataMode: 0 @@ -1228,9 +1209,9 @@ MonoBehaviour: m_SceneHierarchy: m_TreeViewState: scrollPos: {x: 0, y: 0} - m_SelectedIDs: 2a6d00002c6d00002e6d0000306d0000326d0000346d0000366d0000386d00003a6d00003c6d00003e6d0000406d0000426d0000446d0000466d00009c6c00006a6d00006c6d00006e6d0000706d0000 + m_SelectedIDs: 30580000 m_LastClickedID: 0 - m_ExpandedIDs: 2efbffff + m_ExpandedIDs: 48c1feff m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1274,9 +1255,9 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 1043 + x: 1154 y: 95 - width: 426 + width: 315 height: 820 m_SerializedDataModeController: m_DataMode: 0