#if UNITY_IOS || UNITY_IPHONE using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor.XCodeEditor; using PBXProject = UnityEditor.iOS.Xcode.PBXProject; public abstract class PbxProjectSet { // 需要特殊Flag的文件类型 protected static readonly Dictionary compileFlagDict = new Dictionary { { "OpenUDID.m", "-fno-objc-arc" } }; protected static readonly string[] noBuildTypes = { ".h", ".entitlements" }; protected static readonly string[] noRelativePathTypes = { ".framework", ".dylib", ".tbd", ".plist" }; protected static readonly string[] noCopyTypes = { ".txt", ".mdown", ".DS_Store" }; protected readonly PBXProject pbxProject; protected readonly string pbxProjectPath; protected readonly string projectGuid; private readonly string _releaseGuid; private readonly string _runningGuid; private readonly string _profilingGuid; private readonly string _debugGuid; protected readonly string sourcePath; protected readonly string targetPath; protected PbxProjectSet(string source, string target) { sourcePath = source.TrimEnd('/', '\\'); targetPath = target.TrimEnd('/', '\\'); pbxProjectPath = PBXProject.GetPBXProjectPath(target); pbxProject = new PBXProject(); pbxProject.ReadFromFile(pbxProjectPath); projectGuid = pbxProject.TargetGuidByName(PBXProject.GetUnityTargetName()); _debugGuid = pbxProject.BuildConfigByName(projectGuid, "Debug"); _releaseGuid = pbxProject.BuildConfigByName(projectGuid, "Release"); _profilingGuid = pbxProject.BuildConfigByName(projectGuid, "ReleaseForProfiling"); _runningGuid = pbxProject.BuildConfigByName(projectGuid, "ReleaseForRunning"); } protected void ModifyCodes() { // 刘海适配代码 var src = @"_window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];"; var dst = @" CGRect winSize = [UIScreen mainScreen].bounds; if((winSize.size.height == 1125 && winSize.size.width == 2436) || (winSize.size.height == 2436 && winSize.size.width == 1125) || (winSize.size.height == 1242 && winSize.size.width == 2688) || (winSize.size.height == 2688 && winSize.size.width == 1242) || (winSize.size.height == 828 && winSize.size.width == 1792)) { winSize.size.width -= 150; winSize.origin.x = 75; } _window = [[UIWindow alloc] initWithFrame: winSize];"; var unityAppControllerPath = targetPath + "/Classes/UnityAppController.mm"; var unityAppController = new XClassExt(unityAppControllerPath); unityAppController.Replace(src, dst); unityAppController.Dispose(); } protected void AddDirectory(string directory, string projectDir) { AddDirectoryInternal(sourcePath.Open(directory), projectDir); } protected void AddFile(string filePath, string projectDir) { AddFileInternal(sourcePath.Open(filePath), projectDir); } protected void CopyFileOnly(string filePath, string projectDir) { CopyFileInternal(sourcePath.Open(filePath), projectDir); } private void AddDirectoryInternal(string directory, string projectDir) { if (Path.HasExtension(directory)) AddFileInternal(directory, projectDir); else { var files = GetAllFiles(directory); foreach (var file in files) AddFileInternal(file, projectDir); } } // 注:苹果的垃圾玩意会把文件夹当文件一样加入,所以不能直接扫描文件,只能一层一层扫描路径 private IEnumerable GetAllFiles(string directory) { var result = new List(); foreach (var file in Directory.GetFiles(directory)) { var extension = Path.GetExtension(file); if (!string.IsNullOrEmpty(extension) && !noCopyTypes.Contains(extension)) result.Add(file); } var subDirs = Directory.GetDirectories(directory); foreach (var subDir in subDirs) { // 苹果的破文件夹形式的文件 if (!string.IsNullOrEmpty(Path.GetExtension(subDir))) result.Add(subDir); else result.AddRange(GetAllFiles(subDir)); } return result; } private void AddFileInternal(string filePath, string projectDir) { // 如果是.framework或者.bundle之类的垃圾玩意 if (Directory.Exists(filePath)) { var files = Directory.GetFiles(filePath, "*.*", SearchOption.AllDirectories); foreach (var file in files) CopyFileInternal(file, projectDir); } else { CopyFileInternal(filePath, projectDir); } var extension = Path.GetExtension(filePath); var path = filePath.Substring(sourcePath.Length + 1); if (!string.IsNullOrEmpty(projectDir)) path = projectDir.Open(path); var fileName = Path.GetFileName(path); // Frameworks类单独使用特殊ProjectPath var projectPath = noRelativePathTypes.Contains(extension) ? fileName : path; var addFile = pbxProject.AddFile(path, projectPath); // 不需要编译的类型不添加编译 if (!noBuildTypes.Contains(extension)) { string compileFlags; if (compileFlagDict.TryGetValue(fileName, out compileFlags)) pbxProject.AddFileToBuildWithFlags(projectGuid, addFile, compileFlags); else pbxProject.AddFileToBuild(projectGuid, addFile); } } private void CopyFileInternal(string filePath, string projectDir) { var relative = filePath.Substring(sourcePath.Length + 1); var target = targetPath.Open(projectDir).Open(relative); var dir = Path.GetDirectoryName(target); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); File.Copy(filePath, target, true); } public abstract void Action(); protected abstract void SetTargetConfig(string guid); protected void SetAllConfigs() { SetTargetConfig(_debugGuid); SetTargetConfig(_releaseGuid); SetTargetConfig(_runningGuid); SetTargetConfig(_profilingGuid); } protected void Save() { File.WriteAllText(pbxProjectPath, pbxProject.WriteToString()); } } #endif