Search Unity

Unity xcode api

Discussion in 'iOS and tvOS' started by Jeffom, Nov 20, 2014.

  1. Jeffom

    Jeffom

    Joined:
    Oct 6, 2010
    Posts:
    55
    Guhanesh and georgepiva like this.
  2. cbaltzer

    cbaltzer

    Joined:
    Jan 11, 2012
    Posts:
    120
  3. Umai

    Umai

    Joined:
    Jun 18, 2013
    Posts:
    74
    Someone wrote an example usage here:

    http://cflat-inc.hatenablog.com/entry/2015/01/05/074442

    Quoted code:


    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditor.Callbacks;
    4. using UnityEditor.iOS.Xcode; // ←さっきいれたXcodeAPI
    5. using System.Collections;
    6. using System.IO;
    7.  
    8. public class XcodeProjectMod : MonoBehaviour
    9. {
    10.  
    11.     // ちょっとしたユーティリティ関数(http://goo.gl/fzYig8を参考)
    12.     internal static void CopyAndReplaceDirectory(string srcPath, string dstPath)
    13.     {
    14.         if (Directory.Exists(dstPath))
    15.             Directory.Delete(dstPath);
    16.         if (File.Exists(dstPath))
    17.             File.Delete(dstPath);
    18.  
    19.         Directory.CreateDirectory(dstPath);
    20.  
    21.         foreach (var file in Directory.GetFiles(srcPath))
    22.             File.Copy(file, Path.Combine(dstPath, Path.GetFileName(file)));
    23.  
    24.         foreach (var dir in Directory.GetDirectories(srcPath))
    25.             CopyAndReplaceDirectory(dir, Path.Combine(dstPath, Path.GetFileName(dir)));
    26.     }
    27.  
    28.     [PostProcessBuild]
    29.     public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
    30.     {
    31.         if (buildTarget == BuildTarget.iPhone)
    32.         {
    33.             string projPath = PBXProject.GetPBXProjectPath(path);
    34.             PBXProject proj = new PBXProject();
    35.      
    36.             proj.ReadFromString(File.ReadAllText(projPath));
    37.             string target = proj.TargetGuidByName("Unity-iPhone");
    38.  
    39.             // システムのフレームワークを追加
    40.             proj.AddFrameworkToProject(target, "AssetsLibrary.framework", false);
    41.      
    42.             // 自前のフレームワークを追加
    43.             CopyAndReplaceDirectory("Assets/Lib/mylib.framework", Path.Combine(path, "Frameworks/mylib.framework"));
    44.             proj.AddFileToBuild(target, proj.AddFile("Frameworks/mylib.framework", "Frameworks/mylib.framework", PBXSourceTree.Source));
    45.  
    46.             // ファイルを追加
    47.             var fileName = "my_file.xml";
    48.             var filePath = Path.Combine("Assets/Lib", fileName);
    49.             File.Copy(filePath, Path.Combine(path, fileName));
    50.             proj.AddFileToBuild(target, proj.AddFile(fileName, fileName, PBXSourceTree.Source));
    51.  
    52.             // Yosemiteでipaが書き出せないエラーに対応するための設定
    53.             proj.SetBuildProperty(target, "CODE_SIGN_RESOURCE_RULES_PATH", "$(SDKROOT)/ResourceRules.plist");
    54.  
    55.             // フレームワークの検索パスを設定・追加
    56.             proj.SetBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");
    57.             proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks");
    58.      
    59.             // 書き出し
    60.             File.WriteAllText(projPath, proj.WriteToString());
    61.         }
    62.     }
    63. }

    I'm trying to figure this all out at the moment. I need to add frameworks, edit the pch file, add additional linker flags, some files and directories, add url schemes, and so on... so far I could do some of it with help from above code. I might post more on it later in case I figure it all out...

    Some things:

    * they got the "projPath" wrong for me, I had to change "Unity-iPhone" into "Unity-iPhone.xcodeproj" in "projPath".

    * There is a class for handling plist in there, but I'll just use plistbuddy anyway, as it's part of OS X.

    * So far I fail at adding a folder "by reference" recursively... I have a folder which contains several subfolder of which some contains extra .framework:s and other libs and files. Somehow adding a folder always adds it as "real" folder... I need it to be a reference (yellow folder in Xcode, not blue).

    * I actually have to add the appcontroller.m (replace actual code inside didFinishLaunching.. and more) file on every build. It's a real pain in the neck and I guess it would be hard to pull that off even with these tools... sigh.
     
    Last edited: Mar 2, 2015
    Beardserk and georgepiva like this.
  4. georgepiva

    georgepiva

    Joined:
    Dec 16, 2013
    Posts:
    14
    Hi @Umai, I am facing the same issues that you reported above. Did you find some answers? My main issues are:

    * Adding compiler flags to files like `-fno-objc-arc`;

    * Conditional compilation in order to add `iPhoneOS` or `iPhoneSimulator` platforms specific lib versions.

    Did some of you guys try to use one of the next alternatives?
     
    Last edited: Mar 13, 2015
  5. psydent

    psydent

    Joined:
    Feb 11, 2013
    Posts:
    12
    Use mod-pbxproj. It says it supports adding a folder "by reference" recursively. The Unity way is dumping everything into Assets/Plugins/iOS. You'd still have to add your frameworks to the project so they can be linked.

    You can call mod-pbxproj using (shorthand, missing exception handling, logging output, etc.):
    Process myProcess = new Process();
    myProcess.StartInfo.FileName = "python";
    myProcess.StartInfo.Arguments = ?; // the path to your python file
    myProcess.StartInfo.UseShellExecute = false;
    // set anything else
    myProcess.Start();
    myProcess.WaitForExit();

    For compiler flags per file, in your python script you need to make a filelist and can do:
    project.apply_mods({'compiler_flags': {'-fno-objc-arc': filelist}})
    To make the file list I start with filelist = os.listdir(srcDir) and add/remove. I wrote this for a one-off task so apologies it's not generalized.

    For adding code each time, you should patch it in using a postprocess.

    Unity includes a different lib based on if you're targeting iPhoneOS or iPhoneSimulator so just read that value and add the correct platform specific libs and defines.
     
  6. David-Berger

    David-Berger

    Unity Technologies

    Joined:
    Jul 16, 2014
    Posts:
    745
    If you like you can check out the Native Library Demo in the Unity Cloud Build Demos. It is not directly connected as it an example to add a native library to XCode via post process using the XCode Manipulation API, targeting Unity Cloud Build, but the general concept is the same. Although, there are differenced between Unity 4.x and 5.x as the plugin folders are handled differently.
     
  7. povilas

    povilas

    Unity Technologies

    Joined:
    Jan 28, 2014
    Posts:
    427
    Please don't use mod-pbxproj. It does not handle project files correctly. The problem does not arise when opening the project with Xcode though, as it can read slightly corrupted files just fine. However when postprocess steps of various plugins interact with each another, the build sometimes breaks in very strange ways that are hard to understand.

    Use Xcode API provided by Unity. Unfortunately its documentation is not available on the website for some reason at the moment. I'll look into this issue and make sure the documentation is available there in the following days.
     
    David-Berger and georgepiva like this.
  8. psydent

    psydent

    Joined:
    Feb 11, 2013
    Posts:
    12
    mod-pbxproj does handle project files correctly. I'd be happy to re-evaluate if you have an example for which it breaks. But we have over a dozen iOS build jobs using it without any issues.

    When people use mod-pbxproj incorrectly, then it can break. But all those fixes are outside of the mod-pbxproj script. I've had to fix the postprocess steps of some plugins and it's usually because they made bad assumptions.

    The Xcode API provided by Unity is less clear than mod-pbxproj. Having the documentation would be a big help in re-evaluating if it's a better solution. One thing that sticks out is that you have to specify more things when using it, which makes it more prone to breaking/being used incorrectly than mod-pbxproj.
     
    georgepiva likes this.
  9. robot-ink

    robot-ink

    Joined:
    Jul 1, 2011
    Posts:
    18
    Any updates on this? Any plans on more documentation? I use mod-pbxproj as well but if that has the potential to cause problems then I'd like to switch over to a cleaner method.

    I used the example files to add links to frameworks, which works fine, but now I tried copying a plugin (which doesn't copy due to a bug in Unity 5 apparently) and the resulting project can't link to the plugin. It builds when I drag the file in by hand however... any ideas? When copying by hand xcode copies the file and adds it to a group as well as assigns a target, i'm trying to do the same procedure in code but kind of stabbing in the dark...

    Code (csharp):
    1.  
    2. var fileName = "metaiosdk";
    3. var filePath = Path.Combine("Assets/Plugins/iOS", fileName);
    4. File.Copy(filePath, Path.Combine(path, "Libraries/" +fileName));
    5. proj.AddFileToBuild(target, proj.AddFile( "Libraries/" + fileName,  "Libraries/" + fileName, PBXSourceTree.Source));
    6.  
     
  10. mydev555

    mydev555

    Joined:
    Mar 15, 2014
    Posts:
    8
    I also have a question about the XCode API. For my project I have to include several libraries to build in Xcode, also the gpg framework which has a filesize of 116MB. This means that I cannot include that file directly into my github repo, cause it is too big. Is there a solution for handling such a case with Unity Cloud build and the XCode API?

    Can I maybe download the framework file on the fly everytime Unity Cloud builds my app?
    Download link is:

    Play Games C++ SDK Version 1.4.1


     
    Last edited: Jun 11, 2015
  11. povilas

    povilas

    Unity Technologies

    Joined:
    Jan 28, 2014
    Posts:
    427
    aihodge, georgepiva and David-Berger like this.
  12. aihodge

    aihodge

    Joined:
    Nov 23, 2014
    Posts:
    163
    This looks very useful, thanks!
     
  13. Keepabee

    Keepabee

    Joined:
    Jul 12, 2012
    Posts:
    58
    Haha, I love it! That Japanese-commented code example, of which I have no idea what they are trying to do or why, seems to be one of the best Unity code examples I've ever read!

    Having my own problems to solve and advert plugin -specific XCode setup requirements to follow, I can just look at how the original programmer has used paths, property names and the methods to create solutions.

    Yeah, sorry but the Unity Scripting Reference is once again quite unhelpful. I couldn't have used the XCode API without looking at the abovementioned example code to see what kind of paths were expected, or the above forum comment mentioning the bad return value for PBXProject.GetProjectPath method, or what these property names are and where I can look them up.

    I'm overjoyed to have seen this thread and that example!
     
  14. antifuzz

    antifuzz

    Joined:
    Feb 22, 2013
    Posts:
    99
    I've just been trying to get to grips with this Unity Xcode API as well, and come up against the exact same issues as above. PBXProject.GetProjectPath does seem to return the wrong value. You have to change "Unity-iPhone" into "Unity-iPhone.xcodeproj" in "projPath" to get it to work.
    The Unity Docs could seriously do with some good examples adding. This would be a hugely helpful api if it were easier to understand.
    As it is, I've gone back to mod_pbxproj, which works and does the job I need it to.
     
  15. BigToe

    BigToe

    Joined:
    Nov 1, 2010
    Posts:
    208
    I have started using the Xcode Manipulation API and overall it seems to be good. I do have a question regarding adding in a dynamic library. I am trying to add in "libz.1.2.5.dylib" or maybe just "libz.1.dylib".

    If I add them in through Xcode, I do it through the "Link Binary with Libraries" from Build Phases. If I try to add in the "lib.1.2.5.dylib" or "libz.1.dylib"using the PBXProject.addFrameworkToProject(), it adds the file, but it is in red in Xcode which would mean that it is missing.

    proj.AddFrameworkToProject(target, "libz.1.dylib", false);

    I can copy it our of its location in the iOS SDK and add it to my Unity project, copy it to my BuildProject directory, then add it to the Frameworks, but this seems really ineloquent.

    Any advise for the best way to add in the dynamic libraries to Xcode?

    Thanks
     
  16. Jeffom

    Jeffom

    Joined:
    Oct 6, 2010
    Posts:
    55
    I'm guessing that you need the full path of the lib, have you tried that?
     
  17. BigToe

    BigToe

    Joined:
    Nov 1, 2010
    Posts:
    208
    Thanks for the advice. The full path doesn't work with the AddFrameworkToProject() method, but it does work if I use the AddFileToBuild with the full path...

    string libZPath = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/libz.1.dylib";

    proj.AddFileToBuild(target, proj.AddFile(libZPath,"Frameworks/libz.1.dylib",PBXSourceTree.Source));
     
  18. povilas

    povilas

    Unity Technologies

    Joined:
    Jan 28, 2014
    Posts:
    427
    AddFrameworkToProject is meant only for system frameworks, like "Gamekit.framework". For any other libraries please use AddFile with correct source tree - PBXSourceTree.Source for libraries already copied to within the project folder and PBXSourceTree.Sdk for system libraries. For example,

    proj.AddFileToBuild(target, proj.AddFile("usr/lib/libz.1.dylib", "Frameworks/libz.1.dylib", PBXSourceTree.Sdk));
     
    xaldin-76, hantengx and liortal like this.
  19. BigToe

    BigToe

    Joined:
    Nov 1, 2010
    Posts:
    208
    Thanks for the follow-up. That works for me.
     
  20. BigToe

    BigToe

    Joined:
    Nov 1, 2010
    Posts:
    208
    I had a similar problem using the example files and at least solved it on my end.

    The example file has the following two lines to set the Framework Search Path...
    Code (CSharp):
    1. proj.SetBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");
    2.             proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks");
    The problem with that is that the first line ]proj.SetBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(inherited)"); wipes out any existing framework search paths that may already have been added to the project by another plugin.

    So in my case, I had a framework in my Unity Project under "Plugins/iOS/AdColony.framework". If I don't run the Post Processor it appears that Unity will automatically add "Plugins/iOS" to the Framework Search Path in Xcode when the project is built.

    If I run the example post processor script above it obliterates the "Plugins/iOS/" from the Frameworks Search Path and I have a link compilation error trying to find the headers and I get this...

    Code (CSharp):
    1. Lexical or Preprocessor Issue
    2. UnityADC.mm:18:9: 'AdColony/AdColony.h' file not found
    The solution for me and maybe for you... Just don't use
    Code (CSharp):
    1. proj.SetBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");
    It shouldn't be necessary anyway as the default empty Unity Project already sets the Framework Search Paths to "$(inherited)" by default.

    Currently it appears just to be a good way to introduce incompatibility between third party plugins and cause developers a lot of extra hours figuring it out. I wish they would revise the sample.
     
    Last edited: Jul 15, 2015
  21. danien

    danien

    Joined:
    Jun 16, 2009
    Posts:
    71
    Is there a way to add a Run Script build phase through the Xcode API? There is a private m_Section dictionary containing the sections but no public API to access it.
     
    psydent likes this.
  22. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I am trying to add a library to the Xcode project (libicucode.tbd), I am using this code (as suggested above):
    Code (CSharp):
    1. proj.AddFileToBuild(targetGUID, proj.AddFile("usr/lib/libicucore.tbd", "Frameworks/libicucore.tbd", PBXSourceTree.Sdk));
    2.         proj.AddFileToBuild(targetGUID, proj.AddFile("usr/lib/libicucore.tbd", "Frameworks/libicucore.tbd", PBXSourceTree.Build));
    This file is added under Frameworks, but it is not added as input for the "link binary with libraries". I still have to add it manually. Is there any way to add the library using the Xcode API ?
     
    xiaoming0326 and Biro456 like this.
  23. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    paradizIsCool likes this.
  24. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Unity dudes, could you please address this simple question ..

    @povilas

    How to simply "copy one file" (say, an audio file or image) from the Unity folder to the built Xcode folder ..

    https://stackoverflow.com/questions...-how-exactly-do-you-simply-copy-over-one-file



    result in Xcode ...





    Code (CSharp):
    1.  
    2.         project.AddFileToBuild(g, something something something);
    It's totally unclear and undocumented how AddFileToBuild works .. thanks

    Again, simply add one file to the target Bundle in Xcode ... (imagine a .txt data file, an audio file or whatever).