using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEditor; #if UNITY_IOS using UnityEditor.iOS.Xcode; #endif namespace Pack { public partial class PackPlatformiOS { protected override string GetBuildOutputPath() { // iOS 的XCode项目路径最好不能有中文,否则易出错 string path = Application.dataPath + PackConstant.BuildAppPath + "/" + GetBuildTarget() + "/" + channelUniqueId; path = Path.GetFullPath(path).Replace('\\', '/'); return path + "/XCodeProj"; } public override void BuildClear() { base.BuildClear(); DeleteDirectoryAssets(Path.GetFullPath(Application.dataPath + PackConstant.PluginiOSDestPath), true); DeleteDirectoryAssets(Path.GetFullPath(Application.dataPath + PackConstant.SDKBridgeDestPath), true); } protected override void ChangePlayerSettings() { base.ChangePlayerSettings(); PlayerSettings.bundleVersion = gameVersionCode.ToString(true); PlayerSettings.iOS.buildNumber = gameVersionCode; } protected override void ChangePlatformSpecial() { base.ChangePlatformSpecial(); EditorUtility.DisplayProgressBar("平台特殊设置", "开始平台特殊设置", 0); if (plugins != null && plugins.Count > 0) { CopyUnityAssets(Application.dataPath + PackConstant.PluginiOSSrcPath , plugins , Application.dataPath + PackConstant.PluginiOSDestPath , Application.dataPath + PackConstant.PluginiOSSrcMetaPath , Application.dataPath + PackConstant.PluginiOSDestMetaPath); } EditorUtility.DisplayProgressBar("平台特殊设置", "平台特殊设置", 0.5f); if (sdkBridges != null && sdkBridges.Count > 0) { CopyUnityAssets(Application.dataPath + PackConstant.SDKBridgeSrcPath , sdkBridges , Application.dataPath + PackConstant.SDKBridgeDestPath , Application.dataPath + PackConstant.SDKBridgeSrcMetaPath , Application.dataPath + PackConstant.SDKBridgeDestMetaPath); } EditorUtility.DisplayProgressBar("平台特殊设置", "完成平台特殊设置", 1); } protected override BuildOptions ChangeBuildOptionsBefore(BuildOptions buildOptions) { buildOptions = base.ChangeBuildOptionsBefore(buildOptions); return buildOptions; } private void CopymmFile(string[] fs,string topath) { string path = Application.dataPath + PackConstant.BuildSharedResourcePath + "/Plugins/Special/iOS/"; string outPath = GetBuildOutputPath(); foreach (var item in fs) { File.Copy(path + item, Path.Combine(outPath,topath+ "/"+item), true); } } protected override void BuildAppCompleted(BuildOptions buildOptions) { base.BuildAppCompleted(buildOptions); string outPath = GetBuildOutputPath(); // iOS 的XCode项目路径最好不能有中文,否则易出错 // 所以设置一个txt文件来标注项目名字 string dirPath = Path.GetDirectoryName(outPath); if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } string[] files = Directory.GetFiles(dirPath, ".txt"); bool exist = false; string packFileName = GetPackFileName(); foreach (string file in files) { if (Path.GetFileNameWithoutExtension(file) == packFileName) { exist = true; } else { File.Delete(file); } } if (!exist) { File.Create(Path.Combine(dirPath, packFileName + ".txt")); } // 为了过审核,需要删除OpenUrl //File.Copy(Application.dataPath + PackConstant.BuildSharedResourcePath + "/Plugins/Special/iOS/libiPhone-lib.a", Path.Combine(outPath, "Libraries/libiPhone-lib.a"), true); //CopymmFile(new string[] { "LuLuConnector.h", "LuLuConnector.mm" }, "Classes"); ChangeXCodeProject(buildOptions); } #if UNITY_IOS private void AddFrameworkToProject(PBXProject pro, string target, string[] libs, bool weak) { foreach (var item in libs) { pro.AddFrameworkToProject(target,item,weak); } } private PlistElementArray PlistAddUrlType(PlistDocument plist, PlistElementArray urlTypes,string name,string role, string url) { if (urlTypes == null) { urlTypes = plist.root.CreateArray("CFBundleURLTypes"); } PlistElementDict dict = urlTypes.AddDict(); dict.SetString("CFBundleTypeRole", role); dict.SetString("CFBundleURLName", name); dict.CreateArray("CFBundleURLSchemes").AddString(url); return urlTypes; } private void PlistCreateArray(PlistDocument plist, string name,string[] values) { PlistElementArray arr = plist.root.CreateArray(name); foreach (var item in values) { arr.AddString(item); } } class DictItem { public string type; public object data; public DictItem(string type,object data) { this.data = data; this.type = type; } } private void PlistCreateDict(PlistDocument plist,string name, Dictionary keyValues,bool isRoot = false) { PlistElementDict dict = plist.root; if(!isRoot) dict = plist.root.CreateDict(name); foreach (var item in keyValues) { switch (item.Value.type) { case "bool": { dict.SetBoolean(item.Key,(bool)item.Value.data); } break; case "int": { dict.SetInteger(item.Key,(int)item.Value.data); } break; case "float": { dict.SetReal(item.Key,(float)item.Value.data); } break; case "date": { dict.SetDate(item.Key,(System.DateTime)item.Value.data); } break; case "string": { dict.SetString(item.Key,(string)item.Value.data); } break; } } } #endif protected void ChangeXCodeProject(BuildOptions buildOptions) { #if UNITY_IOS EditorUtility.DisplayProgressBar("修改XCodeProject", "开始修改XCodeProject", 0); string outPath = GetBuildOutputPath(); PBXProject pbxProject = new PBXProject(); string pbxprojPath = PBXProject.GetPBXProjectPath(outPath); pbxProject.ReadFromFile(pbxprojPath); string targetGuid = pbxProject.GetUnityMainTargetGuid();//pbxProject.TargetGuidByName("Unity-iPhone"); string unityFmwkGUid = pbxProject.GetUnityFrameworkTargetGuid(); Debug.Log($"=================== targetGuid = {targetGuid} ==============="); //pbxProject.AddCopyFilesBuildPhase(targetGuid, "SSBundle.bundle", Application.dataPath + "/Plugins/iOS", ""); //pbxProject.SetBuildProperty(targetGuid, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym"); //pbxProject.SetBuildProperty(targetGuid, "GCC_GENERATE_DEBUGGING_SYMBOLS", "YES"); //pbxProject.SetBuildProperty(targetGuid, "COPY_PHASE_STRIP", "NO"); //pbxProject.SetBuildProperty(targetGuid, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES"); //pbxProject.SetBuildProperty(targetGuid, "GCC_ENABLE_CPP_EXCEPTIONS", "YES"); pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO"); pbxProject.AddBuildProperty(targetGuid, "OTHER_LDFLAGS", "-ObjC -lz"); pbxProject.AddBuildProperty(unityFmwkGUid, "OTHER_LDFLAGS", "-ObjC"); /* //pbxProject.SetBuildProperty(targetGuid, "SWIFT_VERSION", "5.0"); //pbxProject.AddBuildProperty(targetGuid, "Library Search Path", "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"); //pbxProject.AddBuildProperty(targetGuid, "Library Search Path", "$(SDKROOT)/usr/lib/swift"); //pbxProject.AddBuildProperty(unityFmwkGUid, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)"); //pbxProject.AddBuildProperty(targetGuid, "LIBRARY_SEARCH_PATHS", "$(SDKROOT)/usr/lib/swift"); //pbxProject.AddBuildProperty(unityFmwkGUid, "LIBRARY_SEARCH_PATHS", "$(SDKROOT)/usr/lib/swift"); //pbxProject.AddBuildProperty(targetGuid, "Runpath Search Path", "/usr/lib/swift"); //pbxProject.AddBuildProperty(targetGuid, "RUNPATH_SEARCH_PATHS", "/usr/lib/swift"); //AdSupport.framework AuthenticationServices.framework, Accelerate.framework */ //内购 pbxProject.AddCapability(targetGuid,PBXCapabilityType.InAppPurchase); pbxProject.AddCapability(targetGuid,PBXCapabilityType.SignInWithApple); /* * SDK 依赖库 * -libz.tbd -libbz2.tbd -libxml2.tbd -libresolv.9.tbd * -libsqlite3.tbd -libc++.tbd -lbc++abi.tbd * -Accelerate.framework -CoreImage.framework -CoreLocation.framework -JavaScriptCore.framework -AppTrackingTransparency.framework * -EventKit.framework -EventKitUI.framework -Security.framework */ AddFrameworkToProject(pbxProject, targetGuid,new string[] { "libz.tbd","libbz2.tbd", "libxml2.tbd","libresolv.9.tbd", "libsqlite3.tbd","libc++.tbd","lbc++abi.tbd", "Accelerate.framework","CoreImage.framework","CoreLocation.framework","JavaScriptCore.framework","AppTrackingTransparency.framework", "EventKit.framework","EventKitUI.framework","Security.framework" },false); AddFrameworkToProject(pbxProject, unityFmwkGUid, new string[] { "Accelerate.framework" },false); //pbxProject.AddAssetTagToDefaultInstall pbxProject.WriteToFile(pbxprojPath); EditorUtility.DisplayProgressBar("修改XCodeProject", "修改project.pbxproj完成", 0.25f); string plistPath = Path.Combine(outPath, "Info.plist"); PlistDocument plistDocument = new PlistDocument(); plistDocument.ReadFromFile(plistPath); PlistCreateArray(plistDocument, "LSApplicationQueriesSchemes", new string[] { "fbauth2", "fbapi", "fb-messenger-share-api", "fbshareextension", "fb-messenger-api" , "vk", "vk-share", "vkauthorize" }); //PlistCreateArray(plistDocument, "Queried URL Schemes", new string[] { "vk", "vk-share", "vkauthorize" }); PlistCreateDict(plistDocument, "NSAppTransportSecurity", new Dictionary() { { "NSAllowsArbitraryLoads", new DictItem("bool",true)} }); PlistElementArray urlTs = PlistAddUrlType(plistDocument,null,"vk","Editor", "vk51712598"); PlistAddUrlType(plistDocument, urlTs, "google", "Editor", "com.googleusercontent.apps.629791852483-g1ldf9nkll5ntqvtau1f7853pvqa4fol"); plistDocument.WriteToFile(plistPath); EditorUtility.DisplayProgressBar("修改XCodeProject", "修改info.list完成", 0.5f); if ((buildOptions & BuildOptions.AcceptExternalModificationsToPlayer) == 0) { string deviceSettingsMMPath = Path.Combine(outPath, "Classes/Unity/DeviceSettings.mm"); ObjCScript script = new ObjCScript(deviceSettingsMMPath); script.AddImport("WentingSDK.h"); script.ReplaceInLine("_VendorID = AllocCString([[UIDevice currentDevice].identifierForVendor UUIDString]);", "_VendorID = AllocCString([WentingSDK GetUUID]);"); script.Save(); //if (plugins.Contains("Lebian")) //{ // string unityAppControllerMMPath = Path.Combine(outPath, "Classes/UnityAppController.mm"); // script = new ObjCScript(unityAppControllerMMPath); // script.AddImport("LBSDK/LBInit.h", true); // int idx = script.FindLine("::printf(\"-> applicationDidFinishLaunching()\\n\");"); // script.InsertLine(idx, idx + 1); // script.InsertLine(idx, idx + 2, "// 请务必在方法的最前面调用该接口,否则很容易出问题"); // script.InsertLine(idx, idx + 3, "if ([[LBInit sharedInstance] LBSDKShouldInitWithLaunchOptions:launchOptions]) {"); // script.InsertLine(idx, idx + 4, "\treturn YES;"); // script.InsertLine(idx, idx + 5, "}"); // script.InsertLine(idx, idx + 6); // script.Save(); //} //if (plugins.Contains("WentingLicense")) //{ // string unityAppControllerMMPath = Path.Combine(outPath, "Classes/UnityAppController.mm"); // script = new ObjCScript(unityAppControllerMMPath); // script.AddImport("WentingLicense.h", false); // int idx = script.FindLine("::printf(\"-> applicationDidFinishLaunching()\\n\");"); // script.InsertLine(idx, idx + 1); // script.InsertLine(idx, idx + 2, "if ([[WentingLicense sharedInstance] CheckAgreeWithLaunchOptions:launchOptions]) {"); // script.InsertLine(idx, idx + 3, "\treturn YES;"); // script.InsertLine(idx, idx + 4, "}"); // script.InsertLine(idx, idx + 5); // script.Save(); //} //if (!string.IsNullOrEmpty(plugins.Find((x) => x.StartsWith("YOUYI")))) //{ // string unityAppControllerMMPath = Path.Combine(outPath, "Classes/UnityAppController.mm"); // script = new ObjCScript(unityAppControllerMMPath); // script.AddImport("YWBeginSDK.h", false); // int idx = script.FindLine("::printf(\"-> applicationWillEnterForeground()\\n\");"); // script.InsertLine(idx, idx + 1); // script.InsertLine(idx, idx + 2, "[[YWBeginSDK standardDeafaults] ywInterfaceApplicationWillEnterForeground];"); // script.InsertLine(idx, idx + 3); // script.Save(); //} } EditorUtility.DisplayProgressBar("修改XCodeProject", "完成修改XCodeProject", 1); EditorUtility.ClearProgressBar(); #endif } protected class ObjCScript { private string m_FilePath; private List m_Lines; private int importIdx = -1; private int includeIdx = -1; public ObjCScript(string filePath) { m_FilePath = filePath; if (!File.Exists(filePath)) { PackLog.LogError(filePath + " is not Exist"); return; } m_Lines = new List(File.ReadAllLines(filePath)); for (int i = 0, iMax = m_Lines.Count; i < iMax; i++) { string line = m_Lines[i].Trim(); if (line.StartsWith("#import ")) { importIdx = i; } if (line.StartsWith("#include ")) { includeIdx = i; } } } public void AddImport(string name, bool isframework = false) { if (m_Lines == null) { PackLog.LogError(m_FilePath + " is not Valid Objc Script"); return; } int idx = -1; if (importIdx >= 0 && importIdx < m_Lines.Count) { idx = importIdx; } if (idx == -1) { if (includeIdx >= 0 && includeIdx < m_Lines.Count) { idx = includeIdx; } } if (idx == -1) { PackLog.LogError(m_FilePath + " is not Valid Objc Script"); return; } if (isframework) { idx = idx + 1; m_Lines.Insert(idx, "#import <" + name + ">"); } else { idx = idx + 1; m_Lines.Insert(idx, "#import \"" + name + "\""); } } public int FindLine(string str) { if (m_Lines == null) { PackLog.LogError(m_FilePath + " is not Valid Objc Script"); return -1; } return m_Lines.FindIndex((x) => x.Contains(str)); } public void InsertLine(int alginIdx, int insertIdx, string str = "") { if (m_Lines == null) { PackLog.LogError(m_FilePath + " is not Valid Objc Script"); return; } if (alginIdx < 0 || alginIdx >= m_Lines.Count) { PackLog.LogError(" alginIdx is not Valid Value " + alginIdx); return; } if (insertIdx < 0 || insertIdx >= m_Lines.Count) { PackLog.LogError(" insertIdx is not Valid Value " + insertIdx); return; } if (string.IsNullOrEmpty(str)) { m_Lines.Insert(insertIdx, ""); return; } string line = m_Lines[alginIdx]; int len1 = line.Length; int len2 = len1 - line.TrimStart().Length; string startStr = line.Substring(0, len2); m_Lines.Insert(insertIdx, startStr + str); return; } public void ReplaceInLine(string oldStr, string newStr) { if (m_Lines == null) { PackLog.LogError(m_FilePath + " is not Valid Objc Script"); return; } for (int i = 0, iMax = m_Lines.Count; i < iMax; i++) { string line = m_Lines[i]; if (line.Contains(oldStr)) { m_Lines[i] = line.Replace(oldStr, newStr); } } } public void Save() { if (m_Lines == null) return; File.WriteAllLines(m_FilePath, m_Lines); } public override string ToString() { System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0, iMax = m_Lines.Count; i < iMax; i++) { sb.AppendLine(m_Lines[i]); } return sb.ToString(); } } } }