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 PlistElementDict PlistCreateDict(PlistDocument plist,string name, Dictionary keyValues,bool isRoot = false, PlistElementDict root = null) { PlistElementDict dict = plist.root; if (root == null) { root = plist.root; } if (!isRoot) dict = 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; } } return dict; } #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.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO");//enable Bitcode 设置 为 no pbxProject.AddBuildProperty(targetGuid, "OTHER_LDFLAGS", "-ObjC"); pbxProject.AddBuildProperty(unityFmwkGUid, "OTHER_LDFLAGS", "-ObjC"); // 设置 Allow Non-modular Includes in Framework Modules 为 true // pbxProject.SetBuildProperty(targetGuid, "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES", "YES"); //pbxProject.SetBuildProperty(unityFmwkGUid, "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES", "YES"); pbxProject.AddCapability(targetGuid,PBXCapabilityType.InAppPurchase);//内购 pbxProject.AddCapability(targetGuid,PBXCapabilityType.SignInWithApple);//苹果登录 //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"}); //PlistCreateArray(plistDocument, "Queried URL Schemes", new string[] { "vk", "vk-share", "vkauthorize" }); PlistCreateDict(plistDocument, "NSAppTransportSecurity", new Dictionary() { { "NSAllowsArbitraryLoads", new DictItem("bool",true)} }); //Facebook AppID IOS: 1734387583815032 PlistCreateDict(plistDocument,"",new Dictionary() { { "xuanyou_GameId", new DictItem("string", "127") }, { "FacebookAppID", new DictItem("string", "849135470863608") }, { "FacebookDisplayName", new DictItem("string", "FacebookDisplayName") }, { "NSUserTrackingUsageDescription", new DictItem("string", "App would like to access IDFA for tracking purpose") }, { "NSPhotoLibraryAddUsageDescription", new DictItem("string", "Photo Library Add Usage Description") }, { "NSPhotoLibraryUsageDescription", new DictItem("string", "Photo Library Usage Description") }, },true); PlistElementDict dict = PlistCreateDict(plistDocument, "SPAdjustConfig", new Dictionary() { { "appToken", new DictItem("string","zg6ixp19pdz4")}, }); PlistCreateDict(plistDocument, "eventTokens", new Dictionary() { { "activeEventToken", new DictItem("string","kky0yu")}, { "createRoleToken", new DictItem("string","1p4znl")}, { "firstPayEventToken", new DictItem("string","p6p840")}, { "noviceGuideEventToken", new DictItem("string","21l1no")}, { "payEventToken", new DictItem("string","ot7zkz")}, { "registerEventToken", new DictItem("string","6s22py")}, },false, dict); PlistAddUrlType(plistDocument, null, "facebook", "Editor", "fb849135470863608"); 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(); } 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,bool ismode = 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; if (ismode) { m_Lines.Insert(idx, "@import " + name + ";"); } else { 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(); } } } }