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_EDITOR1 [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; } // Create a new project object from build target XCProject project = new XCProject( pathToBuiltProject ); // Find and run through all projmods files to patch the project. // Please pay attention that ALL projmods files in your project folder will be excuted! string[] files = Directory.GetFiles( Application.dataPath, "*.projmods", SearchOption.AllDirectories ); foreach( string file in files ) { UnityEngine.Debug.Log("ProjMod File: "+file); project.ApplyMod( file ); } //TODO implement generic settings as a module option project.overwriteBuildSetting("CODE_SIGN_IDENTITY[sdk=iphoneos*]", "iPhone Distribution", "Release"); // Finally save the xcode project project.Save(); } #endif #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"); // Get the project file var projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject); Debug.Log("Xcode ProjPath: " + projPath); PBXProject proj = new PBXProject(); proj.ReadFromString(File.ReadAllText(projPath)); var frameworkTarget = proj.GetUnityFrameworkTargetGuid(); proj.AddFrameworkToProject(frameworkTarget, "libz.tbd", false); proj.AddFrameworkToProject(frameworkTarget, "Security.framework", false); proj.AddFrameworkToProject(frameworkTarget, "SystemConfiguration.framework", false); proj.AddFrameworkToProject(frameworkTarget, "MetricKit.framework", false); proj.AddFrameworkToProject(frameworkTarget, "AuthenticationServices.framework", true); // 为获取 IDFA 和 IDFV 添加的框架 proj.AddFrameworkToProject(frameworkTarget, "AdSupport.framework", false); // true 表示 Optional(弱链接),兼容 iOS 14 以下 proj.AddFrameworkToProject(frameworkTarget, "AppTrackingTransparency.framework", true); AddCapability(proj, pathToBuiltProject); proj.WriteToFile(projPath); ModifyInfoPlist(pathToBuiltProject); Debug.Log("end modify xcode project"); } private static void AddCapability(PBXProject project, string pathToBuiltProject) { var target = project.GetUnityMainTargetGuid(); string relativeEntitlementFilePath = "Unity-iPhone/Unity-iPhone.entitlements"; string absoluteEntitlementFilePath = pathToBuiltProject + "/" + relativeEntitlementFilePath; PlistDocument tempEntitlements = new PlistDocument(); PlistElementArray signinArr = new PlistElementArray(); signinArr.AddString("Default"); tempEntitlements.root["com.apple.developer.applesignin"] = signinArr; project.AddCapability(target, PBXCapabilityType.SignInWithApple, relativeEntitlementFilePath, true); var projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject); Debug.Log("Absolute Entitlement File Path: " + absoluteEntitlementFilePath); File.WriteAllText(projPath, project.WriteToString()); tempEntitlements.WriteToFile(absoluteEntitlementFilePath); ModifyEntitlementFile(absoluteEntitlementFilePath); } private static void ModifyEntitlementFile(string absoluteEntitlementFilePath) { try { if (!File.Exists(absoluteEntitlementFilePath)) { Debug.Log("Cant Find EntitlementFile :" + absoluteEntitlementFilePath); return; } StreamReader reader = new StreamReader(absoluteEntitlementFilePath); var content = reader.ReadToEnd().Trim(); reader.Close(); var needFindString = ""; var changeString = "" + "\n" + ""; Debug.Log("Xcode Entitlement Before: " + content); content = content.Replace(needFindString, changeString); Debug.Log("Xcode Entitlement After: " + content); StreamWriter writer = new StreamWriter(new FileStream(absoluteEntitlementFilePath, FileMode.Create)); writer.WriteLine(content); writer.Flush(); writer.Close(); } catch (Exception e) { Debug.Log("ModifyEntitlementFile - Failed: " + e.Message); } } /// /// 处理 Info.plist 权限描述的方法 /// /// private static void ModifyInfoPlist(string pathToBuiltProject) { string plistPath = pathToBuiltProject + "/Info.plist"; if (!File.Exists(plistPath)) { Debug.LogError("找不到 Info.plist 文件: " + plistPath); return; } try { PlistDocument plist = new PlistDocument(); plist.ReadFromString(File.ReadAllText(plistPath)); PlistElementDict rootDict = plist.root; // TODO 确定这段话是否展示 var trackingDescription = "我们需要您的同意来获取设备标识,以便为您提供更个性化的广告服务和更好的游戏体验。"; // 写入 NSUserTrackingUsageDescription 字段 rootDict.SetString("NSUserTrackingUsageDescription", trackingDescription); // 保存覆盖 Info.plist File.WriteAllText(plistPath, plist.WriteToString()); Debug.Log("成功修改 Info.plist,已自动添加 NSUserTrackingUsageDescription 权限描述 "); } catch (Exception e) { Debug.LogError("修改 Info.plist 失败: " + e.Message); } } #endif }