#if UNITY_EDITOR
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif
///
/// 在 tysdk (PostProcessBuild 1000) 之后执行,
/// 将备选 App 图标打入 iOS 包并写入 Info.plist,供 App Store 产品页优化(图标 A/B)使用。
///
public static class IOSBuildProcessor
{
const int PostProcessOrder = 1001;
/// 与 App Store Connect 中「备选图标」标识符保持一致(建议仅字母数字)。
public const string AlternateIconIdentifier = "FishingTravelAlt";
static readonly string SourceIconProjectPath = "Assets/app_icons/icon_fishing_travel_alt.png";
#if UNITY_IOS
const string DestRelativeFolder = "AlternateAppIcons";
static readonly (string fileName, int width, int height)[] IconOutputs =
{
("FishingTravelAlt60x60@2x.png", 120, 120),
("FishingTravelAlt60x60@3x.png", 180, 180),
("FishingTravelAlt76x76@2x~ipad.png", 152, 152),
("FishingTravelAlt83.5x83.5@2x~ipad.png", 167, 167),
};
#endif
[PostProcessBuild(PostProcessOrder)]
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
{
#if UNITY_IOS
if (target != BuildTarget.iOS)
return;
string srcAbs = Path.Combine(Application.dataPath, "app_icons/icon_fishing_travel_alt.png");
if (!File.Exists(srcAbs))
{
Debug.LogError(
$"[IOSBuildProcessor] 未找到备选图标: {srcAbs}(项目内 {SourceIconProjectPath})。");
return;
}
byte[] pngBytes = File.ReadAllBytes(srcAbs);
var srcTex = new Texture2D(2, 2, TextureFormat.RGBA32, false);
if (!srcTex.LoadImage(pngBytes))
{
Debug.LogError("[IOSBuildProcessor] 无法解码 PNG: " + srcAbs);
Object.DestroyImmediate(srcTex);
return;
}
string destDir = Path.Combine(pathToBuiltProject, DestRelativeFolder);
Directory.CreateDirectory(destDir);
foreach (var entry in IconOutputs)
{
Texture2D scaled = ScaleTexture(srcTex, entry.width, entry.height);
try
{
File.WriteAllBytes(Path.Combine(destDir, entry.fileName), scaled.EncodeToPNG());
}
finally
{
Object.DestroyImmediate(scaled);
}
}
Object.DestroyImmediate(srcTex);
AddIconsToXcodeProject(pathToBuiltProject);
MergeAlternateIconsPlist(pathToBuiltProject);
#else
if (target == BuildTarget.iOS)
Debug.LogWarning("[IOSBuildProcessor] 当前编辑器未启用 iOS 模块,已跳过备选图标处理。");
#endif
}
#if UNITY_IOS
static Texture2D ScaleTexture(Texture2D source, int width, int height)
{
var rt = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.ARGB32,
RenderTextureReadWrite.sRGB);
var prev = RenderTexture.active;
Graphics.Blit(source, rt);
RenderTexture.active = rt;
var dest = new Texture2D(width, height, TextureFormat.RGBA32, false);
dest.ReadPixels(new Rect(0, 0, width, height), 0, 0);
dest.Apply();
RenderTexture.active = prev;
RenderTexture.ReleaseTemporary(rt);
return dest;
}
static void AddIconsToXcodeProject(string pathToBuiltProject)
{
string pbxPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
var proj = new PBXProject();
proj.ReadFromFile(pbxPath);
string mainTarget = proj.GetUnityMainTargetGuid();
foreach (var entry in IconOutputs)
{
string relPath = Path.Combine(DestRelativeFolder, entry.fileName).Replace('\\', '/');
string guid = proj.AddFile(relPath, relPath, PBXSourceTree.Source);
proj.AddFileToBuild(mainTarget, guid);
}
proj.WriteToFile(pbxPath);
}
static void MergeAlternateIconsPlist(string pathToBuiltProject)
{
string plistPath = Path.Combine(pathToBuiltProject, "Info.plist");
var plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
PlistElementDict root = plist.root;
root.SetBoolean("UIApplicationSupportsAlternateIcons", true);
PlistElementDict bundleIcons;
if (!root.values.ContainsKey("CFBundleIcons"))
bundleIcons = root.CreateDict("CFBundleIcons");
else
bundleIcons = root.values["CFBundleIcons"].AsDict();
PlistElementDict alternateIcons;
if (!bundleIcons.values.ContainsKey("CFBundleAlternateIcons"))
alternateIcons = bundleIcons.CreateDict("CFBundleAlternateIcons");
else
alternateIcons = bundleIcons.values["CFBundleAlternateIcons"].AsDict();
if (alternateIcons.values.ContainsKey(AlternateIconIdentifier))
alternateIcons.values.Remove(AlternateIconIdentifier);
PlistElementDict iconDict = alternateIcons.CreateDict(AlternateIconIdentifier);
PlistElementArray files = iconDict.CreateArray("CFBundleIconFiles");
files.AddString("FishingTravelAlt60x60");
files.AddString("FishingTravelAlt76x76");
files.AddString("FishingTravelAlt83.5x83.5");
iconDict.SetBoolean("UIPrerenderedIcon", false);
File.WriteAllText(plistPath, plist.WriteToString());
}
#endif
}
#endif