public static void AddFrameworkToProject(framework framework, ref string contents) { string orientationSupport = "Ref = 8AC71EC319E7FBA90027502F /* OrientationSupport.mm */; };"; string pbxFileReference = "wnFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };"; string pbsFrameworksBuildPhase = "1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,"; string frameworksSection = "1D30AB110D05D00D00671497 /* Foundation.framework */,"; contents = contents.Replace(orientationSupport, orientationSupport + "\n\t\t" + framework.id + " /* " + framework.name + ".framework in Frameworks */ = {isa = PBXBuildFile; fileRef = " + framework.fileId + " /* " + framework.name + ".framework */; };"); contents = contents.Replace(pbxFileReference, pbxFileReference + "\n\t\t" + framework.fileId + " /* " + framework.name + ".framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = " + framework.name + ".framework; path = System/Library/Frameworks/" + framework.name + ".framework; sourceTree = SDKROOT; };"); contents = contents.Replace(pbsFrameworksBuildPhase, framework.id + " /* " + framework.name + ".framework in Frameworks */,\n\t\t\t\t" + pbsFrameworksBuildPhase); contents = contents.Replace(frameworksSection, framework.fileId + " /* " + framework.name + ".framework */,\n\t\t\t\t" + frameworksSection); }
public static void LinkLibraries(BuildTarget target, string pathToBuiltProject) { framework[] frameworksToAdd = new framework[1]; frameworksToAdd[0] = new framework("UserNotifications", "CAF63D112040CD8E00A651DC", "CAF63D102040CD8E00A651DC"); string projectFile = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj"; string contents = File.ReadAllText(projectFile); foreach (framework framework in frameworksToAdd) { AddFrameworkToProject(framework, ref contents); } File.WriteAllText(projectFile, contents); }
// MAIN FUNCTION // xcodeproj_filename - filename of the Xcode project to change // frameworks - list of Apple standard frameworks to add to the project public static void updateXcodeProject(string xcodeprojPath, framework[] listFrameworks) { Debug.Log("MAT framework source = " + Path.Combine(MAT_FRAMEWORK_FOLDER_PATH, listFrameworks[0].sName)); Debug.Log("MAT framework target = " + listFrameworks[0].sPath); // Copy the MobileAppTracker.framework copyDirectory(Path.Combine(MAT_FRAMEWORK_FOLDER_PATH, listFrameworks[0].sName), Path.Combine(listFrameworks[0].sPath, listFrameworks[0].sName), true); // STEP 1 : // Create an array of strings by reading in all lines from the xcode project file. string project = xcodeprojPath + "/project.pbxproj"; string[] lines = System.IO.File.ReadAllLines(project); // STEP 2 : // Loop through the project file text and check if MobileAppTracker.framework exists under the frameworks list. // If it exists then the file has already been processed and we skip this file update. int i = 0; bool bFound = false; bool bEnd = false; while (!bFound && !bEnd) { if (lines[i].Length > 5 && (string.Compare(lines[i].Substring(3, 3), "End") == 0) ) bEnd = true; bFound = lines[i].Contains(FRAMEWORK_MOBILEAPPTRACKER); ++i; } if (bFound) { Debug.Log("OnPostProcessBuild - WARNING: Frameworks have already been added to Xcode project"); } else { // STEP 3 : // Edit the project.pbxproj to allow the use of MobileAppTracker.framework. FileStream filestr = new FileStream(project, FileMode.Create); //Create new file and open it for read and write, if the file exists overwrite it. filestr.Close(); StreamWriter fCurrentXcodeProjFile = new StreamWriter(project); // will be used for writing // As we iterate through the list we'll record which section of the // project.pbxproj we are currently in string section = string.Empty; // We use this boolean to decide whether we have already added the list of // build files to the link line. This is needed because there could be multiple // build targets and they are not named in the project.pbxproj bool bFrameworks_build_added = false; i = 0; foreach (string line in lines) { fCurrentXcodeProjFile.WriteLine(line); ////////////////////////////////// // STEP 1 : Include Framewoks // ////////////////////////////////// // Each section starts with a comment such as : /* Begin PBXBuildFile section */' if ( line.Length > 7 && string.Compare(line.Substring(3, 5), "Begin") == 0 ) { section = line.Split(' ')[2]; Debug.Log("NEW_SECTION: "+section); if (section == "PBXBuildFile") { // Add one entry for each framework to the PBXBuildFile section foreach (framework fr in listFrameworks) { add_build_file(fCurrentXcodeProjFile, fr.sId, fr.sName, fr.sFileId, fr.sWeak); } } if (section == "PBXFileReference") { // Add one entry for each framework to the PBXFileReference section foreach (framework fr in listFrameworks) { add_framework_file_reference(fCurrentXcodeProjFile, fr.sFileId, fr.sName, fr.sPath); } } if (line.Length > 5 && string.Compare(line.Substring(3, 3), "End") == 0) { section = string.Empty; } } // The PBXResourcesBuildPhase section is what appears in XCode as 'Link // Binary With Libraries'. As with the frameworks we make the assumption the // first target is always 'Unity-iPhone' as the name of the target itself is // not listed in project.pbxproj if (section == "PBXFrameworksBuildPhase" && line.Trim().Length > 4 && string.Compare(line.Trim().Substring(0, 5) , "files") == 0 && !bFrameworks_build_added) { // Add one entry for each framework to the PBXFrameworksBuildPhase section foreach (framework fr in listFrameworks) { add_frameworks_build_phase(fCurrentXcodeProjFile, fr.sId, fr.sName); } bFrameworks_build_added = true; } // The PBXGroup is the section that appears in XCode as 'Copy Bundle Resources'. if (section == "PBXGroup" && line.Trim().Length > 7 && string.Compare(line.Trim().Substring(0, 8) , "children") == 0 && lines[i-2].Trim().Split(' ').Length > 0 && string.Compare(lines[i-2].Trim().Split(' ')[2] , "CustomTemplate" ) == 0 ) { Debug.Log("Adding frameworks in PBXGroup"); foreach (framework fr in listFrameworks) { Debug.Log(fr.sName); add_group(fCurrentXcodeProjFile, fr.sFileId, fr.sName); } } ////////////////////////////// // STEP 2 : Build Options // ////////////////////////////// if (section == "XCBuildConfiguration" && line.StartsWith("\t\t\t\tOTHER_CFLAGS")) { Debug.Log("OnPostProcessBuild - Adding FRAMEWORK_SEARCH_PATHS"); // Add "." to the framework search path fCurrentXcodeProjFile.Write("\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(SRCROOT)/" + "." + "\\\"\",\n\t\t\t\t);\n"); } ++i; } fCurrentXcodeProjFile.Close(); } }
_ => RestoreObject(framework, oid)
public static void updateXcodeProject(string xcodeprojPath, framework[] listeFrameworks) { //Modify Info.plist string infoPath = xcodeprojPath + "/../Info.plist"; if(File.Exists(infoPath)) { string[] plistLines = File.ReadAllLines(infoPath); List<string> newPlist = new List<string>(plistLines); long len = plistLines.Length - 1; int insertLine = -1; //If the entry is found this will be kept at -1 //Add an SSL flag if enabled #if FUSE_USE_SSL for(int l = 0; l < len; l++) { if(newPlist[l].Contains("plist") && newPlist[l+1].Contains("dict")) { insertLine = l + 2; } if(newPlist[l].Contains("fuse_ssl")) { if(newPlist[l+1].Contains("false")) { newPlist[l+1] = newPlist[l+1].Replace("false", "true"); } insertLine = -1; break; } } //If the flag doesn't exist, add it now if(insertLine != -1) { newPlist.Insert(insertLine, @" <key>fuse_ssl</key>"); newPlist.Insert(insertLine + 1, @" <true/>"); } #endif //Add the entries with Calendar permission strings insertLine = -1; len = newPlist.Count - 1; for(int l = 0; l < len; l++) { if(newPlist[l].Contains("plist") && newPlist[l + 1].Contains("dict")) { insertLine = l + 2; } if(newPlist[l].Contains("NSCalendarsUsageDescription")) { insertLine = -1; break; } } if(insertLine != -1) { newPlist.Insert(insertLine, @" <key>NSCalendarsUsageDescription</key>"); newPlist.Insert(insertLine + 1, @" <string>Advertisement would like to create a calendar event.</string>"); } //Add the entries with Photo Library permission strings insertLine = -1; len = newPlist.Count - 1; for(int l = 0; l < len; l++) { if(newPlist[l].Contains("plist") && newPlist[l + 1].Contains("dict")) { insertLine = l + 2; } if(newPlist[l].Contains("NSPhotoLibraryUsageDescription")) { insertLine = -1; break; } } if(insertLine != -1) { newPlist.Insert(insertLine, @" <key>NSPhotoLibraryUsageDescription</key>"); newPlist.Insert(insertLine + 1, @" <string>Advertisement would like to store a photo.</string>"); } //Add the entries with Camera permission strings insertLine = -1; len = newPlist.Count - 1; for(int l = 0; l < len; l++) { if(newPlist[l].Contains("plist") && newPlist[l + 1].Contains("dict")) { insertLine = l + 2; } if(newPlist[l].Contains("NSCameraUsageDescription")) { insertLine = -1; break; } } if(insertLine != -1) { newPlist.Insert(insertLine, @" <key>NSCameraUsageDescription</key>"); newPlist.Insert(insertLine + 1, @" <string>Advertisement would like to use your camera.</string>"); } //Add the entries with Motion permission strings insertLine = -1; len = newPlist.Count - 1; for(int l = 0; l < len; l++) { if(newPlist[l].Contains("plist") && newPlist[l + 1].Contains("dict")) { insertLine = l + 2; } if(newPlist[l].Contains("NSMotionUsageDescription")) { insertLine = -1; break; } } if(insertLine != -1) { newPlist.Insert(insertLine, @" <key>NSMotionUsageDescription</key>"); newPlist.Insert(insertLine + 1, @" <string>Advertisement would like to use motion for interactive ad controls</string>"); } //Write out the new plist File.WriteAllLines(infoPath, newPlist.ToArray()); } else { UnityEngine.Debug.LogError("Could not find Info.plist. You will need to edit this file manually"); } // STEP 1 : We open up the file generated by Unity and read into memory as // a list of lines for processing string project = xcodeprojPath + "/project.pbxproj"; if(!System.IO.File.Exists(project)) { UnityEngine.Debug.LogError("Could not find Xcode project at the expected location. You will need to manually add CoreTelephony, AdSupport, MessageUI, EventKit, EventKitUI, Twitter, Social, and StoreKit frameworks and the -ObjC linker flag"); return; } #if UNITY_IOS // Uncomment to Test xml project settings // ProcessStartInfo proc = new ProcessStartInfo(); // proc.FileName = "plutil"; // proc.WorkingDirectory = xcodeprojPath; // proc.Arguments = "-convert xml1 project.pbxproj"; // proc.WindowStyle = ProcessWindowStyle.Minimized; // proc.CreateNoWindow = true; // Process process = Process.Start(proc); // process.WaitForExit(); // UnityEngine.Debug.Log("Converting project.pbxProj to xml"); #endif string[] lines = System.IO.File.ReadAllLines(project); // STEP 2 : We process only the missing frameworks bool isXML = (string.Compare(lines[0].Substring(2, 3), "xml") == 0) || (string.Compare(lines[0].Substring(2, 3), "Xml") == 0); int i = 0; bool bEnd = false; while(!bEnd && i < lines.Length) { if(lines[i].Length > 5 && (string.Compare(lines[i].Substring(3, 3), "End") == 0) && !isXML) bEnd = true; if(lines[i].Contains("CoreTelephony.framework")) { bFoundCore = true; } else if(lines[i].Contains("AdSupport.framework")) { bFoundAd = true; } else if(lines[i].Contains("StoreKit.framework")) { bFoundStore = true; } else if(lines[i].Contains("MessageUI.framework")) { bFoundMessage = true; } else if(lines[i].Contains("EventKit.framework")) { bFoundEvent = true; } else if(lines[i].Contains("EventKitUI.framework")) { bFoundEventUI = true; } else if(lines[i].Contains("Twitter.framework")) { bFoundTwitter = true; } else if(lines[i].Contains("Social.framework")) { bFoundSocial = true; } else if(lines[i].Contains("Security.framework")) { bFoundSecurity = true; } else if(lines[i].Contains("WebKit.framework")) { bFoundWebKit = true; } else if (lines[i].Contains("GameKit.framework")) { bFoundGameKit = true; } else if(lines[i].Contains("UIKit.framework")) { bFoundUIKit = true; } else if(lines[i].Contains("GLKit.framework")) { bFoundGLKit = true; } else if(lines[i].Contains("JavaScriptCore.framework")) { bFoundJSCore = true; } else if(lines[i].Contains("UserNotifications.framework")) { bFoundNotifications = true; } else if(lines[i].Contains("libsqlite3.tbd")) { bFoundSQLite = true; } else if(lines[i].Contains("MobileCoreServices.framework")) { bFoundMCS = true; } else if(lines[i].Contains("libxml2.tbd")) { bFoundLibXML = true; } else if(lines[i].Contains("libz.tbd")) { bFoundLibZ = true; } ++i; } // STEP 3 : We'll open/replace project.pbxproj for writing and iterate over the old // file in memory, copying the original file and inserting every extra we need if(isXML) { UnityEngine.Debug.Log("project.pbxProj is xml, using XML script"); XmlDocument projXml = new XmlDocument(); projXml.PreserveWhitespace = true; projXml.LoadXml(System.IO.File.ReadAllText(project)); XmlNode outerDict = null; XmlNode innerDict = null; foreach(XmlNode node in projXml.ChildNodes) if(node.Name == "plist") foreach(XmlNode child in node.ChildNodes) if(child.Name == "dict") outerDict = child; if(outerDict != null) { foreach(XmlNode node in outerDict.ChildNodes) if(node.Name == "dict" && node.HasChildNodes) innerDict = node; } if(innerDict != null) { foreach(framework fr in listeFrameworks) { add_build_file_xml(innerDict, fr.sId, fr.sName, fr.sFileId); add_framework_file_reference_xml(innerDict, fr.sFileId, fr.sName); add_frameworks_build_phase_xml(innerDict, fr.sId, fr.sName); add_group_xml(innerDict, fr.sFileId, fr.sName); } add_ldFlags_xml(innerDict, "-ObjC"); FileStream filestr = new FileStream(project, FileMode.Create); //Create new file and open it for read and write, if the file exists overwrite it. filestr.Close(); projXml.Save(project); //this is gonna be a dirty, dirty hack. string[] lines2 = System.IO.File.ReadAllLines(project); lines2[1] = lines[1]; UnityEngine.Debug.Log("fixing line: " + lines2[1]); filestr = new FileStream(project, FileMode.Create); //Create new file and open it for read and write, if the file exists overwrite it. filestr.Close(); StreamWriter fCurrentXcodeProjFile = new StreamWriter(project); // will be used for writing foreach(string line in lines2) { fCurrentXcodeProjFile.WriteLine(line); } fCurrentXcodeProjFile.Close(); } else { UnityEngine.Debug.Log("project.pbxProj is xml but not in expected format! Please contact fuse support for more information"); } } else { FileStream filestr = new FileStream(project, FileMode.Create); //Create new file and open it for read and write, if the file exists overwrite it. filestr.Close(); StreamWriter fCurrentXcodeProjFile = new StreamWriter(project); // will be used for writing // As we iterate through the list we'll record which section of the // project.pbxproj we are currently in string section = ""; // We use this boolean to decide whether we have already added the list of // build files to the link line. This is needed because there could be multiple // build targets and they are not named in the project.pbxproj bool bFrameworks_build_added = false; int iNbBuildConfigSet = 0; // can't be > 2 i = 0; foreach(string line in lines) { // set Foundation.framework to weak linked if(line.Contains("/* Foundation.framework in Frameworks */ = {isa = PBXBuildFile;") && !line.Contains("settings = {ATTRIBUTES = (Weak, ); };")) { // rewrite the line to set the library as weak linked UnityEngine.Debug.Log("Setting Foundation.framkework to weak link."); string[] splitstring = line.Split(';'); string output = splitstring[0] + ";" + splitstring[1] + "; " + "settings = {ATTRIBUTES = (Weak, ); }; };"; fCurrentXcodeProjFile.WriteLine(output); } // set UIKit.framework to weak linked else if(line.Contains("/* UIKit.framework in Frameworks */ = {isa = PBXBuildFile;") && !line.Contains("settings = {ATTRIBUTES = (Weak, ); };")) { // rewrite the line to set the library as weak linked UnityEngine.Debug.Log("Setting UIKit.framkework to weak link."); string[] splitstring = line.Split(';'); string output = splitstring[0] + ";" + splitstring[1] + "; " + "settings = {ATTRIBUTES = (Weak, ); }; };"; fCurrentXcodeProjFile.WriteLine(output); } //Mark FuseUnitySDK.m as -fno-objc-arc else if(line.Contains("/* FuseUnitySDK.m in Sources */ = {isa = PBXBuildFile;") && !line.Contains(@"settings = {COMPILER_FLAGS = ""-fno-objc-arc""; };")) { UnityEngine.Debug.Log("Marking FuseUnitySDK.m as -fno-objc-arc."); string[] splitstring = line.Split(';'); string output = string.Join(";", splitstring, 0, splitstring.Length - 2) + @"; settings = {COMPILER_FLAGS = ""-fno-objc-arc""; }; };"; fCurrentXcodeProjFile.WriteLine(output); } //Mark FuseUnityDebug.m as -fno-objc-arc else if(line.Contains("/* FuseUnityDebug.m in Sources */ = {isa = PBXBuildFile;") && !line.Contains(@"settings = {COMPILER_FLAGS = ""-fno-objc-arc""; };")) { UnityEngine.Debug.Log("Marking FuseUnityDebug.m as -fno-objc-arc."); string[] splitstring = line.Split(';'); string output = string.Join(";", splitstring, 0, splitstring.Length - 2) + @"; settings = {COMPILER_FLAGS = ""-fno-objc-arc""; }; };"; fCurrentXcodeProjFile.WriteLine(output); } //Mark NSData-Base64.m as -fno-objc-arc else if(line.Contains("/* NSData-Base64.m in Sources */ = {isa = PBXBuildFile;") && !line.Contains(@"settings = {COMPILER_FLAGS = ""-fno-objc-arc""; };")) { UnityEngine.Debug.Log("Marking NSData-Base64.m as -fno-objc-arc."); string[] splitstring = line.Split(';'); string output = string.Join(";", splitstring, 0, splitstring.Length - 2) + @"; settings = {COMPILER_FLAGS = ""-fno-objc-arc""; }; };"; fCurrentXcodeProjFile.WriteLine(output); } else if(line.Contains("ENABLE_BITCODE")) { // Disable bitcode UnityEngine.Debug.Log("Disabling bitcode."); fCurrentXcodeProjFile.WriteLine(line.Replace("YES", "NO")); } else { fCurrentXcodeProjFile.WriteLine(line); } ////////////////////////////////// // STEP 2 : Include Framewoks // ////////////////////////////////// // Each section starts with a comment such as : /* Begin PBXBuildFile section */' if(lines[i].Length > 7 && string.Compare(lines[i].Substring(3, 5), "Begin") == 0) { section = line.Split(' ')[2]; //Debug.Log("NEW_SECTION: "+section); if(section == "PBXBuildFile") { foreach(framework fr in listeFrameworks) add_build_file(fCurrentXcodeProjFile, fr.sId, fr.sName, fr.sFileId); } if(section == "PBXFileReference") { foreach(framework fr in listeFrameworks) add_framework_file_reference(fCurrentXcodeProjFile, fr.sFileId, fr.sName); } if(line.Length > 5 && string.Compare(line.Substring(3, 3), "End") == 0) section = ""; } // The PBXResourcesBuildPhase section is what appears in XCode as 'Link // Binary With Libraries'. As with the frameworks we make the assumption the // first target is always 'Unity-iPhone' as the name of the target itself is // not listed in project.pbxproj if(section == "PBXFrameworksBuildPhase" && line.Trim().Length > 4 && string.Compare(line.Trim().Substring(0, 5), "files") == 0 && !bFrameworks_build_added) { foreach(framework fr in listeFrameworks) add_frameworks_build_phase(fCurrentXcodeProjFile, fr.sId, fr.sName); bFrameworks_build_added = true; } // The PBXGroup is the section that appears in XCode as 'Copy Bundle Resources'. if(section == "PBXGroup" && line.Trim().Length > 7 && string.Compare(line.Trim().Substring(0, 8), "children") == 0 && lines[i - 2].Trim().Split(' ').Length > 0 && string.Compare(lines[i - 2].Trim().Split(' ')[2], "CustomTemplate") == 0) { foreach(framework fr in listeFrameworks) add_group(fCurrentXcodeProjFile, fr.sFileId, fr.sName); } ////////////////////////////// // STEP 3 : Build Options // ////////////////////////////// if(section == "XCBuildConfiguration" && line.StartsWith("\t\t\t\tOTHER_LDFLAGS") && iNbBuildConfigSet < 2) { int j = 0; bool bFlagSet = false; while(string.Compare(lines[i + j].Trim(), "};") != 0) { if(lines[i + j].Contains("ObjC")) { bFlagSet = true; } j++; } if(!bFlagSet) { //fCurrentXcodeProjFile.Write("\t\t\t\t\t\"-all_load\",\n"); fCurrentXcodeProjFile.Write("\t\t\t\t\t\"-ObjC\",\n"); UnityEngine.Debug.Log("OnPostProcessBuild - Adding \"-ObjC\" flag to build options"); // \"-all_load\" and } ++iNbBuildConfigSet; } i++; } fCurrentXcodeProjFile.Close(); } }
// MAIN FUNCTION // xcodeproj_filename - filename of the Xcode project to change // frameworks - list of Apple standard frameworks to add to the project public static void updateXcodeProject(string xcodeprojPath, Dictionary <string, framework> dictFrameworks) { // STEP 1 : // Create an array of strings by reading in all lines from the xcode project file. string project = xcodeprojPath + "/project.pbxproj"; string[] lines = System.IO.File.ReadAllLines(project); // STEP 2 : // Loop through the project file text and find out if all the required frameworks already exist. int i = 0; bool bFound = false; bool bEnd = false; bool existsCORETELEPHONY = false; bool existsIAD = false; bool existsMOBILECORESERVICES = false; bool existsSTOREKIT = false; bool existsSYSTEMCONFIGURATION = false; Debug.Log("total frameworks required = " + dictFrameworks.Count); while (!bFound && !bEnd) { if (lines[i].Length > 5 && (string.Compare(lines[i].Substring(3, 3), "End") == 0)) { bEnd = true; } if (lines [i].Contains(FRAMEWORK_CORETELEPHONY)) { existsCORETELEPHONY = true; dictFrameworks.Remove(FRAMEWORK_CORETELEPHONY); } else if (lines [i].Contains(FRAMEWORK_IAD)) { existsIAD = true; dictFrameworks.Remove(FRAMEWORK_IAD); } else if (lines [i].Contains(FRAMEWORK_MOBILECORESERVICES)) { existsMOBILECORESERVICES = true; dictFrameworks.Remove(FRAMEWORK_MOBILECORESERVICES); } else if (lines [i].Contains(FRAMEWORK_STOREKIT)) { existsSTOREKIT = true; dictFrameworks.Remove(FRAMEWORK_STOREKIT); } else if (lines [i].Contains(FRAMEWORK_SYSTEMCONFIGURATION)) { existsSYSTEMCONFIGURATION = true; dictFrameworks.Remove(FRAMEWORK_SYSTEMCONFIGURATION); } bFound = existsCORETELEPHONY && existsIAD && existsMOBILECORESERVICES && existsSTOREKIT && existsSYSTEMCONFIGURATION; ++i; } Debug.Log("frameworks to add = " + dictFrameworks.Count); if (bFound) { Debug.Log("OnPostProcessBuild - WARNING: The frameworks required by MobileAppTracker are already present in the Xcode project. Nothing to add."); } else { // STEP 3 : // Edit the project.pbxproj and include the missing frameworks required by MobileAppTracker. FileStream filestr = new FileStream(project, FileMode.Create); //Create new file and open it for read and write, if the file exists overwrite it. filestr.Close(); StreamWriter fCurrentXcodeProjFile = new StreamWriter(project); // will be used for writing // As we iterate through the list we'll record which section of the // project.pbxproj we are currently in string section = string.Empty; // We use this boolean to decide whether we have already added the list of // build files to the link line. This is needed because there could be multiple // build targets and they are not named in the project.pbxproj bool bFrameworks_build_added = false; i = 0; foreach (string line in lines) { ////////////////////////////// // STEP 1 : Build Options // ////////////////////////////// if (section == "XCBuildConfiguration" && line.StartsWith("\t\t\t\tOTHER_CFLAGS")) { Debug.Log("OnPostProcessBuild - Adding FRAMEWORK_SEARCH_PATHS"); // Add "." to the framework search path fCurrentXcodeProjFile.Write("\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(SRCROOT)/" + "." + "\\\"\",\n\t\t\t\t);\n"); } fCurrentXcodeProjFile.WriteLine(line); ////////////////////////////////// // STEP 2 : Include Frameworks // ////////////////////////////////// // Each section starts with a comment such as : /* Begin PBXBuildFile section */' if (line.Length > 7 && string.Compare(line.Substring(3, 5), "Begin") == 0) { section = line.Split(' ')[2]; Debug.Log("NEW_SECTION: " + section); if (section == "PBXBuildFile") { // Add one entry for each framework to the PBXBuildFile section // Loop over pairs with foreach foreach (KeyValuePair <string, framework> pair in dictFrameworks) { framework fr = pair.Value; add_build_file(fCurrentXcodeProjFile, fr.sId, fr.sName, fr.sFileId, fr.sWeak); } } if (section == "PBXFileReference") { // Add one entry for each framework to the PBXFileReference section // Loop over pairs with foreach foreach (KeyValuePair <string, framework> pair in dictFrameworks) { framework fr = pair.Value; add_framework_file_reference(fCurrentXcodeProjFile, fr.sFileId, fr.sName, fr.sPath); } } if (line.Length > 5 && string.Compare(line.Substring(3, 3), "End") == 0) { section = string.Empty; } } // The PBXResourcesBuildPhase section is what appears in XCode as 'Link // Binary With Libraries'. As with the frameworks we make the assumption the // first target is always 'Unity-iPhone' as the name of the target itself is // not listed in project.pbxproj if (section == "PBXFrameworksBuildPhase" && line.Trim().Length > 4 && string.Compare(line.Trim().Substring(0, 5), "files") == 0 && !bFrameworks_build_added) { // Add one entry for each framework to the PBXFrameworksBuildPhase section // Loop over pairs with foreach foreach (KeyValuePair <string, framework> pair in dictFrameworks) { framework fr = pair.Value; add_frameworks_build_phase(fCurrentXcodeProjFile, fr.sId, fr.sName); } bFrameworks_build_added = true; } // The PBXGroup is the section that appears in XCode as 'Copy Bundle Resources'. if (section == "PBXGroup" && line.Trim().Length > 7 && string.Compare(line.Trim().Substring(0, 8), "children") == 0 && lines[i - 2].Trim().Split(' ').Length > 0 && string.Compare(lines[i - 2].Trim().Split(' ')[2], "CustomTemplate") == 0) { Debug.Log("Adding frameworks in PBXGroup"); // Loop over pairs with foreach foreach (KeyValuePair <string, framework> pair in dictFrameworks) { framework fr = pair.Value; Debug.Log(fr.sName); add_group(fCurrentXcodeProjFile, fr.sFileId, fr.sName); } } ++i; } fCurrentXcodeProjFile.Close(); } }
// MAIN FUNCTION // xcodeproj_filename - filename of the Xcode project to change // frameworks - list of Apple standard frameworks to add to the project public static void updateXcodeProject(string xcodeprojPath, framework[] listeFrameworks) { // STEP 1 : We open up the file generated by Unity and read into memory as // a list of lines for processing string project = xcodeprojPath + "/project.pbxproj" ; string[] lines = System.IO.File.ReadAllLines(project); // STEP 2 : We check if file has already been processed and only proceed if it hasn't, // we'll do this by looping through the build files and see if CoreTelephony.framework // is there int i = 0 ; bool bFound = false ; bool bEnd = false ; while ( !bFound && !bEnd) { if (lines[i].Length > 5 && (String.Compare(lines[i].Substring(3, 3), "End") == 0) ) bEnd = true ; bFound = lines[i].Contains("CoreTelephony.framework") ; ++i ; } if (bFound) Debug.Log("OnPostProcessBuild - ERROR: Frameworks have already been added to XCode project") ; else { // STEP 3 : We'll open/replace project.pbxproj for writing and iterate over the old // file in memory, copying the original file and inserting every extra we need FileStream filestr = new FileStream(project, FileMode.Create); //Create new file and open it for read and write, if the file exists overwrite it. filestr.Close() ; StreamWriter fCurrentXcodeProjFile = new StreamWriter(project) ; // will be used for writing // As we iterate through the list we'll record which section of the // project.pbxproj we are currently in string section = "" ; // We use this boolean to decide whether we have already added the list of // build files to the link line. This is needed because there could be multiple // build targets and they are not named in the project.pbxproj bool bFrameworks_build_added = false ; int iNbBuildConfigSet = 0 ; // can't be > 2 i = 0 ; foreach (string line in lines) { // if (line.StartsWith("\t\t\t\tGCC_ENABLE_CPP_EXCEPTIONS") || line.StartsWith("\t\t\t\tGCC_ENABLE_CPP_RTTI") || line.StartsWith("\t\t\t\tGCC_ENABLE_OBJC_EXCEPTIONS") ){ // apparently, we don't copy those lines in our new project //} else { fCurrentXcodeProjFile.WriteLine(line) ; ////////////////////////////////// // STEP 2 : Include Framewoks // ////////////////////////////////// // Each section starts with a comment such as : /* Begin PBXBuildFile section */' if ( lines[i].Length > 7 && String.Compare(lines[i].Substring(3, 5), "Begin") == 0 ) { section = line.Split(' ')[2] ; //Debug.Log("NEW_SECTION: "+section) ; if (section == "PBXBuildFile") { foreach (framework fr in listeFrameworks) add_build_file(fCurrentXcodeProjFile, fr.sId, fr.sName, fr.sFileId) ; } if (section == "PBXFileReference") { foreach (framework fr in listeFrameworks) add_framework_file_reference(fCurrentXcodeProjFile, fr.sFileId, fr.sName) ; } if (line.Length > 5 && String.Compare(line.Substring(3, 3), "End") == 0) section = "" ; } // The PBXResourcesBuildPhase section is what appears in XCode as 'Link // Binary With Libraries'. As with the frameworks we make the assumption the // first target is always 'Unity-iPhone' as the name of the target itself is // not listed in project.pbxproj if (section == "PBXFrameworksBuildPhase" && line.Trim().Length > 4 && String.Compare(line.Trim().Substring(0, 5) , "files") == 0 && !bFrameworks_build_added) { foreach (framework fr in listeFrameworks) add_frameworks_build_phase(fCurrentXcodeProjFile, fr.sId, fr.sName) ; bFrameworks_build_added = true ; } // The PBXGroup is the section that appears in XCode as 'Copy Bundle Resources'. if (section == "PBXGroup" && line.Trim().Length > 7 && String.Compare(line.Trim().Substring(0, 8) , "children") == 0 && lines[i-2].Trim().Split(' ').Length > 0 && String.Compare(lines[i-2].Trim().Split(' ')[2] , "CustomTemplate" ) == 0 ) { foreach (framework fr in listeFrameworks) add_group(fCurrentXcodeProjFile, fr.sFileId, fr.sName) ; } ////////////////////////////// // STEP 3 : Build Options // ////////////////////////////// // // AdColony needs "Other Linker Flags" to have "-all_load -ObjC" added to its value // ////////////////////////////// if (section == "XCBuildConfiguration" && line.StartsWith("\t\t\t\tOTHER_LDFLAGS") && iNbBuildConfigSet < 2) { //fCurrentXcodeProjFile.Write("\t\t\t\t\t\"-all_load\",\n") ; fCurrentXcodeProjFile.Write("\t\t\t\t\t\"-ObjC\",\n") ; Debug.Log("OnPostProcessBuild - Adding \"-ObjC\" flag to build options") ; // \"-all_load\" and ++iNbBuildConfigSet ; } // } ++i ; } fCurrentXcodeProjFile.Close() ; } }
public static void updateXcodeProject(string xcodeprojPath, framework[] listeFrameworks) { // STEP 1 : We open up the file generated by Unity and read into memory as // a list of lines for processing string project = xcodeprojPath + "/project.pbxproj"; if( !System.IO.File.Exists(project) ) { Debug.LogError("Could not find Xcode project at the expected location. You will need to manually add CoreTelephony, AdSupport, and StoreKit frameworks and the -ObjC linker flag"); return; } string[] lines = System.IO.File.ReadAllLines(project); // STEP 2 : We process only the missing frameworks int i = 0; bool bEnd = false; while( !bEnd && i < lines.Length ) { if (lines[i].Length > 5 && (string.Compare(lines[i].Substring(3, 3), "End") == 0) ) bEnd = true; if( lines[i].Contains("CoreTelephony.framework") ) { bFoundCore = true; } else if( lines[i].Contains("AdSupport.framework") ) { bFoundAd = true; } else if( lines[i].Contains("StoreKit.framework") ) { bFoundStore = true; } ++i; } // STEP 3 : We'll open/replace project.pbxproj for writing and iterate over the old // file in memory, copying the original file and inserting every extra we need FileStream filestr = new FileStream(project, FileMode.Create); //Create new file and open it for read and write, if the file exists overwrite it. filestr.Close(); StreamWriter fCurrentXcodeProjFile = new StreamWriter(project); // will be used for writing // As we iterate through the list we'll record which section of the // project.pbxproj we are currently in string section = ""; // We use this boolean to decide whether we have already added the list of // build files to the link line. This is needed because there could be multiple // build targets and they are not named in the project.pbxproj bool bFrameworks_build_added = false; int iNbBuildConfigSet = 0; // can't be > 2 i = 0; foreach (string line in lines) { fCurrentXcodeProjFile.WriteLine(line); ////////////////////////////////// // STEP 2 : Include Framewoks // ////////////////////////////////// // Each section starts with a comment such as : /* Begin PBXBuildFile section */' if ( lines[i].Length > 7 && string.Compare(lines[i].Substring(3, 5), "Begin") == 0 ) { section = line.Split(' ')[2]; //Debug.Log("NEW_SECTION: "+section); if (section == "PBXBuildFile") { foreach (framework fr in listeFrameworks) add_build_file(fCurrentXcodeProjFile, fr.sId, fr.sName, fr.sFileId); } if (section == "PBXFileReference") { foreach (framework fr in listeFrameworks) add_framework_file_reference(fCurrentXcodeProjFile, fr.sFileId, fr.sName); } if (line.Length > 5 && string.Compare(line.Substring(3, 3), "End") == 0) section = ""; } // The PBXResourcesBuildPhase section is what appears in XCode as 'Link // Binary With Libraries'. As with the frameworks we make the assumption the // first target is always 'Unity-iPhone' as the name of the target itself is // not listed in project.pbxproj if (section == "PBXFrameworksBuildPhase" && line.Trim().Length > 4 && string.Compare(line.Trim().Substring(0, 5) , "files") == 0 && !bFrameworks_build_added) { foreach (framework fr in listeFrameworks) add_frameworks_build_phase(fCurrentXcodeProjFile, fr.sId, fr.sName); bFrameworks_build_added = true; } // The PBXGroup is the section that appears in XCode as 'Copy Bundle Resources'. if (section == "PBXGroup" && line.Trim().Length > 7 && string.Compare(line.Trim().Substring(0, 8) , "children") == 0 && lines[i-2].Trim().Split(' ').Length > 0 && string.Compare(lines[i-2].Trim().Split(' ')[2] , "CustomTemplate" ) == 0 ) { foreach (framework fr in listeFrameworks) add_group(fCurrentXcodeProjFile, fr.sFileId, fr.sName); } ////////////////////////////// // STEP 3 : Build Options // ////////////////////////////// if (section == "XCBuildConfiguration" && line.StartsWith("\t\t\t\tOTHER_LDFLAGS") && iNbBuildConfigSet < 2) { int j = 0; bool bFlagSet = false; while( string.Compare(lines[i+j].Trim(), "};") != 0 ) { if( lines[i+j].Contains("ObjC") ) { bFlagSet = true; } j++; } if( !bFlagSet ) { //fCurrentXcodeProjFile.Write("\t\t\t\t\t\"-all_load\",\n"); fCurrentXcodeProjFile.Write("\t\t\t\t\t\"-ObjC\",\n"); Debug.Log("OnPostProcessBuild - Adding \"-ObjC\" flag to build options"); // \"-all_load\" and } ++iNbBuildConfigSet; } i++; } fCurrentXcodeProjFile.Close(); }