using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Callbacks;
#endif
using System.IO;
#if UNITY_EDITOR && UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif
public static class XCodePostProcess
{
#if UNITY_EDITOR && UNITY_IOS
[PostProcessBuild(999)]
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
{
if (target != BuildTarget.iOS)
{
Debug.LogWarning("Target is not iPhone. XCodePostProcess will not run");
return;
}
Debug.Log("start modify xcode project");
var projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
PBXProject proj = new PBXProject();
proj.ReadFromString(File.ReadAllText(projPath));
var frameworkTarget = proj.GetUnityFrameworkTargetGuid();
var mainTargetGuid = proj.GetUnityMainTargetGuid();
AddFrameworkSafe(proj, frameworkTarget, "libz.tbd");
AddFrameworkSafe(proj, frameworkTarget, "Security.framework");
AddFrameworkSafe(proj, frameworkTarget, "SystemConfiguration.framework");
AddFrameworkSafe(proj, frameworkTarget, "MetricKit.framework");
AddFrameworkSafe(proj, frameworkTarget, "AuthenticationServices.framework", true);
AddFrameworkSafe(proj, frameworkTarget, "AdSupport.framework");
AddFrameworkSafe(proj, frameworkTarget, "AppTrackingTransparency.framework", true);
// AIHelper
#if SDK_AIHELPER
AddBuildPropertySafe(proj, frameworkTarget, "OTHER_LDFLAGS", "-ObjC");
AddBuildPropertySafe(proj, mainTargetGuid, "OTHER_LDFLAGS", "-ObjC");
Debug.Log("AIHelper: Added -ObjC");
#endif
// CrashSight
#if SDK_CRASHSIGHT
SetBuildProperty(proj, mainTargetGuid, "GENERATE_DEBUG_SYMBOLS", "YES");
SetBuildProperty(proj, mainTargetGuid, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym");
SetBuildProperty(proj, frameworkTarget, "GENERATE_DEBUG_SYMBOLS", "YES");
SetBuildProperty(proj, frameworkTarget, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym");
Debug.Log("CrashSight: dSYM enabled");
#endif
// ThingkingData
#if SDK_THINKINGDATA
// 开启异常
SetBuildProperty(proj, frameworkTarget, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES");
SetBuildProperty(proj, mainTargetGuid, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES");
SetBuildProperty(proj, frameworkTarget, "CLANG_ENABLE_OBJC_EXCEPTIONS", "YES");
SetBuildProperty(proj, mainTargetGuid, "CLANG_ENABLE_OBJC_EXCEPTIONS", "YES");
// sqlite
AddFrameworkSafe(proj, frameworkTarget, "libsqlite3.tbd");
AddFrameworkSafe(proj, mainTargetGuid, "libsqlite3.tbd");
// -ObjC
AddBuildPropertySafe(proj, frameworkTarget, "OTHER_LDFLAGS", "-ObjC");
AddBuildPropertySafe(proj, mainTargetGuid, "OTHER_LDFLAGS", "-ObjC");
// libc++
AddFrameworkSafe(proj, frameworkTarget, "libc++.tbd");
AddFrameworkSafe(proj, mainTargetGuid, "libc++.tbd");
// 常见依赖
AddFrameworkSafe(proj, frameworkTarget, "CoreTelephony.framework");
AddFrameworkSafe(proj, frameworkTarget, "StoreKit.framework");
Debug.Log("ThinkingData: Config applied");
#endif
#if USE_OBFUZ
// Obfuscation build settings
SetBuildProperty(proj, frameworkTarget, "ENABLE_TESTABILITY", "YES");
SetBuildProperty(proj, mainTargetGuid, "ENABLE_TESTABILITY", "YES");
SetBuildProperty(proj, frameworkTarget, "COPY_PHASE_STRIP", "NO");
SetBuildProperty(proj, mainTargetGuid, "COPY_PHASE_STRIP", "NO");
SetBuildProperty(proj, frameworkTarget, "STRIP_STYLE", "all");
SetBuildProperty(proj, mainTargetGuid, "STRIP_STYLE", "all");
Debug.Log("USE_OBFUZ: Build settings applied");
#endif
AddCapability(proj, pathToBuiltProject);
proj.WriteToFile(projPath);
ModifyInfoPlist(pathToBuiltProject);
Debug.Log("end modify xcode project");
}
///
/// 安全添加 Framework(防重复)
///
///
///
///
///
private static void AddFrameworkSafe(PBXProject proj, string target, string framework, bool weak = false)
{
proj.AddFrameworkToProject(target, framework, weak);
}
///
/// 安全添加 BuildProperty(防重复)
///
///
///
///
///
private static void AddBuildPropertySafe(PBXProject proj, string target, string key, string value)
{
var values = proj.GetBuildPropertyForAnyConfig(target, key);
if (values == null || !values.Contains(value))
{
proj.AddBuildProperty(target, key, value);
}
}
///
/// 设置BuildSetting参数
///
///
///
///
///
private static void SetBuildProperty(PBXProject proj, string target, string key, string value)
{
proj.SetBuildProperty(target, key, value);
}
private static void AddCapability(PBXProject project, string pathToBuiltProject)
{
var target = project.GetUnityMainTargetGuid();
string relativePath = "Unity-iPhone/Unity-iPhone.entitlements";
string fullPath = Path.Combine(pathToBuiltProject, relativePath);
project.AddCapability(target, PBXCapabilityType.SignInWithApple, relativePath, true);
PlistDocument entitlementDoc = new PlistDocument();
if (File.Exists(fullPath)) {
entitlementDoc.ReadFromFile(fullPath);
} else {
entitlementDoc.Create();
}
const string signKey = "com.apple.developer.applesignin";
if (entitlementDoc.root[signKey] == null) {
PlistElementArray array = entitlementDoc.root.CreateArray(signKey);
array.AddString("Default");
}
entitlementDoc.WriteToFile(fullPath);
}
///
/// 修改 Info.plist
///
///
private static void ModifyInfoPlist(string pathToBuiltProject)
{
string plistPath = pathToBuiltProject + "/Info.plist";
if (!File.Exists(plistPath))
{
Debug.LogError("找不到 Info.plist 文件");
return;
}
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
var root = plist.root;
// IDFA
root.SetString(
"NSUserTrackingUsageDescription",
"同意我们获取设备标识,将有助于我们数据分析,以更好地优化游戏体验"
);
// 相册权限 否则 ITMS-90683
root.SetString(
"NSPhotoLibraryUsageDescription",
"用于选择图片、上传头像或分享内容"
);
// 写入相册权限 和上面搭配食用
root.SetString(
"NSPhotoLibraryAddUsageDescription",
"用于将图片保存到相册"
);
File.WriteAllText(plistPath, plist.WriteToString());
}
#endif
}