ios优化
@ -31,19 +31,45 @@ public class iOSFixDuplicateShellScript
|
|||||||
|
|
||||||
string content = File.ReadAllText(projPath);
|
string content = File.ReadAllText(projPath);
|
||||||
|
|
||||||
string pattern = @"(\t+([A-F0-9]+) /\* ShellScript \*/,)\r?\n\t+\2 /\* ShellScript \*,/";
|
// 1. 移除连续重复的 ShellScript 行
|
||||||
string newContent = Regex.Replace(content, pattern, "$1");
|
string pattern1 = @"\t+[A-F0-9]+ /\* ShellScript \*/,(\r?\n\t+[A-F0-9]+ /\* ShellScript \*,)+";
|
||||||
|
content = Regex.Replace(content, pattern1, m =>
|
||||||
if (newContent != content)
|
|
||||||
{
|
{
|
||||||
File.WriteAllText(projPath, newContent);
|
Debug.Log($"[PostProcess] 移除连续重复 ShellScript 行: {m.Value.TrimEnd().Length} chars");
|
||||||
Debug.Log("[PostProcess] Removed duplicate ShellScript from GameAssembly target");
|
return m.Groups[0].Value.Split('\n')[0]; // 只保留第一行
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. 移除整个文件中非连续的重复 ShellScript(按 ID 去重)
|
||||||
|
var lines = content.Split('\n');
|
||||||
|
var seenShellScriptIds = new System.Collections.Generic.HashSet<string>();
|
||||||
|
var outputLines = new System.Collections.Generic.List<string>();
|
||||||
|
int removedCount = 0;
|
||||||
|
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
var match = Regex.Match(line, @"^\t+([A-F0-9]+) /\* ShellScript \*/,?$");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
string id = match.Groups[1].Value;
|
||||||
|
if (!seenShellScriptIds.Add(id))
|
||||||
|
{
|
||||||
|
removedCount++;
|
||||||
|
continue; // 跳过重复
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputLines.Add(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修复光子矩阵 app 大小写
|
if (removedCount > 0)
|
||||||
newContent = newContent.Replace("photonmatrix.app", "PhotonMatrix.app");
|
{
|
||||||
|
content = string.Join("\n", outputLines);
|
||||||
|
Debug.Log($"[PostProcess] 按 ID 去重移除了 {removedCount} 个 ShellScript 条目");
|
||||||
|
}
|
||||||
|
|
||||||
File.WriteAllText(projPath, newContent);
|
// 3. 修复光子矩阵 app 大小写
|
||||||
|
content = content.Replace("photonmatrix.app", "PhotonMatrix.app");
|
||||||
|
|
||||||
|
File.WriteAllText(projPath, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FixPodfile(string pathToBuiltProject)
|
private static void FixPodfile(string pathToBuiltProject)
|
||||||
|
|||||||
@ -1,91 +1,162 @@
|
|||||||
#if UNITY_IOS
|
#if UNITY_IOS
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Callbacks;
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// iOS 出包后自动替换高清 App 图标,解决 Unity 压缩导致图标模糊的问题。
|
/// iOS 出包后自动替换高清 App 图标,解决 Unity 压缩导致图标模糊的问题。
|
||||||
|
/// 使用 IPostprocessBuildWithReport 确保在所有 PostProcessBuild 之后执行。
|
||||||
/// 使用方式:将精确尺寸的 PNG 图标放入 Assets/Icons/iOS/ 目录下,打包时自动生效。
|
/// 使用方式:将精确尺寸的 PNG 图标放入 Assets/Icons/iOS/ 目录下,打包时自动生效。
|
||||||
|
/// 命名规则:iPhone-App-180.png(设备-用途-像素尺寸)可被 Xcode Asset Catalog 自动识别。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class iOSIconPostProcessor
|
public class iOSIconPostProcessor : IPostprocessBuildWithReport
|
||||||
{
|
{
|
||||||
|
public int callbackOrder => int.MaxValue;
|
||||||
|
|
||||||
private const string SOURCE_ICON_DIR = "Assets/Icons/iOS/";
|
private const string SOURCE_ICON_DIR = "Assets/Icons/iOS/";
|
||||||
|
|
||||||
// 各尺寸图标配置 (idiom, scale, size, 文件名)
|
// 图标配置: (idiom, scale, 点尺寸, 源文件名, 目标文件名)
|
||||||
private static readonly (string idiom, string scale, string size, string file)[] ICON_CONFIGS =
|
// 源文件在 Assets/Icons/iOS/ 下,目标文件写入 Xcode 的 AppIcon.appiconset
|
||||||
|
private static readonly (string idiom, string scale, string size, string src, string dst)[] ICON_CONFIGS =
|
||||||
{
|
{
|
||||||
("iphone", "2x", "20x20", "icon-20@2x.png"),
|
// --- iPhone ---
|
||||||
("iphone", "3x", "20x20", "icon-20@3x.png"),
|
("iphone", "2x", "20x20", "iPhone-Notification-40.png", "Icon-iPhone-Notification-40.png"),
|
||||||
("iphone", "2x", "29x29", "icon-29@2x.png"),
|
("iphone", "3x", "20x20", "iPhone-Notification-60.png", "Icon-iPhone-Notification-60.png"),
|
||||||
("iphone", "3x", "29x29", "icon-29@3x.png"),
|
("iphone", "2x", "29x29", "iPhone-Settings-58.png", "Icon-iPhone-Settings-58.png"),
|
||||||
("iphone", "2x", "40x40", "icon-40@2x.png"),
|
("iphone", "3x", "29x29", "iPhone-Settings-87.png", "Icon-iPhone-Settings-87.png"),
|
||||||
("iphone", "3x", "40x40", "icon-40@3x.png"),
|
("iphone", "2x", "40x40", "iPhone-Spotlight-80.png", "Icon-iPhone-Spotlight-80.png"),
|
||||||
("iphone", "2x", "60x60", "icon-60@2x.png"),
|
("iphone", "3x", "40x40", "iPhone-Spotlight-120.png", "Icon-iPhone-Spotlight-120.png"),
|
||||||
("iphone", "3x", "60x60", "icon-60@3x.png"),
|
("iphone", "2x", "60x60", "iPhone-App-120.png", "Icon-iPhone-App-120.png"),
|
||||||
("ipad", "2x", "20x20", "icon-20@2x.png"),
|
("iphone", "3x", "60x60", "iPhone-App-180.png", "Icon-iPhone-App-180.png"),
|
||||||
("ipad", "2x", "29x29", "icon-29@2x.png"),
|
|
||||||
("ipad", "2x", "40x40", "icon-40@2x.png"),
|
// --- iPad(复用 iPhone 同名图标作为回退) ---
|
||||||
("ipad", "2x", "76x76", "icon-76@2x.png"),
|
("ipad", "2x", "20x20", "iPhone-Notification-40.png", "Icon-iPad-Notification-40.png"),
|
||||||
("ipad", "2x", "83.5x83.5", "icon-83.5@2x.png"),
|
("ipad", "2x", "29x29", "iPhone-Settings-58.png", "Icon-iPad-Settings-58.png"),
|
||||||
("ios-marketing", "1x", "1024x1024", "icon-1024.png"),
|
("ipad", "2x", "40x40", "iPhone-Spotlight-80.png", "Icon-iPad-Spotlight-80.png"),
|
||||||
|
("ipad", "2x", "76x76", "iPhone-Spotlight-80.png", "Icon-iPad-App-76.png"),
|
||||||
|
("ipad", "2x", "83.5x83.5", "iPhone-App-120.png", "Icon-iPad-Pro-App-167.png"),
|
||||||
|
|
||||||
|
// --- App Store ---
|
||||||
|
("ios-marketing", "1x", "1024x1024", "AppStore-1024.png", "Icon-AppStore-1024.png"),
|
||||||
};
|
};
|
||||||
|
|
||||||
[PostProcessBuild(int.MaxValue)]
|
public void OnPostprocessBuild(BuildReport report)
|
||||||
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
|
||||||
{
|
{
|
||||||
if (target != BuildTarget.iOS) return;
|
if (report.summary.platform != BuildTarget.iOS) return;
|
||||||
|
|
||||||
string iconSetPath = Path.Combine(pathToBuiltProject, "Unity-iPhone/Images.xcassets/AppIcon.appiconset");
|
string pathToBuiltProject = report.summary.outputPath;
|
||||||
if (!Directory.Exists(iconSetPath))
|
string iconSetPath = FindAppIconPath(pathToBuiltProject);
|
||||||
|
if (string.IsNullOrEmpty(iconSetPath))
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.LogWarning($"[iOSIconPostProcessor] 未找到 AppIcon.appiconset 目录: {iconSetPath}");
|
Debug.LogWarning($"[iOSIconPostProcessor] 未找到 AppIcon.appiconset 目录,跳过图标替换");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int copied = 0;
|
EditorApplication.delayCall += () => ReplaceIcons(iconSetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReplaceIcons(string iconSetPath)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(iconSetPath))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[iOSIconPostProcessor] AppIcon.appiconset 目录已不存在: {iconSetPath}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string projectRoot = Path.GetDirectoryName(Application.dataPath);
|
||||||
|
string sourceDir = Path.Combine(projectRoot, SOURCE_ICON_DIR);
|
||||||
|
|
||||||
|
// 清空旧图标
|
||||||
|
foreach (string oldFile in Directory.GetFiles(iconSetPath, "*.png"))
|
||||||
|
{
|
||||||
|
File.Delete(oldFile);
|
||||||
|
}
|
||||||
|
Debug.Log($"[iOSIconPostProcessor] 已清空旧图标");
|
||||||
|
|
||||||
|
// 复制新图标(源文件 → 目标 Xcode 标准名称)
|
||||||
|
var copiedDstFiles = new HashSet<string>();
|
||||||
foreach (var cfg in ICON_CONFIGS)
|
foreach (var cfg in ICON_CONFIGS)
|
||||||
{
|
{
|
||||||
string src = Path.GetFullPath(Path.Combine(SOURCE_ICON_DIR, cfg.file));
|
string src = Path.Combine(sourceDir, cfg.src);
|
||||||
string dst = Path.Combine(iconSetPath, cfg.file);
|
|
||||||
if (File.Exists(src))
|
if (File.Exists(src))
|
||||||
{
|
{
|
||||||
|
string dst = Path.Combine(iconSetPath, cfg.dst);
|
||||||
File.Copy(src, dst, overwrite: true);
|
File.Copy(src, dst, overwrite: true);
|
||||||
copied++;
|
copiedDstFiles.Add(cfg.dst);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.LogWarning($"[iOSIconPostProcessor] 缺少图标文件: {src}");
|
Debug.LogWarning($"[iOSIconPostProcessor] 缺少源图标: {cfg.src}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copied > 0)
|
if (copiedDstFiles.Count > 0)
|
||||||
{
|
{
|
||||||
WriteContentsJson(iconSetPath);
|
WriteContentsJson(iconSetPath, copiedDstFiles);
|
||||||
UnityEngine.Debug.Log($"[iOSIconPostProcessor] 已替换 {copied} 个 App 图标到 Xcode 项目");
|
Debug.Log($"[iOSIconPostProcessor] 已替换 {copiedDstFiles.Count} 个 App 图标");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("[iOSIconPostProcessor] 未找到任何可用图标");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteContentsJson(string iconSetPath)
|
private static string FindAppIconPath(string buildPath)
|
||||||
|
{
|
||||||
|
string[] candidates =
|
||||||
|
{
|
||||||
|
Path.Combine(buildPath, "Unity-iPhone/Images.xcassets/AppIcon.appiconset"),
|
||||||
|
Path.Combine(buildPath, "Images.xcassets/AppIcon.appiconset"),
|
||||||
|
Path.Combine(buildPath, "Unity-iPhone/Unity-iPhone/Images.xcassets/AppIcon.appiconset"),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string path in candidates)
|
||||||
|
{
|
||||||
|
if (Directory.Exists(path))
|
||||||
|
{
|
||||||
|
Debug.Log($"[iOSIconPostProcessor] 找到 AppIcon 目录: {path}");
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string searchRoot = Path.Combine(buildPath, "Unity-iPhone");
|
||||||
|
if (!Directory.Exists(searchRoot)) searchRoot = buildPath;
|
||||||
|
foreach (string dir in Directory.GetDirectories(searchRoot, "AppIcon.appiconset", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
Debug.Log($"[iOSIconPostProcessor] 搜索找到 AppIcon 目录: {dir}");
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteContentsJson(string iconSetPath, HashSet<string> dstFiles)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine("{");
|
sb.AppendLine("{");
|
||||||
sb.AppendLine(" \"images\" : [");
|
sb.AppendLine(" \"images\" : [");
|
||||||
|
|
||||||
for (int i = 0; i < ICON_CONFIGS.Length; i++)
|
bool first = true;
|
||||||
|
foreach (var cfg in ICON_CONFIGS)
|
||||||
{
|
{
|
||||||
var cfg = ICON_CONFIGS[i];
|
if (!dstFiles.Contains(cfg.dst))
|
||||||
sb.Append(" {");
|
continue;
|
||||||
sb.Append($"\"idiom\" : \"{cfg.idiom}\", ");
|
|
||||||
|
if (!first) sb.AppendLine(",");
|
||||||
|
else sb.AppendLine();
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
sb.Append($" {{\"idiom\" : \"{cfg.idiom}\", ");
|
||||||
sb.Append($"\"scale\" : \"{cfg.scale}\", ");
|
sb.Append($"\"scale\" : \"{cfg.scale}\", ");
|
||||||
sb.Append($"\"size\" : \"{cfg.size}\"");
|
sb.Append($"\"size\" : \"{cfg.size}\", ");
|
||||||
if (!string.IsNullOrEmpty(cfg.file))
|
sb.Append($"\"filename\" : \"{cfg.dst}\"}}");
|
||||||
sb.Append($", \"filename\" : \"{cfg.file}\"");
|
|
||||||
sb.Append("}");
|
|
||||||
if (i < ICON_CONFIGS.Length - 1) sb.Append(",");
|
|
||||||
sb.AppendLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
sb.AppendLine(" ],");
|
sb.AppendLine(" ],");
|
||||||
sb.AppendLine(" \"info\" : {");
|
sb.AppendLine(" \"info\" : {");
|
||||||
sb.AppendLine(" \"version\" : 1,");
|
sb.AppendLine(" \"version\" : 1,");
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@ -174,7 +174,7 @@ PlayerSettings:
|
|||||||
buildNumber:
|
buildNumber:
|
||||||
Standalone: 0
|
Standalone: 0
|
||||||
VisionOS: 0
|
VisionOS: 0
|
||||||
iPhone: 2
|
iPhone: 3
|
||||||
tvOS: 0
|
tvOS: 0
|
||||||
overrideDefaultApplicationIdentifier: 1
|
overrideDefaultApplicationIdentifier: 1
|
||||||
AndroidBundleVersionCode: 1
|
AndroidBundleVersionCode: 1
|
||||||
@ -417,6 +417,30 @@ PlayerSettings:
|
|||||||
- {fileID: 0}
|
- {fileID: 0}
|
||||||
m_Width: 120
|
m_Width: 120
|
||||||
m_Height: 120
|
m_Height: 120
|
||||||
|
m_Kind: 0
|
||||||
|
m_SubKind: iPhone
|
||||||
|
- m_Textures:
|
||||||
|
- {fileID: 0}
|
||||||
|
m_Width: 167
|
||||||
|
m_Height: 167
|
||||||
|
m_Kind: 0
|
||||||
|
m_SubKind: iPad
|
||||||
|
- m_Textures:
|
||||||
|
- {fileID: 0}
|
||||||
|
m_Width: 152
|
||||||
|
m_Height: 152
|
||||||
|
m_Kind: 0
|
||||||
|
m_SubKind: iPad
|
||||||
|
- m_Textures:
|
||||||
|
- {fileID: 0}
|
||||||
|
m_Width: 76
|
||||||
|
m_Height: 76
|
||||||
|
m_Kind: 0
|
||||||
|
m_SubKind: iPad
|
||||||
|
- m_Textures:
|
||||||
|
- {fileID: 2800000, guid: a7dc74acf58f7154f9a4a438ad70df1d, type: 3}
|
||||||
|
m_Width: 120
|
||||||
|
m_Height: 120
|
||||||
m_Kind: 3
|
m_Kind: 3
|
||||||
m_SubKind: iPhone
|
m_SubKind: iPhone
|
||||||
- m_Textures:
|
- m_Textures:
|
||||||
@ -453,14 +477,12 @@ PlayerSettings:
|
|||||||
m_Height: 29
|
m_Height: 29
|
||||||
m_Kind: 1
|
m_Kind: 1
|
||||||
m_SubKind: iPhone
|
m_SubKind: iPhone
|
||||||
- m_Textures:
|
- m_Textures: []
|
||||||
- {fileID: 0}
|
|
||||||
m_Width: 58
|
m_Width: 58
|
||||||
m_Height: 58
|
m_Height: 58
|
||||||
m_Kind: 1
|
m_Kind: 1
|
||||||
m_SubKind: iPad
|
m_SubKind: iPad
|
||||||
- m_Textures:
|
- m_Textures: []
|
||||||
- {fileID: 0}
|
|
||||||
m_Width: 29
|
m_Width: 29
|
||||||
m_Height: 29
|
m_Height: 29
|
||||||
m_Kind: 1
|
m_Kind: 1
|
||||||
|
|||||||