├── LICENSE ├── LICENSE.meta ├── PBXBuildFile.cs ├── PBXBuildFile.cs.meta ├── PBXBuildPhase.cs ├── PBXBuildPhase.cs.meta ├── PBXDictionary.cs ├── PBXDictionary.cs.meta ├── PBXFileReference.cs ├── PBXFileReference.cs.meta ├── PBXGroup.cs ├── PBXGroup.cs.meta ├── PBXList.cs ├── PBXList.cs.meta ├── PBXObject.cs ├── PBXObject.cs.meta ├── PBXParser.cs ├── PBXParser.cs.meta ├── PBXProject.cs ├── PBXProject.cs.meta ├── PBXVariantGroup.cs ├── PBXVariantGroup.cs.meta ├── Readme.mdown ├── Readme.mdown.meta ├── XCBuildConfiguration.cs ├── XCBuildConfiguration.cs.meta ├── XCConfigurationList.cs ├── XCConfigurationList.cs.meta ├── XCFileOperationQueue.cs ├── XCFileOperationQueue.cs.meta ├── XCMod.cs ├── XCMod.cs.meta ├── XCProject.cs ├── XCProject.cs.meta ├── XCSourceFile.cs ├── XCSourceFile.cs.meta ├── XCTarget.cs ├── XCTarget.cs.meta ├── XCodeEditorMenu.cs ├── XCodeEditorMenu.cs.meta ├── XMiniJSON.cs ├── XMiniJSON.cs.meta └── sample_config.projmods /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Daniele Cariola 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: efd071e8beb084c7dbc945f03e3e9f6c 3 | -------------------------------------------------------------------------------- /PBXBuildFile.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXBuildFile : PBXObject 8 | { 9 | private const string FILE_REF_KEY = "fileRef"; 10 | private const string SETTINGS_KEY = "settings"; 11 | private const string ATTRIBUTES_KEY = "ATTRIBUTES"; 12 | private const string WEAK_VALUE = "Weak"; 13 | private const string COMPILER_FLAGS_KEY = "COMPILER_FLAGS"; 14 | 15 | public PBXBuildFile( PBXFileReference fileRef, bool weak = false ) : base() 16 | { 17 | 18 | this.Add( FILE_REF_KEY, fileRef.guid ); 19 | SetWeakLink( weak ); 20 | 21 | // def Create(cls, file_ref, weak=False): 22 | // if isinstance(file_ref, PBXFileReference): 23 | // file_ref = file_ref.id 24 | // 25 | // bf = cls() 26 | // bf.id = cls.GenerateId() 27 | // bf['fileRef'] = file_ref 28 | // 29 | // if weak: 30 | // bf.set_weak_link(True) 31 | // 32 | // return bf 33 | } 34 | 35 | public PBXBuildFile( string guid, PBXDictionary dictionary ) : base ( guid, dictionary ) 36 | { 37 | // Debug.Log( "constructor child" ); 38 | } 39 | 40 | public bool SetWeakLink( bool weak = false ) 41 | { 42 | PBXDictionary settings = null; 43 | PBXList attributes = null; 44 | 45 | if( !_data.ContainsKey( SETTINGS_KEY ) ) { 46 | if( weak ) { 47 | attributes = new PBXList(); 48 | attributes.Add( WEAK_VALUE ); 49 | 50 | settings = new PBXDictionary(); 51 | settings.Add( ATTRIBUTES_KEY, attributes ); 52 | _data[ SETTINGS_KEY ] = settings; 53 | } 54 | return true; 55 | } 56 | 57 | settings = _data[ SETTINGS_KEY ] as PBXDictionary; 58 | if( !settings.ContainsKey( ATTRIBUTES_KEY ) ) { 59 | if( weak ) { 60 | attributes = new PBXList(); 61 | attributes.Add( WEAK_VALUE ); 62 | settings.Add( ATTRIBUTES_KEY, attributes ); 63 | return true; 64 | } 65 | else { 66 | return false; 67 | } 68 | } 69 | else { 70 | attributes = settings[ ATTRIBUTES_KEY ] as PBXList; 71 | } 72 | 73 | if( weak ) { 74 | attributes.Add( WEAK_VALUE ); 75 | } 76 | else { 77 | attributes.Remove( WEAK_VALUE ); 78 | } 79 | 80 | settings.Add( ATTRIBUTES_KEY, attributes ); 81 | this.Add( SETTINGS_KEY, settings ); 82 | 83 | return true; 84 | } 85 | 86 | public bool AddCompilerFlag( string flag ) 87 | { 88 | if( !_data.ContainsKey( SETTINGS_KEY ) ) 89 | _data[ SETTINGS_KEY ] = new PBXDictionary(); 90 | 91 | if( !((PBXDictionary)_data[ SETTINGS_KEY ]).ContainsKey( COMPILER_FLAGS_KEY ) ) { 92 | ((PBXDictionary)_data[ SETTINGS_KEY ]).Add( COMPILER_FLAGS_KEY, flag ); 93 | return true; 94 | } 95 | 96 | string[] flags = ((string)((PBXDictionary)_data[ SETTINGS_KEY ])[ COMPILER_FLAGS_KEY ]).Split( ' ' ); 97 | foreach( string item in flags ) { 98 | if( item.CompareTo( flag ) == 0 ) 99 | return false; 100 | } 101 | 102 | ((PBXDictionary)_data[ SETTINGS_KEY ])[ COMPILER_FLAGS_KEY ] = ( string.Join( " ", flags ) + " " + flag ); 103 | return true; 104 | 105 | // def add_compiler_flag(self, flag): 106 | // k_settings = 'settings' 107 | // k_attributes = 'COMPILER_FLAGS' 108 | // 109 | // if not self.has_key(k_settings): 110 | // self[k_settings] = PBXDict() 111 | // 112 | // if not self[k_settings].has_key(k_attributes): 113 | // self[k_settings][k_attributes] = flag 114 | // return True 115 | // 116 | // flags = self[k_settings][k_attributes].split(' ') 117 | // 118 | // if flag in flags: 119 | // return False 120 | // 121 | // flags.append(flag) 122 | // 123 | // self[k_settings][k_attributes] = ' '.join(flags) 124 | } 125 | 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /PBXBuildFile.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ffd51577e814940a8a93200cde422eb0 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXBuildPhase.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXBuildPhase : PBXObject 8 | { 9 | protected const string FILES_KEY = "files"; 10 | 11 | public PBXBuildPhase() :base() 12 | { 13 | // Debug.Log( "base" ); 14 | } 15 | 16 | public PBXBuildPhase( string guid, PBXDictionary dictionary ) : base ( guid, dictionary ) 17 | { 18 | // Debug.Log( "constructor " + GetType().Name ); 19 | } 20 | 21 | public bool AddBuildFile( PBXBuildFile file ) 22 | { 23 | // if( ((string)file[ ISA_KEY ]).CompareTo( "PBXBuildFile" ) != 0 ) 24 | // return false; 25 | // Debug.Log( "--> buildphase " + (string)_data[ ISA_KEY ] ); 26 | 27 | 28 | if( !ContainsKey( FILES_KEY ) ){ 29 | // Debug.Log( "key not present" ); 30 | this.Add( FILES_KEY, new PBXList() ); 31 | } 32 | // Debug.Log( "key: " + _data[ FILES_KEY ] ); 33 | // Debug.Log( "Adding: " + file.guid ); 34 | ((PBXList)_data[ FILES_KEY ]).Add( file.guid ); 35 | // if( ((PBXList)_data[ FILES_KEY ]).Contains( file.guid ) ) { 36 | // Debug.Log( "AGGIUNTO" ); 37 | // } 38 | // else { 39 | // Debug.Log( "MANCA" ); 40 | // } 41 | 42 | return true; 43 | } 44 | 45 | public void RemoveBuildFile( string id ) 46 | { 47 | if( !ContainsKey( FILES_KEY ) ) { 48 | this.Add( FILES_KEY, new PBXList() ); 49 | return; 50 | } 51 | 52 | ((PBXList)_data[ FILES_KEY ]).Remove( id ); 53 | } 54 | 55 | public bool HasBuildFile( string id ) 56 | { 57 | if( !ContainsKey( FILES_KEY ) ) { 58 | this.Add( FILES_KEY, new PBXList() ); 59 | return false; 60 | } 61 | 62 | if( !IsGuid( id ) ) 63 | return false; 64 | 65 | return ((PBXList)_data[ FILES_KEY ]).Contains( id ); 66 | } 67 | 68 | // class PBXBuildPhase(PBXObject): 69 | // def add_build_file(self, bf): 70 | // if bf.get('isa') != 'PBXBuildFile': 71 | // return False 72 | // 73 | // if not self.has_key('files'): 74 | // self['files'] = PBXList() 75 | // 76 | // self['files'].add(bf.id) 77 | // 78 | // return True 79 | // 80 | // def remove_build_file(self, id): 81 | // if not self.has_key('files'): 82 | // self['files'] = PBXList() 83 | // return 84 | // 85 | // self['files'].remove(id) 86 | // 87 | // def has_build_file(self, id): 88 | // if not self.has_key('files'): 89 | // self['files'] = PBXList() 90 | // return False 91 | // 92 | // if not PBXObject.IsGuid(id): 93 | // id = id.id 94 | // 95 | // return id in self['files'] 96 | } 97 | 98 | public class PBXFrameworksBuildPhase : PBXBuildPhase 99 | { 100 | public PBXFrameworksBuildPhase( string guid, PBXDictionary dictionary ) : base ( guid, dictionary ) 101 | { 102 | // Debug.Log( "constructor child" + GetType().Name ); 103 | } 104 | } 105 | 106 | public class PBXResourcesBuildPhase : PBXBuildPhase 107 | { 108 | public PBXResourcesBuildPhase( string guid, PBXDictionary dictionary ) : base ( guid, dictionary ) 109 | { 110 | // Debug.Log( "constructor child" + GetType().Name ); 111 | } 112 | } 113 | 114 | public class PBXShellScriptBuildPhase : PBXBuildPhase 115 | { 116 | public PBXShellScriptBuildPhase( string guid, PBXDictionary dictionary ) : base ( guid, dictionary ) 117 | { 118 | // Debug.Log( "constructor child" + GetType().Name ); 119 | } 120 | } 121 | 122 | public class PBXSourcesBuildPhase : PBXBuildPhase 123 | { 124 | public PBXSourcesBuildPhase( string guid, PBXDictionary dictionary ) : base ( guid, dictionary ) 125 | { 126 | // Debug.Log( "constructor child" + GetType().Name ); 127 | } 128 | } 129 | 130 | public class PBXCopyFilesBuildPhase : PBXBuildPhase 131 | { 132 | public PBXCopyFilesBuildPhase( string guid, PBXDictionary dictionary ) : base ( guid, dictionary ) 133 | { 134 | // Debug.Log( "constructor child" + GetType().Name ); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /PBXBuildPhase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45e20ea7193b74e02b784077e774b23f 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXDictionary.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXDictionary : Dictionary 8 | { 9 | 10 | public void Append( PBXDictionary dictionary ) 11 | { 12 | foreach( var item in dictionary) { 13 | this.Add( item.Key, item.Value ); 14 | } 15 | } 16 | 17 | public void Append( PBXDictionary dictionary ) where T : PBXObject 18 | { 19 | foreach( var item in dictionary) { 20 | this.Add( item.Key, item.Value ); 21 | } 22 | } 23 | } 24 | 25 | public class PBXDictionary : Dictionary where T : PBXObject 26 | { 27 | public PBXDictionary() 28 | { 29 | 30 | } 31 | 32 | public PBXDictionary( PBXDictionary genericDictionary ) 33 | { 34 | foreach( KeyValuePair currentItem in genericDictionary ) { 35 | if( ((string)((PBXDictionary)currentItem.Value)[ "isa" ]).CompareTo( typeof(T).Name ) == 0 ) { 36 | T instance = (T)System.Activator.CreateInstance( typeof(T), currentItem.Key, (PBXDictionary)currentItem.Value ); 37 | this.Add( currentItem.Key, instance ); 38 | } 39 | } 40 | } 41 | 42 | public void Add( T newObject ) 43 | { 44 | this.Add( newObject.guid, newObject ); 45 | } 46 | 47 | public void Append( PBXDictionary dictionary ) 48 | { 49 | foreach( KeyValuePair item in dictionary) { 50 | this.Add( item.Key, (T)item.Value ); 51 | } 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /PBXDictionary.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e2d23f084277542dbbe7a017cb9799ce 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXFileReference.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXFileReference : PBXObject 8 | { 9 | protected const string PATH_KEY = "path"; 10 | protected const string NAME_KEY = "name"; 11 | protected const string SOURCETREE_KEY = "sourceTree"; 12 | protected const string EXPLICIT_FILE_TYPE_KEY = "explicitFileType"; 13 | protected const string LASTKNOWN_FILE_TYPE_KEY = "lastKnownFileType"; 14 | protected const string ENCODING_KEY = "fileEncoding"; 15 | 16 | public string buildPhase; 17 | public readonly Dictionary trees = new Dictionary { 18 | { TreeEnum.ABSOLUTE, "" }, 19 | { TreeEnum.GROUP, "" }, 20 | { TreeEnum.BUILT_PRODUCTS_DIR, "BUILT_PRODUCTS_DIR" }, 21 | { TreeEnum.DEVELOPER_DIR, "DEVELOPER_DIR" }, 22 | { TreeEnum.SDKROOT, "SDKROOT" }, 23 | { TreeEnum.SOURCE_ROOT, "SOURCE_ROOT" } 24 | }; 25 | 26 | public static readonly Dictionary typeNames = new Dictionary { 27 | { ".a", "archive.ar" }, 28 | { ".app", "wrapper.application" }, 29 | { ".s", "sourcecode.asm" }, 30 | { ".c", "sourcecode.c.c" }, 31 | { ".cpp", "sourcecode.cpp.cpp" }, 32 | { ".framework", "wrapper.framework" }, 33 | { ".h", "sourcecode.c.h" }, 34 | { ".icns", "image.icns" }, 35 | { ".m", "sourcecode.c.objc" }, 36 | { ".mm", "sourcecode.cpp.objcpp" }, 37 | { ".nib", "wrapper.nib" }, 38 | { ".plist", "text.plist.xml" }, 39 | { ".png", "image.png" }, 40 | { ".rtf", "text.rtf" }, 41 | { ".tiff", "image.tiff" }, 42 | { ".txt", "text" }, 43 | { ".xcodeproj", "wrapper.pb-project" }, 44 | { ".xib", "file.xib" }, 45 | { ".strings", "text.plist.strings" }, 46 | { ".bundle", "wrapper.plug-in" }, 47 | { ".dylib", "compiled.mach-o.dylib" } 48 | }; 49 | 50 | public static readonly Dictionary typePhases = new Dictionary { 51 | { ".a", "PBXFrameworksBuildPhase" }, 52 | { ".app", null }, 53 | { ".s", "PBXSourcesBuildPhase" }, 54 | { ".c", "PBXSourcesBuildPhase" }, 55 | { ".cpp", "PBXSourcesBuildPhase" }, 56 | { ".framework", "PBXFrameworksBuildPhase" }, 57 | { ".h", null }, 58 | { ".icns", "PBXResourcesBuildPhase" }, 59 | { ".m", "PBXSourcesBuildPhase" }, 60 | { ".mm", "PBXSourcesBuildPhase" }, 61 | { ".nib", "PBXResourcesBuildPhase" }, 62 | { ".plist", "PBXResourcesBuildPhase" }, 63 | { ".png", "PBXResourcesBuildPhase" }, 64 | { ".rtf", "PBXResourcesBuildPhase" }, 65 | { ".tiff", "PBXResourcesBuildPhase" }, 66 | { ".txt", "PBXResourcesBuildPhase" }, 67 | { ".xcodeproj", null }, 68 | { ".xib", "PBXResourcesBuildPhase" }, 69 | { ".strings", "PBXResourcesBuildPhase" }, 70 | { ".bundle", "PBXResourcesBuildPhase" }, 71 | { ".dylib", "PBXFrameworksBuildPhase" } 72 | }; 73 | 74 | public PBXFileReference( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) 75 | { 76 | 77 | } 78 | 79 | public PBXFileReference( string filePath, TreeEnum tree = TreeEnum.SOURCE_ROOT ) : base() 80 | { 81 | this.Add( PATH_KEY, filePath ); 82 | this.Add( NAME_KEY, System.IO.Path.GetFileName( filePath ) ); 83 | this.Add( SOURCETREE_KEY, (string)( System.IO.Path.IsPathRooted( filePath ) ? trees[TreeEnum.ABSOLUTE] : trees[tree] ) ); 84 | this.GuessFileType(); 85 | } 86 | 87 | public string name { 88 | get { 89 | if( !ContainsKey( NAME_KEY ) ) { 90 | return null; 91 | } 92 | return (string)_data[NAME_KEY]; 93 | } 94 | } 95 | 96 | private void GuessFileType() 97 | { 98 | this.Remove( EXPLICIT_FILE_TYPE_KEY ); 99 | this.Remove( LASTKNOWN_FILE_TYPE_KEY ); 100 | string extension = System.IO.Path.GetExtension( (string)_data[ PATH_KEY ] ); 101 | if( !PBXFileReference.typeNames.ContainsKey( extension ) ){ 102 | Debug.LogWarning( "Unknown file extension: " + extension + "\nPlease add extension and Xcode type to PBXFileReference.types" ); 103 | return; 104 | } 105 | 106 | this.Add( LASTKNOWN_FILE_TYPE_KEY, PBXFileReference.typeNames[ extension ] ); 107 | this.buildPhase = PBXFileReference.typePhases[ extension ]; 108 | } 109 | 110 | private void SetFileType( string fileType ) 111 | { 112 | this.Remove( EXPLICIT_FILE_TYPE_KEY ); 113 | this.Remove( LASTKNOWN_FILE_TYPE_KEY ); 114 | 115 | this.Add( EXPLICIT_FILE_TYPE_KEY, fileType ); 116 | } 117 | 118 | // class PBXFileReference(PBXType): 119 | // def __init__(self, d=None): 120 | // PBXType.__init__(self, d) 121 | // self.build_phase = None 122 | // 123 | // types = { 124 | // '.a':('archive.ar', 'PBXFrameworksBuildPhase'), 125 | // '.app': ('wrapper.application', None), 126 | // '.s': ('sourcecode.asm', 'PBXSourcesBuildPhase'), 127 | // '.c': ('sourcecode.c.c', 'PBXSourcesBuildPhase'), 128 | // '.cpp': ('sourcecode.cpp.cpp', 'PBXSourcesBuildPhase'), 129 | // '.framework': ('wrapper.framework','PBXFrameworksBuildPhase'), 130 | // '.h': ('sourcecode.c.h', None), 131 | // '.icns': ('image.icns','PBXResourcesBuildPhase'), 132 | // '.m': ('sourcecode.c.objc', 'PBXSourcesBuildPhase'), 133 | // '.mm': ('sourcecode.cpp.objcpp', 'PBXSourcesBuildPhase'), 134 | // '.nib': ('wrapper.nib', 'PBXResourcesBuildPhase'), 135 | // '.plist': ('text.plist.xml', 'PBXResourcesBuildPhase'), 136 | // '.png': ('image.png', 'PBXResourcesBuildPhase'), 137 | // '.rtf': ('text.rtf', 'PBXResourcesBuildPhase'), 138 | // '.tiff': ('image.tiff', 'PBXResourcesBuildPhase'), 139 | // '.txt': ('text', 'PBXResourcesBuildPhase'), 140 | // '.xcodeproj': ('wrapper.pb-project', None), 141 | // '.xib': ('file.xib', 'PBXResourcesBuildPhase'), 142 | // '.strings': ('text.plist.strings', 'PBXResourcesBuildPhase'), 143 | // '.bundle': ('wrapper.plug-in', 'PBXResourcesBuildPhase'), 144 | // '.dylib': ('compiled.mach-o.dylib', 'PBXFrameworksBuildPhase') 145 | // } 146 | // 147 | // trees = [ 148 | // '', 149 | // '', 150 | // 'BUILT_PRODUCTS_DIR', 151 | // 'DEVELOPER_DIR', 152 | // 'SDKROOT', 153 | // 'SOURCE_ROOT', 154 | // ] 155 | // 156 | // def guess_file_type(self): 157 | // self.remove('explicitFileType') 158 | // self.remove('lastKnownFileType') 159 | // ext = os.path.splitext(self.get('name', ''))[1] 160 | // 161 | // f_type, build_phase = PBXFileReference.types.get(ext, ('?', None)) 162 | // 163 | // self['lastKnownFileType'] = f_type 164 | // self.build_phase = build_phase 165 | // 166 | // if f_type == '?': 167 | // print 'unknown file extension: %s' % ext 168 | // print 'please add extension and Xcode type to PBXFileReference.types' 169 | // 170 | // return f_type 171 | // 172 | // def set_file_type(self, ft): 173 | // self.remove('explicitFileType') 174 | // self.remove('lastKnownFileType') 175 | // 176 | // self['explicitFileType'] = ft 177 | // 178 | // @classmethod 179 | // def Create(cls, os_path, tree='SOURCE_ROOT'): 180 | // if tree not in cls.trees: 181 | // print 'Not a valid sourceTree type: %s' % tree 182 | // return None 183 | // 184 | // fr = cls() 185 | // fr.id = cls.GenerateId() 186 | // fr['path'] = os_path 187 | // fr['name'] = os.path.split(os_path)[1] 188 | // fr['sourceTree'] = '' if os.path.isabs(os_path) else tree 189 | // fr.guess_file_type() 190 | // 191 | // return fr 192 | } 193 | 194 | public enum TreeEnum { 195 | ABSOLUTE, 196 | GROUP, 197 | BUILT_PRODUCTS_DIR, 198 | DEVELOPER_DIR, 199 | SDKROOT, 200 | SOURCE_ROOT 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /PBXFileReference.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2792ed7b2a30d40c199e8e27ebf39ccf 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXGroup.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXGroup : PBXObject 8 | { 9 | protected const string NAME_KEY = "name"; 10 | protected const string CHILDREN_KEY = "children"; 11 | protected const string PATH_KEY = "path"; 12 | protected const string SOURCETREE_KEY = "sourceTree"; 13 | 14 | #region Constructor 15 | 16 | public PBXGroup( string name, string path = null, string tree = "SOURCE_ROOT" ) : base() 17 | { 18 | this.Add( NAME_KEY, name ); 19 | this.Add( CHILDREN_KEY, new PBXList() ); 20 | 21 | if( path != null ) { 22 | this.Add( PATH_KEY, path ); 23 | this.Add( SOURCETREE_KEY, tree ); 24 | } 25 | else { 26 | this.Add( SOURCETREE_KEY, "" ); 27 | } 28 | } 29 | 30 | public PBXGroup( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) 31 | { 32 | 33 | } 34 | 35 | #endregion 36 | #region Properties 37 | 38 | public string name { 39 | get { 40 | if( !ContainsKey( NAME_KEY ) ) { 41 | return null; 42 | } 43 | return (string)_data[NAME_KEY]; 44 | } 45 | } 46 | 47 | public PBXList children { 48 | get { 49 | if( !ContainsKey( CHILDREN_KEY ) ) { 50 | this.Add( CHILDREN_KEY, new PBXList() ); 51 | } 52 | return (PBXList)_data[CHILDREN_KEY]; 53 | } 54 | } 55 | 56 | public string path { 57 | get { 58 | if( !ContainsKey( PATH_KEY ) ) { 59 | return null; 60 | } 61 | return (string)_data[PATH_KEY]; 62 | } 63 | } 64 | 65 | public string sourceTree { 66 | get { 67 | return (string)_data[SOURCETREE_KEY]; 68 | } 69 | } 70 | 71 | #endregion 72 | 73 | 74 | public string AddChild( PBXObject child ) 75 | { 76 | if( child is PBXFileReference || child is PBXGroup ) { 77 | children.Add( child.guid ); 78 | return child.guid; 79 | } 80 | 81 | return null; 82 | } 83 | 84 | public void RemoveChild( string id ) 85 | { 86 | if( !IsGuid( id ) ) 87 | return; 88 | 89 | children.Remove( id ); 90 | } 91 | 92 | public bool HasChild( string id ) 93 | { 94 | if( !ContainsKey( CHILDREN_KEY ) ) { 95 | this.Add( CHILDREN_KEY, new PBXList() ); 96 | return false; 97 | } 98 | 99 | if( !IsGuid( id ) ) 100 | return false; 101 | 102 | return ((PBXList)_data[ CHILDREN_KEY ]).Contains( id ); 103 | } 104 | 105 | public string GetName() 106 | { 107 | return (string)_data[ NAME_KEY ]; 108 | } 109 | 110 | // class PBXGroup(PBXObject): 111 | // def add_child(self, ref): 112 | // if not isinstance(ref, PBXDict): 113 | // return None 114 | // 115 | // isa = ref.get('isa') 116 | // 117 | // if isa != 'PBXFileReference' and isa != 'PBXGroup': 118 | // return None 119 | // 120 | // if not self.has_key('children'): 121 | // self['children'] = PBXList() 122 | // 123 | // self['children'].add(ref.id) 124 | // 125 | // return ref.id 126 | // 127 | // def remove_child(self, id): 128 | // if not self.has_key('children'): 129 | // self['children'] = PBXList() 130 | // return 131 | // 132 | // if not PBXObject.IsGuid(id): 133 | // id = id.id 134 | // 135 | // self['children'].remove(id) 136 | // 137 | // def has_child(self, id): 138 | // if not self.has_key('children'): 139 | // self['children'] = PBXList() 140 | // return False 141 | // 142 | // if not PBXObject.IsGuid(id): 143 | // id = id.id 144 | // 145 | // return id in self['children'] 146 | // 147 | // def get_name(self): 148 | // path_name = os.path.split(self.get('path',''))[1] 149 | // return self.get('name', path_name) 150 | // 151 | // @classmethod 152 | // def Create(cls, name, path=None, tree='SOURCE_ROOT'): 153 | // grp = cls() 154 | // grp.id = cls.GenerateId() 155 | // grp['name'] = name 156 | // grp['children'] = PBXList() 157 | // 158 | // if path: 159 | // grp['path'] = path 160 | // grp['sourceTree'] = tree 161 | // else: 162 | // grp['sourceTree'] = '' 163 | // 164 | // return grp 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /PBXGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1af26133e9aa04b77bd12d21d94f118e 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXList.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXList : ArrayList 8 | { 9 | public PBXList() 10 | { 11 | 12 | } 13 | 14 | public PBXList( object firstValue ) 15 | { 16 | this.Add( firstValue ); 17 | } 18 | } 19 | 20 | // public class PBXList : ArrayList 21 | // { 22 | // public int Add( T value ) 23 | // { 24 | // return (ArrayList)this.Add( value ); 25 | // } 26 | // } 27 | } 28 | -------------------------------------------------------------------------------- /PBXList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5dab64c67c818480d9451129a0e67e80 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXObject.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXObject 8 | { 9 | protected const string ISA_KEY = "isa"; 10 | // 11 | protected string _guid; 12 | protected PBXDictionary _data; 13 | 14 | #region Properties 15 | 16 | public string guid { 17 | get { 18 | if( string.IsNullOrEmpty( _guid ) ) 19 | _guid = GenerateGuid().ToUpper(); 20 | 21 | return _guid; 22 | } 23 | } 24 | 25 | public PBXDictionary data { 26 | get { 27 | if( _data == null ) 28 | _data = new PBXDictionary(); 29 | 30 | return _data; 31 | } 32 | } 33 | 34 | 35 | #endregion 36 | #region Constructors 37 | 38 | public PBXObject() 39 | { 40 | _data = new PBXDictionary(); 41 | _data[ ISA_KEY ] = this.GetType().Name; 42 | _guid = GenerateGuid(); 43 | } 44 | 45 | public PBXObject( string guid ) : this() 46 | { 47 | if( IsGuid( guid.ToUpper() ) ) 48 | _guid = guid.ToUpper(); 49 | } 50 | 51 | public PBXObject( string guid, PBXDictionary dictionary ) : this( guid ) 52 | { 53 | // Debug.Log( "constructor parent " + this.GetType().Name ); 54 | 55 | if( !dictionary.ContainsKey( ISA_KEY ) || ((string)dictionary[ ISA_KEY ]).CompareTo( this.GetType().Name ) != 0 ) 56 | Debug.LogError( "PBXDictionary is not a valid ISA object" ); 57 | 58 | foreach( KeyValuePair item in dictionary ) { 59 | _data[ item.Key ] = item.Value; 60 | } 61 | } 62 | 63 | #endregion 64 | #region Static methods 65 | 66 | public static bool IsGuid( string aString ) 67 | { 68 | return System.Text.RegularExpressions.Regex.IsMatch( aString, @"^[A-F0-9]{24}$" ); 69 | } 70 | 71 | public static string GenerateGuid() 72 | { 73 | return System.Guid.NewGuid().ToString("N").Substring( 8 ).ToUpper(); 74 | } 75 | 76 | 77 | #endregion 78 | #region Data manipulation 79 | 80 | public void Add( string key, object obj ) 81 | { 82 | _data.Add( key, obj ); 83 | } 84 | 85 | public bool Remove( string key ) 86 | { 87 | return _data.Remove( key ); 88 | } 89 | 90 | public bool ContainsKey( string key ) 91 | { 92 | return _data.ContainsKey( key ); 93 | } 94 | 95 | #endregion 96 | // class PBXObject(PBXDict): 97 | // def __init__(self, d=None): 98 | // PBXDict.__init__(self, d) 99 | // 100 | // if not self.has_key('isa'): 101 | // self['isa'] = self.__class__.__name__ 102 | // self.id = None 103 | // 104 | // @staticmethod 105 | // def Convert(o): 106 | // if isinstance(o, list): 107 | // return PBXList(o) 108 | // elif isinstance(o, dict): 109 | // isa = o.get('isa') 110 | // 111 | // if not isa: 112 | // return PBXDict(o) 113 | // 114 | // cls = globals().get(isa) 115 | // 116 | // if cls and issubclass(cls, PBXObject): 117 | // return cls(o) 118 | // 119 | // print 'warning: unknown PBX type: %s' % isa 120 | // return PBXDict(o) 121 | // else: 122 | // return o 123 | } 124 | 125 | public class PBXNativeTarget : PBXObject 126 | { 127 | public PBXNativeTarget() : base() { 128 | } 129 | 130 | public PBXNativeTarget( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) { 131 | } 132 | } 133 | 134 | public class PBXContainerItemProxy : PBXObject 135 | { 136 | public PBXContainerItemProxy() : base() { 137 | } 138 | 139 | public PBXContainerItemProxy( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) { 140 | } 141 | } 142 | 143 | public class PBXReferenceProxy : PBXObject 144 | { 145 | public PBXReferenceProxy() : base() { 146 | } 147 | 148 | public PBXReferenceProxy( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) { 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /PBXObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 32f133b9e55274ea89cb600dce102228 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXParser.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | 9 | namespace UnityEditor.XCodeEditor 10 | { 11 | public class PBXParser 12 | { 13 | public const string PBX_HEADER_TOKEN = "// !$*UTF8*$!\n"; 14 | public const char WHITESPACE_SPACE = ' '; 15 | public const char WHITESPACE_TAB = '\t'; 16 | public const char WHITESPACE_NEWLINE = '\n'; 17 | public const char WHITESPACE_CARRIAGE_RETURN = '\r'; 18 | public const char ARRAY_BEGIN_TOKEN = '('; 19 | public const char ARRAY_END_TOKEN = ')'; 20 | public const char ARRAY_ITEM_DELIMITER_TOKEN = ','; 21 | public const char DICTIONARY_BEGIN_TOKEN = '{'; 22 | public const char DICTIONARY_END_TOKEN = '}'; 23 | public const char DICTIONARY_ASSIGN_TOKEN = '='; 24 | public const char DICTIONARY_ITEM_DELIMITER_TOKEN = ';'; 25 | public const char QUOTEDSTRING_BEGIN_TOKEN = '"'; 26 | public const char QUOTEDSTRING_END_TOKEN = '"'; 27 | public const char QUOTEDSTRING_ESCAPE_TOKEN = '\\'; 28 | public const char END_OF_FILE = (char)0x1A; 29 | public const string COMMENT_BEGIN_TOKEN = "/*"; 30 | public const string COMMENT_END_TOKEN = "*/"; 31 | public const string COMMENT_LINE_TOKEN = "//"; 32 | private const int BUILDER_CAPACITY = 20000; 33 | 34 | // 35 | private char[] data; 36 | private int index; 37 | // public bool success; 38 | // private int indent; 39 | 40 | public PBXDictionary Decode( string data ) 41 | { 42 | // success = true; 43 | if( !data.StartsWith( PBX_HEADER_TOKEN ) ) { 44 | Debug.Log( "Wrong file format." ); 45 | return null; 46 | } 47 | 48 | data = data.Substring( 13 ); 49 | this.data = data.ToCharArray(); 50 | index = 0; 51 | 52 | return (PBXDictionary)ParseValue(); 53 | } 54 | 55 | public string Encode( PBXDictionary pbxData, bool readable = false ) 56 | { 57 | // indent = 0; 58 | 59 | StringBuilder builder = new StringBuilder( PBX_HEADER_TOKEN, BUILDER_CAPACITY ); 60 | bool success = SerializeValue( pbxData, builder, readable ); 61 | 62 | return ( success ? builder.ToString() : null ); 63 | } 64 | 65 | #region Move 66 | 67 | private char NextToken() 68 | { 69 | SkipWhitespaces(); 70 | return StepForeward(); 71 | } 72 | 73 | private string Peek( int step = 1 ) 74 | { 75 | string sneak = string.Empty; 76 | for( int i = 1; i <= step; i++ ) { 77 | if( data.Length - 1 < index + i ) { 78 | break; 79 | } 80 | sneak += data[ index + i ]; 81 | } 82 | return sneak; 83 | } 84 | 85 | private bool SkipWhitespaces() 86 | { 87 | bool whitespace = false; 88 | while( Regex.IsMatch( StepForeward().ToString(), @"\s" ) ) 89 | whitespace = true; 90 | 91 | StepBackward(); 92 | 93 | if( SkipComments() ) { 94 | whitespace = true; 95 | SkipWhitespaces(); 96 | } 97 | 98 | return whitespace; 99 | } 100 | 101 | private bool SkipComments() 102 | { 103 | string s = string.Empty; 104 | string tag = Peek( 2 ); 105 | switch( tag ) { 106 | case COMMENT_BEGIN_TOKEN: { 107 | while( Peek( 2 ).CompareTo( COMMENT_END_TOKEN ) != 0 ) { 108 | s += StepForeward(); 109 | } 110 | s += StepForeward( 2 ); 111 | break; 112 | } 113 | case COMMENT_LINE_TOKEN: { 114 | while( !Regex.IsMatch( StepForeward().ToString(), @"\n" ) ) 115 | continue; 116 | 117 | break; 118 | } 119 | default: 120 | return false; 121 | } 122 | return true; 123 | } 124 | 125 | private char StepForeward( int step = 1 ) 126 | { 127 | index = Math.Min( data.Length, index + step ); 128 | return data[ index ]; 129 | } 130 | 131 | private char StepBackward( int step = 1 ) 132 | { 133 | index = Math.Max( 0, index - step ); 134 | return data[ index ]; 135 | } 136 | 137 | #endregion 138 | #region Parse 139 | 140 | private object ParseValue() 141 | { 142 | switch( NextToken() ) { 143 | case END_OF_FILE: 144 | Debug.Log( "End of file" ); 145 | return null; 146 | case DICTIONARY_BEGIN_TOKEN: 147 | return ParseDictionary(); 148 | case ARRAY_BEGIN_TOKEN: 149 | return ParseArray(); 150 | case QUOTEDSTRING_BEGIN_TOKEN: 151 | return ParseString(); 152 | default: 153 | StepBackward(); 154 | return ParseEntity(); 155 | } 156 | } 157 | 158 | // private T Convert( PBXDictionary dictionary ) 159 | // { 160 | // if( dictionary.ContainsKey( "isa" ) ){ 161 | //// ((string)dictionary["isa"]).CompareTo( 162 | // Type targetType = Type.GetType( (string)dictionary["isa"] ); 163 | // if( targetType.IsSubclassOf( typeof(PBXObject) ) ) { 164 | // Debug.Log( "ok" ); 165 | // T converted = (T)Activator.CreateInstance( targetType ); 166 | // return converted; 167 | // } 168 | // else { 169 | // Debug.Log( "Warning: unknown PBX type: " + targetType.Name ); 170 | // return default(T); 171 | // } 172 | // 173 | // } 174 | // return default(T); 175 | // 176 | // } 177 | 178 | private PBXDictionary ParseDictionary() 179 | { 180 | SkipWhitespaces(); 181 | PBXDictionary dictionary = new PBXDictionary(); 182 | string keyString = string.Empty; 183 | object valueObject = null; 184 | 185 | bool complete = false; 186 | while( !complete ) { 187 | switch( NextToken() ) { 188 | case END_OF_FILE: 189 | Debug.Log( "Error: reached end of file inside a dictionary: " + index ); 190 | complete = true; 191 | break; 192 | 193 | case DICTIONARY_ITEM_DELIMITER_TOKEN: 194 | keyString = string.Empty; 195 | valueObject = null; 196 | break; 197 | 198 | case DICTIONARY_END_TOKEN: 199 | keyString = string.Empty; 200 | valueObject = null; 201 | complete = true; 202 | break; 203 | 204 | case DICTIONARY_ASSIGN_TOKEN: 205 | valueObject = ParseValue(); 206 | dictionary.Add( keyString, valueObject ); 207 | break; 208 | 209 | default: 210 | StepBackward(); 211 | keyString = ParseValue() as string; 212 | break; 213 | } 214 | } 215 | return dictionary; 216 | } 217 | 218 | private PBXList ParseArray() 219 | { 220 | PBXList list = new PBXList(); 221 | bool complete = false; 222 | while( !complete ) { 223 | switch( NextToken() ) { 224 | case END_OF_FILE: 225 | Debug.Log( "Error: Reached end of file inside a list: " + list ); 226 | complete = true; 227 | break; 228 | case ARRAY_END_TOKEN: 229 | complete = true; 230 | break; 231 | case ARRAY_ITEM_DELIMITER_TOKEN: 232 | break; 233 | default: 234 | StepBackward(); 235 | list.Add( ParseValue() ); 236 | break; 237 | } 238 | } 239 | return list; 240 | } 241 | 242 | private object ParseString() 243 | { 244 | string s = string.Empty; 245 | char c = StepForeward(); 246 | while( c != QUOTEDSTRING_END_TOKEN ) { 247 | s += c; 248 | 249 | if( c == QUOTEDSTRING_ESCAPE_TOKEN ) 250 | s += StepForeward(); 251 | 252 | c = StepForeward(); 253 | } 254 | 255 | return s; 256 | } 257 | 258 | private object ParseEntity() 259 | { 260 | string word = string.Empty; 261 | 262 | while( !Regex.IsMatch( Peek(), @"[;,\s=]" ) ) { 263 | word += StepForeward(); 264 | } 265 | 266 | if( word.Length != 24 && Regex.IsMatch( word, @"^\d+$" ) ) { 267 | return Int32.Parse( word ); 268 | } 269 | 270 | return word; 271 | } 272 | 273 | #endregion 274 | #region Serialize 275 | 276 | private bool SerializeValue( object value, StringBuilder builder, bool readable = false ) 277 | { 278 | if( value == null ) { 279 | builder.Append( "null" ); 280 | } 281 | else if( value is PBXObject ) { 282 | SerializeDictionary( ((PBXObject)value).data, builder, readable ); 283 | } 284 | else if( value is Dictionary ) { 285 | SerializeDictionary( (Dictionary)value, builder, readable ); 286 | } 287 | else if( value.GetType().IsArray ) { 288 | SerializeArray( new ArrayList( (ICollection)value ), builder, readable ); 289 | } 290 | else if( value is ArrayList ) { 291 | SerializeArray( (ArrayList)value, builder, readable ); 292 | } 293 | else if( value is string ) { 294 | SerializeString( (string)value, builder, readable ); 295 | } 296 | else if( value is Char ) { 297 | SerializeString( Convert.ToString( (char)value ), builder, readable ); 298 | } 299 | else if( value is bool ) { 300 | builder.Append( Convert.ToInt32( value ).ToString() ); 301 | } 302 | else if( value.GetType().IsPrimitive ) { 303 | builder.Append( Convert.ToString( value ) ); 304 | } 305 | // else if( value is Hashtable ) 306 | // { 307 | // serializeObject( (Hashtable)value, builder ); 308 | // } 309 | // else if( ( value is Boolean ) && ( (Boolean)value == true ) ) 310 | // { 311 | // builder.Append( "NO" ); 312 | // } 313 | // else if( ( value is Boolean ) && ( (Boolean)value == false ) ) 314 | // { 315 | // builder.Append( "YES" ); 316 | // } 317 | else { 318 | Debug.LogWarning( "Error: unknown object of type " + value.GetType().Name ); 319 | return false; 320 | } 321 | 322 | return true; 323 | } 324 | 325 | private bool SerializeDictionary( Dictionary dictionary, StringBuilder builder, bool readable = false ) 326 | { 327 | builder.Append( DICTIONARY_BEGIN_TOKEN ); 328 | 329 | foreach( KeyValuePair pair in dictionary ) { 330 | SerializeString( pair.Key, builder ); 331 | builder.Append( DICTIONARY_ASSIGN_TOKEN ); 332 | SerializeValue( pair.Value, builder ); 333 | builder.Append( DICTIONARY_ITEM_DELIMITER_TOKEN ); 334 | } 335 | 336 | builder.Append( DICTIONARY_END_TOKEN ); 337 | return true; 338 | } 339 | 340 | private bool SerializeArray( ArrayList anArray, StringBuilder builder, bool readable = false ) 341 | { 342 | builder.Append( ARRAY_BEGIN_TOKEN ); 343 | 344 | for( int i = 0; i < anArray.Count; i++ ) 345 | { 346 | object value = anArray[i]; 347 | 348 | if( !SerializeValue( value, builder ) ) 349 | { 350 | return false; 351 | } 352 | 353 | builder.Append( ARRAY_ITEM_DELIMITER_TOKEN ); 354 | } 355 | 356 | builder.Append( ARRAY_END_TOKEN ); 357 | return true; 358 | } 359 | 360 | private bool SerializeString( string aString, StringBuilder builder, bool useQuotes = false, bool readable = false ) 361 | { 362 | // Is a GUID? 363 | if( Regex.IsMatch( aString.ToUpper(), @"^[A-F0-9]{24}$" ) ) { 364 | builder.Append( aString.ToUpper() ); 365 | return true; 366 | } 367 | 368 | // Is an empty string? 369 | if( string.IsNullOrEmpty( aString ) ) { 370 | builder.Append( QUOTEDSTRING_BEGIN_TOKEN ); 371 | builder.Append( QUOTEDSTRING_END_TOKEN ); 372 | return true; 373 | } 374 | 375 | if( !Regex.IsMatch( aString, @"^[A-Za-z0-9_.]+$" ) ) { 376 | useQuotes = true; 377 | } 378 | 379 | if( useQuotes ) 380 | builder.Append( QUOTEDSTRING_BEGIN_TOKEN ); 381 | 382 | builder.Append( aString ); 383 | 384 | if( useQuotes ) 385 | builder.Append( QUOTEDSTRING_END_TOKEN ); 386 | 387 | return true; 388 | } 389 | 390 | #endregion 391 | } 392 | } -------------------------------------------------------------------------------- /PBXParser.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4318f22732c14aeeaa07d76a3c78a3c 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXProject.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXProject : PBXObject 8 | { 9 | protected string MAINGROUP_KEY = "mainGroup"; 10 | 11 | public PBXProject() : base() { 12 | } 13 | 14 | public PBXProject( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) { 15 | } 16 | 17 | public string mainGroupID { 18 | get { 19 | return (string)_data[ MAINGROUP_KEY ]; 20 | } 21 | } 22 | 23 | public void AddKnownRegion(string region) 24 | { 25 | if (string.IsNullOrEmpty(region)) { 26 | return; 27 | } 28 | 29 | if (System.Text.RegularExpressions.Regex.IsMatch(region, "[a-z]{2}[_-][a-z]{2}", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) { 30 | region = "\"" + region.Replace("_", "-") + "\""; 31 | } 32 | 33 | PBXList _list = (PBXList)this.data["knownRegions"]; 34 | if (!_list.Contains(region)) { 35 | _list.Add(region); 36 | } 37 | } 38 | 39 | public void RemoveKnownRegion(string region) 40 | { 41 | if (string.IsNullOrEmpty(region)) { 42 | return; 43 | } 44 | 45 | if (System.Text.RegularExpressions.Regex.IsMatch(region, "[a-z]{2}[_-][a-z]{2}", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) { 46 | region = "\"" + region.Replace("_", "-") + "\""; 47 | } 48 | 49 | PBXList _list = (PBXList)this.data["knownRegions"]; 50 | if (_list.Contains(region)) { 51 | _list.Remove(region); 52 | } 53 | } 54 | 55 | public void RemoveKnownRegionAll() 56 | { 57 | // やや強引だが、全部消しちゃうと動かなくなるので、初期値として英語を追加しておく 58 | this.data["knownRegions"] = new PBXList("en"); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /PBXProject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e2ac3a1ba3f94cb8bce3080b392f77c 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /PBXVariantGroup.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class PBXVariantGroup : PBXGroup 8 | { 9 | public PBXVariantGroup(string name, string path = null, string tree = "SOURCE_ROOT") : base(name, path, tree) 10 | { 11 | } 12 | 13 | public PBXVariantGroup(string guid, PBXDictionary dictionary) : base(guid, dictionary) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PBXVariantGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e713758fbeaa421a843f06fe0dd30e7 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Readme.mdown: -------------------------------------------------------------------------------- 1 | # XCode Editor for Unity 2 | 3 | ## OVERVIEW 4 | 5 | The purpose of this project is to allow editing an XCode 4 project. 6 | 7 | This project is based upon the python project **Mod PBXProj** by Calvin Rien (http://the.darktable.com/). Due to the recent addiction of PostProcessBuild attribute to Unity, I found much useful having a C# version of the library. 8 | 9 | 10 | ## INSTALLATION 11 | 12 | Clone this repo somewhere under Assets/Editor in your project. If your project is not yet checked into git, then you'll need to do the appropriate setup and add this as a submodule (google: git-submodule). 13 | 14 | If you already use git for your project, then just add this as a submodule. 15 | 16 | 17 | ## USAGE 18 | 19 | You can use the XCProject class in any part of your editor and postprocess code. Taking advantage of the great powers of the new PostProcessBuild attribute, I suggest to use a small cs static class to run through all the projmods files in your asses folder and simply apply them to the newly created xcode project. 20 | 21 | ```cs 22 | using UnityEditor; 23 | 24 | public static class XCodePostProcess 25 | { 26 | [PostProcessBuild] 27 | public static void OnPostProcessBuild( BuildTarget target, string path ) 28 | { 29 | // Create a new project object from build target 30 | XCodeEditor.XCProject project = new XCodeEditor.XCProject( targetPath ); 31 | 32 | // Find and run through all projmods files to patch the project 33 | var files = System.IO.Directory.GetFiles( Application.dataPath, "*.projmods", SearchOption.AllDirectories ); 34 | foreach( var file in files ) { 35 | project.ApplyMod( file ); 36 | } 37 | 38 | // Finally save the xcode project 39 | project.Save(); 40 | } 41 | } 42 | ``` 43 | 44 | The projmods file is a simple text file containing a JSON object. It will be used to pass the parameters to the ApplyMod method. This is the file I use for the GameCenter plugin as a brief example: 45 | 46 | ```json 47 | { 48 | "group": "GameCenter", 49 | "libs": [], 50 | "frameworks": ["GameKit.framework"], 51 | "headerpaths": ["Editor/iOS/GameCenter/**"], 52 | "files": ["Editor/iOS/GameCenter/GameCenterBinding.m", 53 | "Editor/iOS/GameCenter/GameCenterController.h", 54 | "Editor/iOS/GameCenter/GameCenterController.mm", 55 | "Editor/iOS/GameCenter/GameCenterManager.h", 56 | "Editor/iOS/GameCenter/GameCenterManager.m"], 57 | "folders": [], 58 | "excludes": ["^.*.meta$", "^.*.mdown^", "^.*.pdf$"] 59 | } 60 | ``` 61 | 62 | - group: all files and folders will be parented to this group; 63 | - libs: add libraries to build phase; 64 | - frameworks: add frameworks to the project; 65 | - headerpaths: add header paths to build phase; 66 | - files: add single files to the project; 67 | - folders: create a subgroup and add all files to the project (recursive); 68 | - excludes: file mask to exclude; 69 | 70 | Note: all paths are relative to projmods location 71 | 72 | 73 | ## LICENSE 74 | 75 | This code is distributed under the terms and conditions of the MIT license. 76 | 77 | Copyright (c) 2012 Daniele Cariola 78 | 79 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 80 | 81 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 82 | 83 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 84 | -------------------------------------------------------------------------------- /Readme.mdown.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a8213bf10e38424b81ce56f7700deba 3 | -------------------------------------------------------------------------------- /XCBuildConfiguration.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityEditor.XCodeEditor 5 | { 6 | public class XCBuildConfiguration : PBXObject 7 | { 8 | protected const string BUILDSETTINGS_KEY = "buildSettings"; 9 | protected const string HEADER_SEARCH_PATHS_KEY = "HEADER_SEARCH_PATHS"; 10 | protected const string LIBRARY_SEARCH_PATHS_KEY = "LIBRARY_SEARCH_PATHS"; 11 | protected const string FRAMEWORK_SEARCH_PATHS_KEY = "FRAMEWORK_SEARCH_PATHS"; 12 | protected const string OTHER_C_FLAGS_KEY = "OTHER_CFLAGS"; 13 | protected const string OTHER_LD_FLAGS_KEY = "OTHER_LDFLAGS"; 14 | protected const string GCC_ENABLE_CPP_EXCEPTIONS_KEY = "GCC_ENABLE_CPP_EXCEPTIONS"; 15 | protected const string GCC_ENABLE_OBJC_EXCEPTIONS_KEY = "GCC_ENABLE_OBJC_EXCEPTIONS"; 16 | 17 | public XCBuildConfiguration( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) 18 | { 19 | 20 | } 21 | 22 | public PBXDictionary buildSettings { 23 | get { 24 | if( ContainsKey( BUILDSETTINGS_KEY ) ) 25 | return (PBXDictionary)_data[BUILDSETTINGS_KEY]; 26 | 27 | return null; 28 | } 29 | } 30 | 31 | protected bool AddSearchPaths( string path, string key, bool recursive = true ) 32 | { 33 | PBXList paths = new PBXList(); 34 | paths.Add( path ); 35 | return AddSearchPaths( paths, key, recursive ); 36 | } 37 | 38 | protected bool AddSearchPaths( PBXList paths, string key, bool recursive = true ) 39 | { 40 | bool modified = false; 41 | 42 | if( !ContainsKey( BUILDSETTINGS_KEY ) ) 43 | this.Add( BUILDSETTINGS_KEY, new PBXDictionary() ); 44 | 45 | foreach( string path in paths ) { 46 | string currentPath = path; 47 | if( recursive && !path.EndsWith( "/**" ) ) 48 | currentPath += "/**"; 49 | 50 | // Debug.Log( "adding: " + currentPath ); 51 | if( !((PBXDictionary)_data[BUILDSETTINGS_KEY]).ContainsKey( key ) ) { 52 | ((PBXDictionary)_data[BUILDSETTINGS_KEY]).Add( key, new PBXList() ); 53 | } 54 | else if( ((PBXDictionary)_data[BUILDSETTINGS_KEY])[key] is string ) { 55 | PBXList list = new PBXList(); 56 | list.Add( ((PBXDictionary)_data[BUILDSETTINGS_KEY])[key] ); 57 | ((PBXDictionary)_data[BUILDSETTINGS_KEY])[key] = list; 58 | } 59 | 60 | currentPath = "\\\"" + currentPath + "\\\""; 61 | 62 | if( !((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[key]).Contains( currentPath ) ) { 63 | ((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[key]).Add( currentPath ); 64 | modified = true; 65 | } 66 | } 67 | 68 | return modified; 69 | } 70 | 71 | public bool AddHeaderSearchPaths( PBXList paths, bool recursive = true ) 72 | { 73 | return this.AddSearchPaths( paths, HEADER_SEARCH_PATHS_KEY, recursive ); 74 | } 75 | 76 | public bool AddLibrarySearchPaths( PBXList paths, bool recursive = true ) 77 | { 78 | return this.AddSearchPaths( paths, LIBRARY_SEARCH_PATHS_KEY, recursive ); 79 | } 80 | 81 | public bool AddFrameworkSearchPaths(PBXList paths, bool recursive = true) 82 | { 83 | return this.AddSearchPaths(paths, FRAMEWORK_SEARCH_PATHS_KEY, recursive); 84 | } 85 | 86 | public bool AddOtherCFlags( string flag ) 87 | { 88 | //Debug.Log( "INIZIO 1" ); 89 | PBXList flags = new PBXList(); 90 | flags.Add( flag ); 91 | return AddOtherCFlags( flags ); 92 | } 93 | 94 | public bool AddOtherCFlags( PBXList flags ) 95 | { 96 | //Debug.Log( "INIZIO 2" ); 97 | 98 | bool modified = false; 99 | 100 | if( !ContainsKey( BUILDSETTINGS_KEY ) ) 101 | this.Add( BUILDSETTINGS_KEY, new PBXDictionary() ); 102 | 103 | foreach( string flag in flags ) { 104 | 105 | if( !((PBXDictionary)_data[BUILDSETTINGS_KEY]).ContainsKey( OTHER_C_FLAGS_KEY ) ) { 106 | ((PBXDictionary)_data[BUILDSETTINGS_KEY]).Add( OTHER_C_FLAGS_KEY, new PBXList() ); 107 | } 108 | else if ( ((PBXDictionary)_data[BUILDSETTINGS_KEY])[ OTHER_C_FLAGS_KEY ] is string ) { 109 | string tempString = (string)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_C_FLAGS_KEY]; 110 | ((PBXDictionary)_data[BUILDSETTINGS_KEY])[ OTHER_C_FLAGS_KEY ] = new PBXList(); 111 | ((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_C_FLAGS_KEY]).Add( tempString ); 112 | } 113 | 114 | if( !((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_C_FLAGS_KEY]).Contains( flag ) ) { 115 | ((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_C_FLAGS_KEY]).Add( flag ); 116 | modified = true; 117 | } 118 | } 119 | 120 | return modified; 121 | } 122 | 123 | public bool AddOtherLDFlags( string flag ) 124 | { 125 | //Debug.Log( "INIZIO A" ); 126 | PBXList flags = new PBXList(); 127 | flags.Add( flag ); 128 | return AddOtherLDFlags( flags ); 129 | } 130 | 131 | public bool AddOtherLDFlags( PBXList flags ) 132 | { 133 | //Debug.Log( "INIZIO B" ); 134 | 135 | bool modified = false; 136 | 137 | if( !ContainsKey( BUILDSETTINGS_KEY ) ) 138 | this.Add( BUILDSETTINGS_KEY, new PBXDictionary() ); 139 | 140 | foreach( string flag in flags ) { 141 | 142 | if( !((PBXDictionary)_data[BUILDSETTINGS_KEY]).ContainsKey( OTHER_LD_FLAGS_KEY ) ) { 143 | ((PBXDictionary)_data[BUILDSETTINGS_KEY]).Add( OTHER_LD_FLAGS_KEY, new PBXList() ); 144 | } 145 | else if ( ((PBXDictionary)_data[BUILDSETTINGS_KEY])[ OTHER_LD_FLAGS_KEY ] is string ) { 146 | string tempString = (string)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_LD_FLAGS_KEY]; 147 | ((PBXDictionary)_data[BUILDSETTINGS_KEY])[ OTHER_LD_FLAGS_KEY ] = new PBXList(); 148 | ((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_LD_FLAGS_KEY]).Add( tempString ); 149 | } 150 | 151 | if( !((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_LD_FLAGS_KEY]).Contains( flag ) ) { 152 | ((PBXList)((PBXDictionary)_data[BUILDSETTINGS_KEY])[OTHER_LD_FLAGS_KEY]).Add( flag ); 153 | modified = true; 154 | } 155 | } 156 | 157 | return modified; 158 | } 159 | 160 | public bool GccEnableCppExceptions (string value) 161 | { 162 | if (!ContainsKey (BUILDSETTINGS_KEY)) 163 | this.Add (BUILDSETTINGS_KEY, new PBXDictionary ()); 164 | 165 | ((PBXDictionary)_data [BUILDSETTINGS_KEY])[GCC_ENABLE_CPP_EXCEPTIONS_KEY] = value; 166 | return true; 167 | } 168 | 169 | public bool GccEnableObjCExceptions (string value) 170 | { 171 | if (!ContainsKey (BUILDSETTINGS_KEY)) 172 | this.Add (BUILDSETTINGS_KEY, new PBXDictionary ()); 173 | 174 | ((PBXDictionary)_data [BUILDSETTINGS_KEY])[GCC_ENABLE_OBJC_EXCEPTIONS_KEY] = value; 175 | return true; 176 | } 177 | 178 | // class XCBuildConfiguration(PBXType): 179 | // def add_search_paths(self, paths, base, key, recursive=True): 180 | // modified = False 181 | // 182 | // if not isinstance(paths, list): 183 | // paths = [paths] 184 | // 185 | // if not self.has_key(base): 186 | // self[base] = PBXDict() 187 | // 188 | // for path in paths: 189 | // if recursive and not path.endswith('/**'): 190 | // path = os.path.join(path, '**') 191 | // 192 | // if not self[base].has_key(key): 193 | // self[base][key] = PBXList() 194 | // elif isinstance(self[base][key], basestring): 195 | // self[base][key] = PBXList(self[base][key]) 196 | // 197 | // if self[base][key].add('\\"%s\\"' % path): 198 | // modified = True 199 | // 200 | // return modified 201 | // 202 | // def add_header_search_paths(self, paths, recursive=True): 203 | // return self.add_search_paths(paths, 'buildSettings', 'HEADER_SEARCH_PATHS', recursive=recursive) 204 | // 205 | // def add_library_search_paths(self, paths, recursive=True): 206 | // return self.add_search_paths(paths, 'buildSettings', 'LIBRARY_SEARCH_PATHS', recursive=recursive) 207 | // 208 | // def add_other_cflags(self, flags): 209 | // modified = False 210 | // 211 | // base = 'buildSettings' 212 | // key = 'OTHER_CFLAGS' 213 | // 214 | // if isinstance(flags, basestring): 215 | // flags = PBXList(flags) 216 | // 217 | // if not self.has_key(base): 218 | // self[base] = PBXDict() 219 | // 220 | // for flag in flags: 221 | // 222 | // if not self[base].has_key(key): 223 | // self[base][key] = PBXList() 224 | // elif isinstance(self[base][key], basestring): 225 | // self[base][key] = PBXList(self[base][key]) 226 | // 227 | // if self[base][key].add(flag): 228 | // self[base][key] = [e for e in self[base][key] if e] 229 | // modified = True 230 | // 231 | // return modified 232 | } 233 | } -------------------------------------------------------------------------------- /XCBuildConfiguration.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6072c24958d074bbba00b6654dea8a07 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XCConfigurationList.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityEditor.XCodeEditor 6 | { 7 | public class XCConfigurationList : PBXObject 8 | { 9 | // XCBuildConfigurationList buildConfigurations; 10 | // bool defaultConfigurationIsVisible = false; 11 | // string defaultConfigurationName; 12 | 13 | public XCConfigurationList( string guid, PBXDictionary dictionary ) : base( guid, dictionary ) { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /XCConfigurationList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 186b7292bd62b4867bff9c84f77ba73e 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XCFileOperationQueue.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityEditor.XCodeEditor 5 | { 6 | public class XCFileOperationQueue : System.IDisposable 7 | { 8 | 9 | public void Dispose() 10 | { 11 | 12 | } 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /XCFileOperationQueue.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8a20716d12def417c9d0a303293098ac 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XCMod.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.IO; 4 | using Json = MiniJSON; 5 | 6 | namespace UnityEditor.XCodeEditor 7 | { 8 | public class XCMod 9 | { 10 | // private string group; 11 | // private ArrayList patches; 12 | // private ArrayList libs; 13 | // private ArrayList frameworks; 14 | // private ArrayList headerpaths; 15 | // private ArrayList files; 16 | // private ArrayList folders; 17 | // private ArrayList excludes; 18 | private Hashtable _datastore; 19 | private ArrayList _libs; 20 | 21 | public string name { get; private set; } 22 | public string path { get; private set; } 23 | 24 | public string group { 25 | get { 26 | return (string)_datastore["group"]; 27 | } 28 | } 29 | 30 | public ArrayList patches { 31 | get { 32 | return (ArrayList)_datastore["patches"]; 33 | } 34 | } 35 | 36 | public ArrayList libs { 37 | get { 38 | if( _libs == null ) { 39 | _libs = new ArrayList( ((ArrayList)_datastore["libs"]).Count ); 40 | foreach( string fileRef in (ArrayList)_datastore["libs"] ) { 41 | _libs.Add( new XCModFile( fileRef ) ); 42 | } 43 | } 44 | return _libs; 45 | } 46 | } 47 | 48 | public ArrayList frameworks { 49 | get { 50 | return (ArrayList)_datastore["frameworks"]; 51 | } 52 | } 53 | 54 | public ArrayList headerpaths { 55 | get { 56 | return (ArrayList)_datastore["headerpaths"]; 57 | } 58 | } 59 | 60 | public Hashtable buildSettings { 61 | get { 62 | return (Hashtable)_datastore["buildSettings"]; 63 | } 64 | } 65 | 66 | public ArrayList files { 67 | get { 68 | return (ArrayList)_datastore["files"]; 69 | } 70 | } 71 | 72 | public ArrayList folders { 73 | get { 74 | return (ArrayList)_datastore["folders"]; 75 | } 76 | } 77 | 78 | public ArrayList excludes { 79 | get { 80 | return (ArrayList)_datastore["excludes"]; 81 | } 82 | } 83 | 84 | public XCMod( string filename ) 85 | { 86 | FileInfo projectFileInfo = new FileInfo( filename ); 87 | if( !projectFileInfo.Exists ) { 88 | Debug.LogWarning( "File does not exist." ); 89 | } 90 | 91 | name = System.IO.Path.GetFileNameWithoutExtension( filename ); 92 | path = System.IO.Path.GetDirectoryName( filename ); 93 | 94 | string contents = projectFileInfo.OpenText().ReadToEnd(); 95 | _datastore = (Hashtable)XMiniJSON.jsonDecode( contents ); 96 | 97 | // group = (string)_datastore["group"]; 98 | // patches = (ArrayList)_datastore["patches"]; 99 | // libs = (ArrayList)_datastore["libs"]; 100 | // frameworks = (ArrayList)_datastore["frameworks"]; 101 | // headerpaths = (ArrayList)_datastore["headerpaths"]; 102 | // files = (ArrayList)_datastore["files"]; 103 | // folders = (ArrayList)_datastore["folders"]; 104 | // excludes = (ArrayList)_datastore["excludes"]; 105 | } 106 | 107 | 108 | // "group": "GameCenter", 109 | // "patches": [], 110 | // "libs": [], 111 | // "frameworks": ["GameKit.framework"], 112 | // "headerpaths": ["Editor/iOS/GameCenter/**"], 113 | // "files": ["Editor/iOS/GameCenter/GameCenterBinding.m", 114 | // "Editor/iOS/GameCenter/GameCenterController.h", 115 | // "Editor/iOS/GameCenter/GameCenterController.mm", 116 | // "Editor/iOS/GameCenter/GameCenterManager.h", 117 | // "Editor/iOS/GameCenter/GameCenterManager.m"], 118 | // "folders": [], 119 | // "excludes": ["^.*\\.meta$", "^.*\\.mdown^", "^.*\\.pdf$"] 120 | 121 | } 122 | 123 | public class XCModFile 124 | { 125 | public string filePath { get; private set; } 126 | public bool isWeak { get; private set; } 127 | 128 | public XCModFile( string inputString ) 129 | { 130 | isWeak = false; 131 | 132 | if( inputString.Contains( ":" ) ) { 133 | string[] parts = inputString.Split( ':' ); 134 | filePath = parts[0]; 135 | isWeak = ( parts[1].CompareTo( "weak" ) == 0 ); 136 | } 137 | else { 138 | filePath = inputString; 139 | } 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /XCMod.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9cf4113445351432eaf07fcc51ce34dc 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XCProject.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace UnityEditor.XCodeEditor 9 | { 10 | public partial class XCProject : System.IDisposable 11 | { 12 | 13 | // private string _filePath; 14 | private PBXDictionary _datastore; 15 | public PBXDictionary _objects; 16 | private PBXDictionary _configurations; 17 | 18 | private PBXGroup _rootGroup; 19 | private string _defaultConfigurationName; 20 | private string _rootObjectKey; 21 | 22 | public string projectRootPath { get; private set; } 23 | private FileInfo projectFileInfo; 24 | 25 | public string filePath { get; private set; } 26 | private string sourcePathRoot; 27 | private bool modified = false; 28 | 29 | #region Data 30 | 31 | // Objects 32 | private PBXDictionary _buildFiles; 33 | private PBXDictionary _groups; 34 | private PBXDictionary _variantGroups; 35 | private PBXDictionary _fileReferences; 36 | private PBXDictionary _nativeTargets; 37 | 38 | private PBXDictionary _frameworkBuildPhases; 39 | private PBXDictionary _resourcesBuildPhases; 40 | private PBXDictionary _shellScriptBuildPhases; 41 | private PBXDictionary _sourcesBuildPhases; 42 | private PBXDictionary _copyBuildPhases; 43 | 44 | private PBXDictionary _buildConfigurations; 45 | private PBXDictionary _configurationLists; 46 | 47 | private PBXProject _project; 48 | 49 | #endregion 50 | #region Constructor 51 | 52 | public XCProject() 53 | { 54 | 55 | } 56 | 57 | public XCProject( string filePath ) : this() 58 | { 59 | if( !System.IO.Directory.Exists( filePath ) ) { 60 | Debug.LogWarning( "Path does not exists." ); 61 | return; 62 | } 63 | 64 | if( filePath.EndsWith( ".xcodeproj" ) ) { 65 | // Debug.Log( "Opening project " + filePath ); 66 | this.projectRootPath = Path.GetDirectoryName( filePath ); 67 | this.filePath = filePath; 68 | } else { 69 | // Debug.Log( "Looking for xcodeproj files in " + filePath ); 70 | string[] projects = System.IO.Directory.GetDirectories( filePath, "*.xcodeproj" ); 71 | if( projects.Length == 0 ) { 72 | Debug.LogWarning( "Error: missing xcodeproj file" ); 73 | return; 74 | } 75 | 76 | this.projectRootPath = filePath; 77 | this.filePath = projects[ 0 ]; 78 | } 79 | 80 | // Convert to absolute 81 | this.projectRootPath = Path.GetFullPath(this.projectRootPath); 82 | 83 | projectFileInfo = new FileInfo( Path.Combine( this.filePath, "project.pbxproj" ) ); 84 | StreamReader sr = projectFileInfo.OpenText(); 85 | string contents = sr.ReadToEnd(); 86 | sr.Close(); 87 | 88 | PBXParser parser = new PBXParser(); 89 | _datastore = parser.Decode( contents ); 90 | if( _datastore == null ) { 91 | throw new System.Exception( "Project file not found at file path " + filePath ); 92 | } 93 | 94 | if( !_datastore.ContainsKey( "objects" ) ) { 95 | Debug.Log( "Errore " + _datastore.Count ); 96 | return; 97 | } 98 | 99 | _objects = (PBXDictionary)_datastore["objects"]; 100 | modified = false; 101 | 102 | _rootObjectKey = (string)_datastore["rootObject"]; 103 | if( !string.IsNullOrEmpty( _rootObjectKey ) ) { 104 | // _rootObject = (PBXDictionary)_objects[ _rootObjectKey ]; 105 | _project = new PBXProject( _rootObjectKey, (PBXDictionary)_objects[ _rootObjectKey ] ); 106 | // _rootGroup = (PBXDictionary)_objects[ (string)_rootObject[ "mainGroup" ] ]; 107 | _rootGroup = new PBXGroup( _rootObjectKey, (PBXDictionary)_objects[ _project.mainGroupID ] ); 108 | } 109 | else { 110 | Debug.LogWarning( "error: project has no root object" ); 111 | _project = null; 112 | _rootGroup = null; 113 | } 114 | 115 | } 116 | 117 | #endregion 118 | #region Properties 119 | 120 | public PBXProject project { 121 | get { 122 | return _project; 123 | } 124 | } 125 | 126 | public PBXGroup rootGroup { 127 | get { 128 | return _rootGroup; 129 | } 130 | } 131 | 132 | public PBXDictionary buildFiles { 133 | get { 134 | if( _buildFiles == null ) { 135 | _buildFiles = new PBXDictionary( _objects ); 136 | } 137 | return _buildFiles; 138 | } 139 | } 140 | 141 | public PBXDictionary groups { 142 | get { 143 | if( _groups == null ) { 144 | _groups = new PBXDictionary( _objects ); 145 | } 146 | return _groups; 147 | } 148 | } 149 | 150 | public PBXDictionary variantGroups { 151 | get { 152 | if( _variantGroups == null ) { 153 | _variantGroups = new PBXDictionary( _objects ); 154 | } 155 | return _variantGroups; 156 | } 157 | } 158 | 159 | public PBXDictionary fileReferences { 160 | get { 161 | if( _fileReferences == null ) { 162 | _fileReferences = new PBXDictionary( _objects ); 163 | } 164 | return _fileReferences; 165 | } 166 | } 167 | 168 | public PBXDictionary nativeTargets { 169 | get { 170 | if( _nativeTargets == null ) { 171 | _nativeTargets = new PBXDictionary( _objects ); 172 | } 173 | return _nativeTargets; 174 | } 175 | } 176 | 177 | public PBXDictionary buildConfigurations { 178 | get { 179 | if( _buildConfigurations == null ) { 180 | _buildConfigurations = new PBXDictionary( _objects ); 181 | } 182 | return _buildConfigurations; 183 | } 184 | } 185 | 186 | public PBXDictionary configurationLists { 187 | get { 188 | if( _configurationLists == null ) { 189 | _configurationLists = new PBXDictionary( _objects ); 190 | } 191 | return _configurationLists; 192 | } 193 | } 194 | 195 | public PBXDictionary frameworkBuildPhases { 196 | get { 197 | if( _frameworkBuildPhases == null ) { 198 | _frameworkBuildPhases = new PBXDictionary( _objects ); 199 | } 200 | return _frameworkBuildPhases; 201 | } 202 | } 203 | 204 | public PBXDictionary resourcesBuildPhases { 205 | get { 206 | if( _resourcesBuildPhases == null ) { 207 | _resourcesBuildPhases = new PBXDictionary( _objects ); 208 | } 209 | return _resourcesBuildPhases; 210 | } 211 | } 212 | 213 | public PBXDictionary shellScriptBuildPhases { 214 | get { 215 | if( _shellScriptBuildPhases == null ) { 216 | _shellScriptBuildPhases = new PBXDictionary( _objects ); 217 | } 218 | return _shellScriptBuildPhases; 219 | } 220 | } 221 | 222 | public PBXDictionary sourcesBuildPhases { 223 | get { 224 | if( _sourcesBuildPhases == null ) { 225 | _sourcesBuildPhases = new PBXDictionary( _objects ); 226 | } 227 | return _sourcesBuildPhases; 228 | } 229 | } 230 | 231 | public PBXDictionary copyBuildPhases { 232 | get { 233 | if( _copyBuildPhases == null ) { 234 | _copyBuildPhases = new PBXDictionary( _objects ); 235 | } 236 | return _copyBuildPhases; 237 | } 238 | } 239 | 240 | 241 | #endregion 242 | #region PBXMOD 243 | 244 | public bool AddOtherCFlags( string flag ) 245 | { 246 | return AddOtherCFlags( new PBXList( flag ) ); 247 | } 248 | 249 | public bool AddOtherCFlags( PBXList flags ) 250 | { 251 | foreach( KeyValuePair buildConfig in buildConfigurations ) { 252 | buildConfig.Value.AddOtherCFlags( flags ); 253 | } 254 | modified = true; 255 | return modified; 256 | } 257 | 258 | public bool AddOtherLDFlags( string flag ) 259 | { 260 | return AddOtherLDFlags( new PBXList( flag ) ); 261 | } 262 | 263 | public bool AddOtherLDFlags( PBXList flags ) 264 | { 265 | foreach( KeyValuePair buildConfig in buildConfigurations ) { 266 | buildConfig.Value.AddOtherLDFlags( flags ); 267 | } 268 | modified = true; 269 | return modified; 270 | } 271 | 272 | public bool GccEnableCppExceptions (string value) 273 | { 274 | foreach( KeyValuePair buildConfig in buildConfigurations ) { 275 | buildConfig.Value.GccEnableCppExceptions( value ); 276 | } 277 | modified = true; 278 | return modified; 279 | } 280 | 281 | public bool GccEnableObjCExceptions (string value) 282 | { 283 | foreach( KeyValuePair buildConfig in buildConfigurations ) { 284 | buildConfig.Value.GccEnableObjCExceptions( value ); 285 | } 286 | modified = true; 287 | return modified; 288 | } 289 | 290 | public bool AddHeaderSearchPaths( string path ) 291 | { 292 | return AddHeaderSearchPaths( new PBXList( path ) ); 293 | } 294 | 295 | public bool AddHeaderSearchPaths( PBXList paths ) 296 | { 297 | foreach( KeyValuePair buildConfig in buildConfigurations ) { 298 | // Debug.Log( "ADDING HEADER PATH: " + paths + " to " + buildConfig.Key ); 299 | buildConfig.Value.AddHeaderSearchPaths( paths ); 300 | } 301 | modified = true; 302 | return modified; 303 | } 304 | 305 | public bool AddLibrarySearchPaths( string path ) 306 | { 307 | return AddLibrarySearchPaths( new PBXList( path ) ); 308 | } 309 | 310 | public bool AddLibrarySearchPaths( PBXList paths ) 311 | { 312 | foreach( KeyValuePair buildConfig in buildConfigurations ) { 313 | buildConfig.Value.AddLibrarySearchPaths( paths ); 314 | } 315 | modified = true; 316 | return modified; 317 | } 318 | 319 | public bool AddFrameworkSearchPaths(string path) 320 | { 321 | return AddFrameworkSearchPaths(new PBXList(path)); 322 | } 323 | 324 | public bool AddFrameworkSearchPaths(PBXList paths) 325 | { 326 | foreach (KeyValuePair buildConfig in buildConfigurations) 327 | { 328 | buildConfig.Value.AddFrameworkSearchPaths(paths); 329 | } 330 | modified = true; 331 | return modified; 332 | } 333 | 334 | //FRAMEWORK_SEARCH_PATHS = ( 335 | // "$(inherited)", 336 | // "\"$(SRCROOT)/../../../../../../../Documents/FacebookSDK\"", 337 | //); 338 | 339 | 340 | // public PBXList GetObjectOfType( string type ) 341 | // { 342 | // PBXList result = new PBXList(); 343 | // foreach( KeyValuePair current in _objects ) { 344 | // //Debug.Log( "object: " + ((PBXDictionary)current.Value)["isa"] ); 345 | // if( string.Compare( (string)((PBXDictionary)current.Value)["isa"], type ) == 0 ) 346 | // result.Add( current.Value ); 347 | // } 348 | // return result; 349 | // } 350 | 351 | public object GetObject( string guid ) 352 | { 353 | return _objects[guid]; 354 | } 355 | 356 | 357 | // public PBXDictionary GetBuildPhase( string buildPhase ) 358 | // { 359 | // switch( buildPhase ) { 360 | // case "PBXFrameworksBuildPhase": 361 | // return (PBXDictionary)frameworkBuildPhases; 362 | // case "PBXResourcesBuildPhase": 363 | // return (PBXDictionary)resourcesBuildPhases; 364 | // case "PBXShellScriptBuildPhase": 365 | // return (PBXDictionary)shellScriptBuildPhases; 366 | // case "PBXSourcesBuildPhase": 367 | // return (PBXDictionary)sourcesBuildPhases; 368 | // case "PBXCopyFilesBuildPhase": 369 | // return (PBXDictionary)copyBuildPhases; 370 | // default: 371 | // return default(T); 372 | // } 373 | // } 374 | 375 | public PBXDictionary AddFile( string filePath, PBXGroup parent = null, string tree = "SOURCE_ROOT", bool createBuildFiles = true, bool weak = false, string name = null ) 376 | { 377 | PBXDictionary results = new PBXDictionary(); 378 | string absPath = string.Empty; 379 | 380 | if( Path.IsPathRooted( filePath ) ) { 381 | absPath = filePath; 382 | // Debug.Log( "Is rooted: " + absPath ); 383 | } 384 | else if( tree.CompareTo( "SDKROOT" ) != 0) { 385 | absPath = Path.Combine( Application.dataPath.Replace("Assets", ""), filePath ); 386 | // Debug.Log( "RElative: " + absPath ); 387 | } 388 | 389 | if( !( File.Exists( absPath ) || Directory.Exists( absPath ) ) && tree.CompareTo( "SDKROOT" ) != 0 ) { 390 | Debug.Log( "Missing file: " + absPath + " > " + filePath ); 391 | return results; 392 | } 393 | else if( tree.CompareTo( "SOURCE_ROOT" ) == 0 || tree.CompareTo( "GROUP" ) == 0 ) { 394 | System.Uri fileURI = new System.Uri( absPath ); 395 | System.Uri rootURI = new System.Uri( ( projectRootPath + "/." ) ); 396 | filePath = rootURI.MakeRelativeUri( fileURI ).ToString(); 397 | } 398 | // else { 399 | // tree = ""; 400 | // Debug.Log( "3: " + filePath ); 401 | // } 402 | // Debug.Log( "Add file result path: " + filePath ); 403 | 404 | if( parent == null ) { 405 | parent = _rootGroup; 406 | } 407 | 408 | // TODO: Aggiungere controllo se file già presente 409 | PBXFileReference fileReference = GetFile( System.IO.Path.GetFileName( filePath ) ); 410 | if( fileReference != null ) { 411 | // Debug.Log( "File già presente." ); 412 | return null; 413 | } 414 | 415 | fileReference = new PBXFileReference( filePath, (TreeEnum)System.Enum.Parse( typeof(TreeEnum), tree ) ); 416 | if (!string.IsNullOrEmpty(name)) { 417 | fileReference.data["name"] = name; 418 | } 419 | parent.AddChild( fileReference ); 420 | fileReferences.Add( fileReference ); 421 | results.Add( fileReference.guid, fileReference ); 422 | 423 | //Create a build file for reference 424 | if( !string.IsNullOrEmpty( fileReference.buildPhase ) && createBuildFiles ) { 425 | // PBXDictionary currentPhase = GetBuildPhase( fileReference.buildPhase ); 426 | PBXBuildFile buildFile; 427 | switch( fileReference.buildPhase ) { 428 | case "PBXFrameworksBuildPhase": 429 | foreach( KeyValuePair currentObject in frameworkBuildPhases ) { 430 | buildFile = new PBXBuildFile( fileReference, weak ); 431 | buildFiles.Add( buildFile ); 432 | currentObject.Value.AddBuildFile( buildFile ); 433 | } 434 | 435 | if ( !string.IsNullOrEmpty( absPath ) && File.Exists(absPath) && tree.CompareTo( "SOURCE_ROOT" ) == 0 ) { 436 | //Debug.LogError(absPath); 437 | string libraryPath = Path.Combine( "$(SRCROOT)", Path.GetDirectoryName( filePath ) ); 438 | this.AddLibrarySearchPaths( new PBXList(libraryPath) ); 439 | } 440 | else if (!string.IsNullOrEmpty( absPath ) && Directory.Exists(absPath) && absPath.EndsWith(".framework") && tree.CompareTo("GROUP") == 0) { // Annt: Add framework search path for FacebookSDK 441 | string frameworkPath = Path.Combine( "$(SRCROOT)", Path.GetDirectoryName( filePath ) ); 442 | this.AddFrameworkSearchPaths(new PBXList(frameworkPath)); 443 | } 444 | break; 445 | case "PBXResourcesBuildPhase": 446 | foreach( KeyValuePair currentObject in resourcesBuildPhases ) { 447 | buildFile = new PBXBuildFile( fileReference, weak ); 448 | buildFiles.Add( buildFile ); 449 | currentObject.Value.AddBuildFile( buildFile ); 450 | } 451 | break; 452 | case "PBXShellScriptBuildPhase": 453 | foreach( KeyValuePair currentObject in shellScriptBuildPhases ) { 454 | buildFile = new PBXBuildFile( fileReference, weak ); 455 | buildFiles.Add( buildFile ); 456 | currentObject.Value.AddBuildFile( buildFile ); 457 | } 458 | break; 459 | case "PBXSourcesBuildPhase": 460 | foreach( KeyValuePair currentObject in sourcesBuildPhases ) { 461 | buildFile = new PBXBuildFile( fileReference, weak ); 462 | buildFiles.Add( buildFile ); 463 | currentObject.Value.AddBuildFile( buildFile ); 464 | } 465 | break; 466 | case "PBXCopyFilesBuildPhase": 467 | foreach( KeyValuePair currentObject in copyBuildPhases ) { 468 | buildFile = new PBXBuildFile( fileReference, weak ); 469 | buildFiles.Add( buildFile ); 470 | currentObject.Value.AddBuildFile( buildFile ); 471 | } 472 | break; 473 | case null: 474 | Debug.LogWarning( "fase non supportata null" ); 475 | break; 476 | default: 477 | Debug.LogWarning( "fase non supportata def" ); 478 | return null; 479 | } 480 | } 481 | 482 | // Debug.Log( "Results " + results.Count + " - " ); 483 | // foreach( KeyValuePair obj in results ){ 484 | // Debug.Log( obj.Key + " - " + obj.Value.GetType().Name ); 485 | // } 486 | return results; 487 | 488 | // def add_file(self, f_path, parent=None, tree='SOURCE_ROOT', create_build_files=True, weak=False): 489 | // results = [] 490 | // 491 | // abs_path = '' 492 | // 493 | // if os.path.isabs(f_path): 494 | // abs_path = f_path 495 | // 496 | // if not os.path.exists(f_path): 497 | // return results 498 | // elif tree == 'SOURCE_ROOT': 499 | // f_path = os.path.relpath(f_path, self.source_root) 500 | // else: 501 | // tree = '' 502 | // 503 | // if not parent: 504 | // parent = self.root_group 505 | // elif not isinstance(parent, PBXGroup): 506 | // # assume it's an id 507 | // parent = self.objects.get(parent, self.root_group) 508 | // 509 | // file_ref = PBXFileReference.Create(f_path, tree) 510 | // parent.add_child(file_ref) 511 | // results.append(file_ref) 512 | // # create a build file for the file ref 513 | // if file_ref.build_phase and create_build_files: 514 | // phases = self.get_build_phases(file_ref.build_phase) 515 | // 516 | // for phase in phases: 517 | // build_file = PBXBuildFile.Create(file_ref, weak=weak) 518 | // 519 | // phase.add_build_file(build_file) 520 | // results.append(build_file) 521 | // 522 | // if abs_path and tree == 'SOURCE_ROOT' and os.path.isfile(abs_path)\ 523 | // and file_ref.build_phase == 'PBXFrameworksBuildPhase': 524 | // 525 | // library_path = os.path.join('$(SRCROOT)', os.path.split(f_path)[0]) 526 | // 527 | // self.add_library_search_paths([library_path], recursive=False) 528 | // 529 | // for r in results: 530 | // self.objects[r.id] = r 531 | // 532 | // if results: 533 | // self.modified = True 534 | // 535 | // return results 536 | } 537 | 538 | public bool AddFolder( string folderPath, PBXGroup parent = null, string[] exclude = null, bool recursive = true, bool createBuildFile = true ) 539 | { 540 | if( !Directory.Exists( folderPath ) ) 541 | return false; 542 | DirectoryInfo sourceDirectoryInfo = new DirectoryInfo( folderPath ); 543 | 544 | if( exclude == null ) 545 | exclude = new string[] {}; 546 | string regexExclude = string.Format( @"{0}", string.Join( "|", exclude ) ); 547 | 548 | // PBXDictionary results = new PBXDictionary(); 549 | 550 | if( parent == null ) 551 | parent = rootGroup; 552 | 553 | // Create group 554 | PBXGroup newGroup = GetGroup( sourceDirectoryInfo.Name, null /*relative path*/, parent ); 555 | // groups.Add( newGroup ); 556 | 557 | foreach( string directory in Directory.GetDirectories( folderPath ) ) 558 | { 559 | if( Regex.IsMatch( directory, regexExclude ) ) { 560 | continue; 561 | } 562 | 563 | // special_folders = ['.bundle', '.framework', '.xcodeproj'] 564 | Debug.Log( "DIR: " + directory ); 565 | if( directory.EndsWith( ".bundle" ) ) { 566 | // Treath it like a file and copy even if not recursive 567 | Debug.LogWarning( "This is a special folder: " + directory ); 568 | AddFile( directory, newGroup, "SOURCE_ROOT", createBuildFile ); 569 | Debug.Log( "fatto" ); 570 | continue; 571 | } 572 | 573 | if( recursive ) { 574 | Debug.Log( "recursive" ); 575 | AddFolder( directory, newGroup, exclude, recursive, createBuildFile ); 576 | } 577 | } 578 | // Adding files. 579 | foreach( string file in Directory.GetFiles( folderPath ) ) { 580 | if( Regex.IsMatch( file, regexExclude ) ) { 581 | continue; 582 | } 583 | //Debug.Log( "--> " + file + ", " + newGroup ); 584 | AddFile( file, newGroup, "SOURCE_ROOT", createBuildFile ); 585 | } 586 | 587 | modified = true; 588 | return modified; 589 | // def add_folder(self, os_path, parent=None, excludes=None, recursive=True, create_build_files=True): 590 | // if not os.path.isdir(os_path): 591 | // return [] 592 | // 593 | // if not excludes: 594 | // excludes = [] 595 | // 596 | // results = [] 597 | // 598 | // if not parent: 599 | // parent = self.root_group 600 | // elif not isinstance(parent, PBXGroup): 601 | // # assume it's an id 602 | // parent = self.objects.get(parent, self.root_group) 603 | // 604 | // path_dict = {os.path.split(os_path)[0]:parent} 605 | // special_list = [] 606 | // 607 | // for (grp_path, subdirs, files) in os.walk(os_path): 608 | // parent_folder, folder_name = os.path.split(grp_path) 609 | // parent = path_dict.get(parent_folder, parent) 610 | // 611 | // if [sp for sp in special_list if parent_folder.startswith(sp)]: 612 | // continue 613 | // 614 | // if folder_name.startswith('.'): 615 | // special_list.append(grp_path) 616 | // continue 617 | // 618 | // if os.path.splitext(grp_path)[1] in XcodeProject.special_folders: 619 | // # if this file has a special extension (bundle or framework mainly) treat it as a file 620 | // special_list.append(grp_path) 621 | // 622 | // new_files = self.verify_files([folder_name], parent=parent) 623 | // 624 | // if new_files: 625 | // results.extend(self.add_file(grp_path, parent, create_build_files=create_build_files)) 626 | // 627 | // continue 628 | // 629 | // # create group 630 | // grp = self.get_or_create_group(folder_name, path=self.get_relative_path(grp_path) , parent=parent) 631 | // path_dict[grp_path] = grp 632 | // 633 | // results.append(grp) 634 | // 635 | // file_dict = {} 636 | // 637 | // for f in files: 638 | // if f[0] == '.' or [m for m in excludes if re.match(m,f)]: 639 | // continue 640 | // 641 | // kwds = { 642 | // 'create_build_files': create_build_files, 643 | // 'parent': grp, 644 | // 'name': f 645 | // } 646 | // 647 | // f_path = os.path.join(grp_path, f) 648 | // 649 | // file_dict[f_path] = kwds 650 | // 651 | // new_files = self.verify_files([n.get('name') for n in file_dict.values()], parent=grp) 652 | // 653 | // add_files = [(k,v) for k,v in file_dict.items() if v.get('name') in new_files] 654 | // 655 | // for path, kwds in add_files: 656 | // kwds.pop('name', None) 657 | // 658 | // self.add_file(path, **kwds) 659 | // 660 | // if not recursive: 661 | // break 662 | // 663 | // for r in results: 664 | // self.objects[r.id] = r 665 | // 666 | // return results 667 | } 668 | 669 | #endregion 670 | #region Getters 671 | public PBXFileReference GetFile( string name ) 672 | { 673 | if( string.IsNullOrEmpty( name ) ) { 674 | return null; 675 | } 676 | 677 | foreach( KeyValuePair current in fileReferences ) { 678 | if( !string.IsNullOrEmpty( current.Value.name ) && current.Value.name == name ) { 679 | return current.Value; 680 | } 681 | if( !string.IsNullOrEmpty( current.Value.name ) && current.Value.name == "\"" + name + "\"" ) { 682 | return current.Value; 683 | } 684 | if( null != current.Value.data["path"] && !string.IsNullOrEmpty( current.Value.data["path"].ToString() ) && current.Value.data["path"].ToString() == name ) { 685 | return current.Value; 686 | } 687 | if( null != current.Value.data["path"] && !string.IsNullOrEmpty( current.Value.data["path"].ToString() ) && current.Value.data["path"].ToString() == "\"" + name + "\"" ) { 688 | return current.Value; 689 | } 690 | } 691 | 692 | return null; 693 | } 694 | 695 | public PBXFileReference GetFileByID( string guid ) 696 | { 697 | if( string.IsNullOrEmpty( guid ) ) { 698 | return null; 699 | } 700 | 701 | foreach (KeyValuePair current in fileReferences) { 702 | if ( !string.IsNullOrEmpty( current.Value.guid ) && current.Value.guid.ToUpper() == guid.ToUpper() ) { 703 | return current.Value; 704 | } 705 | } 706 | 707 | return null; 708 | } 709 | 710 | public string GetFileKey( string name ) 711 | { 712 | if( string.IsNullOrEmpty( name ) ) { 713 | return null; 714 | } 715 | 716 | foreach( KeyValuePair current in fileReferences ) { 717 | if( !string.IsNullOrEmpty( current.Value.name ) && current.Value.name == name ) { 718 | return current.Key; 719 | } 720 | if( !string.IsNullOrEmpty( current.Value.name ) && current.Value.name == "\"" + name + "\"" ) { 721 | return current.Key; 722 | } 723 | if( null != current.Value.data["path"] && !string.IsNullOrEmpty( current.Value.data["path"].ToString() ) && current.Value.data["path"].ToString() == name ) { 724 | return current.Key; 725 | } 726 | if( null != current.Value.data["path"] && !string.IsNullOrEmpty( current.Value.data["path"].ToString() ) && current.Value.data["path"].ToString() == "\"" + name + "\"" ) { 727 | return current.Key; 728 | } 729 | } 730 | 731 | return null; 732 | } 733 | 734 | public PBXBuildFile GetBuildFile(PBXFileReference fileReference) 735 | { 736 | if (null == fileReference) { 737 | return null; 738 | } 739 | foreach( KeyValuePair current in buildFiles ) { 740 | if (!current.Value.data.ContainsKey("fileRef") || string.IsNullOrEmpty((string)current.Value.data["fileRef"])) { 741 | continue; 742 | } 743 | if(current.Value.data["fileRef"].ToString().ToUpper() == fileReference.guid.ToUpper()) { 744 | return current.Value; 745 | } 746 | } 747 | return null; 748 | } 749 | 750 | public PBXBuildFile GetBuildFileByID( string guid ) 751 | { 752 | if( string.IsNullOrEmpty( guid ) ) { 753 | return null; 754 | } 755 | 756 | foreach (KeyValuePair current in buildFiles) { 757 | if ( !string.IsNullOrEmpty( current.Value.guid ) && current.Value.guid.ToUpper() == guid.ToUpper() ) { 758 | return current.Value; 759 | } 760 | } 761 | 762 | return null; 763 | } 764 | 765 | public string GetBuildFileKey(PBXFileReference fileReference) 766 | { 767 | if (null == fileReference) { 768 | return null; 769 | } 770 | foreach( KeyValuePair current in buildFiles ) { 771 | if (!current.Value.data.ContainsKey("fileRef") || string.IsNullOrEmpty((string)current.Value.data["fileRef"])) { 772 | continue; 773 | } 774 | if(current.Value.data["fileRef"].ToString().ToUpper() == fileReference.guid.ToUpper()) { 775 | return current.Key; 776 | } 777 | } 778 | return null; 779 | } 780 | 781 | public PBXGroup GetGroup( string name, string path = null, PBXGroup parent = null ) 782 | { 783 | // Debug.Log( "GetGroup: " + name + ", " + path + ", " + parent ); 784 | if( string.IsNullOrEmpty( name ) ) 785 | return null; 786 | 787 | if( parent == null ) 788 | parent = rootGroup; 789 | 790 | foreach( KeyValuePair current in groups ) { 791 | 792 | // Debug.Log( "current: " + current.Value.guid + ", " + current.Value.name + ", " + current.Value.path + " - " + parent.HasChild( current.Key ) ); 793 | if( string.IsNullOrEmpty( current.Value.name ) ) { 794 | if( current.Value.path.CompareTo( name ) == 0 && parent.HasChild( current.Key ) ) { 795 | return current.Value; 796 | } 797 | } 798 | else if( current.Value.name.CompareTo( name ) == 0 && parent.HasChild( current.Key ) ) { 799 | return current.Value; 800 | } 801 | } 802 | 803 | PBXGroup result = new PBXGroup( name, path ); 804 | groups.Add( result ); 805 | parent.AddChild( result ); 806 | 807 | modified = true; 808 | return result; 809 | 810 | // def get_or_create_group(self, name, path=None, parent=None): 811 | // if not name: 812 | // return None 813 | // 814 | // if not parent: 815 | // parent = self.root_group 816 | // elif not isinstance(parent, PBXGroup): 817 | // # assume it's an id 818 | // parent = self.objects.get(parent, self.root_group) 819 | // 820 | // groups = self.get_groups_by_name(name) 821 | // 822 | // for grp in groups: 823 | // if parent.has_child(grp.id): 824 | // return grp 825 | // 826 | // grp = PBXGroup.Create(name, path) 827 | // parent.add_child(grp) 828 | // 829 | // self.objects[grp.id] = grp 830 | // 831 | // self.modified = True 832 | // 833 | // return grp 834 | } 835 | 836 | public PBXVariantGroup GetVariantGroup( string name, string path = null, PBXGroup parent = null ) 837 | { 838 | if( string.IsNullOrEmpty( name ) ) 839 | return null; 840 | 841 | if( parent == null ) 842 | parent = rootGroup; 843 | 844 | foreach( KeyValuePair current in variantGroups ) { 845 | 846 | if( string.IsNullOrEmpty( current.Value.name ) ) { 847 | if( current.Value.path.CompareTo( name ) == 0 && parent.HasChild( current.Key ) ) { 848 | return current.Value; 849 | } 850 | } 851 | else if( current.Value.name.CompareTo( name ) == 0 && parent.HasChild( current.Key ) ) { 852 | return current.Value; 853 | } 854 | } 855 | 856 | PBXVariantGroup result = new PBXVariantGroup( name, path ); 857 | variantGroups.Add( result ); 858 | parent.AddChild( result ); 859 | 860 | modified = true; 861 | return result; 862 | 863 | } 864 | 865 | #endregion 866 | // #region Files 867 | // 868 | // 869 | // /// 870 | // /// Returns all file resources in the project, as an array of `XCSourceFile` objects. 871 | // /// 872 | // /// 873 | // /// The files. 874 | // /// 875 | // public ArrayList GetFiles() 876 | // { 877 | // return null; 878 | // } 879 | // 880 | // /// 881 | // /// Returns the project file with the specified key, or nil. 882 | // /// 883 | // /// 884 | // /// The file with key. 885 | // /// 886 | // /// 887 | // /// Key. 888 | // /// 889 | // public XCSourceFile GetFileWithKey( string key ) 890 | // { 891 | // return null; 892 | // } 893 | // 894 | // /// 895 | // /// Returns the project file with the specified name, or nil. If more than one project file matches the specified name, 896 | // /// which one is returned is undefined. 897 | // /// 898 | // /// 899 | // /// The file with name. 900 | // /// 901 | // /// 902 | // /// Name. 903 | // /// 904 | // public XCSourceFile GetFileWithName( string name ) 905 | // { 906 | // return null; 907 | // } 908 | // 909 | // /// 910 | // /// Returns all header files in the project, as an array of `XCSourceFile` objects. 911 | // /// 912 | // /// 913 | // /// The header files. 914 | // /// 915 | // public ArrayList GetHeaderFiles() 916 | // { 917 | // return null; 918 | // } 919 | // 920 | // /** 921 | // * Returns all implementation obj-c implementation files in the project, as an array of `XCSourceFile` objects. 922 | // */ 923 | // public ArrayList GetObjectiveCFiles() 924 | // { 925 | // return null; 926 | // } 927 | // 928 | // /** 929 | // * Returns all implementation obj-c++ implementation files in the project, as an array of `XCSourceFile` objects. 930 | // */ 931 | // public ArrayList GetObjectiveCPlusPlusFiles() 932 | // { 933 | // return null; 934 | // } 935 | // 936 | // /** 937 | // * Returns all the xib files in the project, as an array of `XCSourceFile` objects. 938 | // */ 939 | // public ArrayList GetXibFiles() 940 | // { 941 | // return null; 942 | // 943 | // } 944 | // 945 | // public ArrayList getImagePNGFiles() 946 | // { 947 | // return null; 948 | // } 949 | // 950 | // #endregion 951 | // #region Groups 952 | // /** 953 | // * Lists the groups in an xcode project, returning an array of `PBXGroup` objects. 954 | // */ 955 | // public PBXList groups { 956 | // get { 957 | // return null; 958 | // } 959 | // } 960 | // 961 | // /** 962 | // * Returns the root (top-level) group. 963 | // */ 964 | // public PBXGroup rootGroup { 965 | // get { 966 | // return null; 967 | // } 968 | // } 969 | // 970 | // /** 971 | // * Returns the root (top-level) groups, if there are multiple. An array of rootGroup if there is only one. 972 | // */ 973 | // public ArrayList rootGroups { 974 | // get { 975 | // return null; 976 | // } 977 | // } 978 | // 979 | // /** 980 | // * Returns the group with the given key, or nil. 981 | // */ 982 | // public PBXGroup GetGroupWithKey( string key ) 983 | // { 984 | // return null; 985 | // } 986 | // 987 | // /** 988 | // * Returns the group with the specified display name path - the directory relative to the root group. Eg Source/Main 989 | // */ 990 | // public PBXGroup GetGroupWithPathFromRoot( string path ) 991 | // { 992 | // return null; 993 | // } 994 | // 995 | // /** 996 | // * Returns the parent group for the group or file with the given key; 997 | // */ 998 | // public PBXGroup GetGroupForGroupMemberWithKey( string key ) 999 | // { 1000 | // return null; 1001 | // } 1002 | // 1003 | // /** 1004 | // * Returns the parent group for the group or file with the source file 1005 | // */ 1006 | // public PBXGroup GetGroupWithSourceFile( XCSourceFile sourceFile ) 1007 | // { 1008 | // return null; 1009 | // } 1010 | // 1011 | // #endregion 1012 | // #region Target 1013 | // 1014 | // /** 1015 | // * Lists the targets in an xcode project, returning an array of `XCTarget` objects. 1016 | // */ 1017 | // public ArrayList targets { 1018 | // get { 1019 | // return null; 1020 | // } 1021 | // } 1022 | // 1023 | // /** 1024 | // * Returns the target with the specified name, or nil. 1025 | // */ 1026 | // public XCTarget GetTargetWithName( string name ) 1027 | // { 1028 | // return null; 1029 | // } 1030 | // 1031 | // #endregion 1032 | // #region Configurations 1033 | // 1034 | // /** 1035 | // * Returns the target with the specified name, or nil. 1036 | // */ 1037 | // public Dictionary configurations { 1038 | // get { 1039 | // return null; 1040 | // } 1041 | // } 1042 | // 1043 | // public Dictionary GetConfigurationWithName( string name ) 1044 | // { 1045 | // return null; 1046 | // } 1047 | // 1048 | // public XCBuildConfigurationList defaultConfiguration { 1049 | // get { 1050 | // return null; 1051 | // } 1052 | // } 1053 | // 1054 | // #endregion 1055 | #region Mods 1056 | 1057 | public void ApplyMod( string pbxmod ) 1058 | { 1059 | XCMod mod = new XCMod( pbxmod ); 1060 | ApplyMod( mod ); 1061 | } 1062 | 1063 | public void ApplyMod( XCMod mod ) 1064 | { 1065 | PBXGroup modGroup = this.GetGroup( mod.group ); 1066 | 1067 | // Debug.Log( "Adding libraries..." ); 1068 | // PBXGroup librariesGroup = this.GetGroup( "Libraries" ); 1069 | foreach( XCModFile libRef in mod.libs ) { 1070 | string completeLibPath = System.IO.Path.Combine( "usr/lib", libRef.filePath ); 1071 | this.AddFile( completeLibPath, modGroup, "SDKROOT", true, libRef.isWeak ); 1072 | } 1073 | 1074 | // Debug.Log( "Adding frameworks..." ); 1075 | PBXGroup frameworkGroup = this.GetGroup( "Frameworks" ); 1076 | foreach( string framework in mod.frameworks ) { 1077 | string[] filename = framework.Split( ':' ); 1078 | bool isWeak = ( filename.Length > 1 ) ? true : false; 1079 | string completePath = System.IO.Path.Combine( "System/Library/Frameworks", filename[0] ); 1080 | this.AddFile( completePath, frameworkGroup, "SDKROOT", true, isWeak ); 1081 | } 1082 | 1083 | // Debug.Log( "Adding files..." ); 1084 | foreach( string filePath in mod.files ) { 1085 | string absoluteFilePath = System.IO.Path.Combine( mod.path, filePath ); 1086 | 1087 | 1088 | if( filePath.EndsWith(".framework") ) 1089 | this.AddFile( absoluteFilePath, frameworkGroup, "GROUP", true, false); 1090 | else 1091 | this.AddFile( absoluteFilePath, modGroup ); 1092 | } 1093 | 1094 | // Debug.Log( "Adding folders..." ); 1095 | foreach( string folderPath in mod.folders ) { 1096 | string absoluteFolderPath = System.IO.Path.Combine( mod.path, folderPath ); 1097 | this.AddFolder( absoluteFolderPath, modGroup, (string[])mod.excludes.ToArray( typeof(string) ) ); 1098 | } 1099 | 1100 | // Debug.Log( "Adding headerpaths..." ); 1101 | foreach( string headerpath in mod.headerpaths ) { 1102 | string absoluteHeaderPath = System.IO.Path.Combine( mod.path, headerpath ); 1103 | this.AddHeaderSearchPaths( absoluteHeaderPath ); 1104 | } 1105 | 1106 | // Debug.Log( "Configure build settings..." ); 1107 | Hashtable buildSettings = mod.buildSettings; 1108 | if( null != buildSettings && buildSettings.ContainsKey("OTHER_LDFLAGS") ) 1109 | { 1110 | // Debug.Log( " Adding other linker flags..." ); 1111 | ArrayList otherLinkerFlags = (ArrayList) buildSettings["OTHER_LDFLAGS"]; 1112 | foreach( string linker in otherLinkerFlags ) 1113 | { 1114 | string _linker = linker; 1115 | if( !_linker.StartsWith("-") ) 1116 | _linker = "-" + _linker; 1117 | this.AddOtherLDFlags( _linker ); 1118 | } 1119 | } 1120 | 1121 | if( null != buildSettings && buildSettings.ContainsKey("GCC_ENABLE_CPP_EXCEPTIONS") ) 1122 | { 1123 | // Debug.Log( " GCC_ENABLE_CPP_EXCEPTIONS = " + buildSettings["GCC_ENABLE_CPP_EXCEPTIONS"] ); 1124 | this.GccEnableCppExceptions( (string) buildSettings["GCC_ENABLE_CPP_EXCEPTIONS"] ); 1125 | } 1126 | 1127 | if( null != buildSettings && buildSettings.ContainsKey("GCC_ENABLE_OBJC_EXCEPTIONS") ) 1128 | { 1129 | // Debug.Log( " GCC_ENABLE_OBJC_EXCEPTIONS = " + buildSettings["GCC_ENABLE_OBJC_EXCEPTIONS"] ); 1130 | this.GccEnableObjCExceptions( (string) buildSettings["GCC_ENABLE_OBJC_EXCEPTIONS"] ); 1131 | } 1132 | 1133 | this.Consolidate(); 1134 | } 1135 | 1136 | #endregion 1137 | #region Savings 1138 | 1139 | public void Consolidate() 1140 | { 1141 | PBXDictionary consolidated = new PBXDictionary(); 1142 | consolidated.Append( this.buildFiles ); 1143 | consolidated.Append( this.groups ); 1144 | consolidated.Append( this.variantGroups ); 1145 | consolidated.Append( this.fileReferences ); 1146 | // consolidated.Append( this.project ); 1147 | consolidated.Append( this.nativeTargets ); 1148 | consolidated.Append( this.frameworkBuildPhases ); 1149 | consolidated.Append( this.resourcesBuildPhases ); 1150 | consolidated.Append( this.shellScriptBuildPhases ); 1151 | consolidated.Append( this.sourcesBuildPhases ); 1152 | consolidated.Append( this.copyBuildPhases ); 1153 | consolidated.Append( this.buildConfigurations ); 1154 | consolidated.Append( this.configurationLists ); 1155 | consolidated.Add( project.guid, project.data ); 1156 | _objects = consolidated; 1157 | consolidated = null; 1158 | } 1159 | 1160 | 1161 | public void Backup() 1162 | { 1163 | string backupPath = Path.Combine( this.filePath, "project.backup.pbxproj" ); 1164 | 1165 | // Delete previous backup file 1166 | if( File.Exists( backupPath ) ) 1167 | File.Delete( backupPath ); 1168 | 1169 | // Backup original pbxproj file first 1170 | File.Copy( System.IO.Path.Combine( this.filePath, "project.pbxproj" ), backupPath ); 1171 | } 1172 | 1173 | /// 1174 | /// Saves a project after editing. 1175 | /// 1176 | public void Save() 1177 | { 1178 | PBXDictionary result = new PBXDictionary(); 1179 | result.Add( "archiveVersion", 1 ); 1180 | result.Add( "classes", new PBXDictionary() ); 1181 | result.Add( "objectVersion", 45 ); 1182 | 1183 | Consolidate(); 1184 | result.Add( "objects", _objects ); 1185 | 1186 | result.Add( "rootObject", _rootObjectKey ); 1187 | 1188 | Backup(); 1189 | 1190 | // Parse result object directly into file 1191 | PBXParser parser = new PBXParser(); 1192 | StreamWriter saveFile = File.CreateText( System.IO.Path.Combine( this.filePath, "project.pbxproj" ) ); 1193 | saveFile.Write( parser.Encode( result, false ) ); 1194 | saveFile.Close(); 1195 | 1196 | // Xcode4Controller.Connect(); 1197 | // Xcode4Controller.OpenProject(filePath); 1198 | } 1199 | 1200 | /** 1201 | * Raw project data. 1202 | */ 1203 | public Dictionary objects { 1204 | get { 1205 | return null; 1206 | } 1207 | } 1208 | 1209 | 1210 | #endregion 1211 | 1212 | public void Dispose() 1213 | { 1214 | 1215 | } 1216 | } 1217 | } -------------------------------------------------------------------------------- /XCProject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99d07ffc2f1ec4dd2a3d4c80a5b81e51 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XCSourceFile.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityEditor.XCodeEditor 5 | { 6 | public class XCSourceFile : System.IDisposable 7 | { 8 | 9 | public void Dispose() 10 | { 11 | 12 | } 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /XCSourceFile.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 88d0290a28a6c4c339fa14fef6465310 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XCTarget.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityEditor.XCodeEditor 5 | { 6 | public class XCTarget : System.IDisposable 7 | { 8 | 9 | public void Dispose() 10 | { 11 | 12 | } 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /XCTarget.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 69423e6564ea64fc3b96ea9a712863e6 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XCodeEditorMenu.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | 7 | namespace UnityEditor.XCodeEditor 8 | { 9 | public class XCodeEditorMenu 10 | { 11 | 12 | //[MenuItem ("Build Tools/XCode Editor/DebugTest %t")] 13 | static void DebugTest() 14 | { 15 | // string projectPath = Path.Combine( Directory.GetParent( Application.dataPath ).ToString(), "XCode" ); 16 | // Debug.Log( "XcodePath: " + projectPath ); 17 | 18 | // XCProject currentProject = new XCProject( projectPath ); 19 | //XCProject.ApplyMod( projectPath, "/Users/Elyn/Projects/UnityPlugins/Unity Sandbox Project/Assets/Modules/GameCenter/Editor/iOS/GameCenter.projmods" ); 20 | 21 | //Debug.Log( 22 | // PBXDictionary test = new PBXDictionary(); 23 | // bool result = false; 24 | // if( test is Dictionary ) 25 | // result = true; 26 | // 27 | // Debug.Log( result ); 28 | 29 | // PBXType type = new PBXType(); 30 | // Debug.Log( "TYPE: " + type["isa"] ); 31 | // 32 | // PBXBuildFile build = new PBXBuildFile( "" ); 33 | // Debug.Log( "BUILDFILE: " + build["isa"] ); 34 | 35 | // Debug.Log( PBXObject.GenerateGuid().ToUpper() ); 36 | // PBXList testList = currentProject.GetObjectOfType( "XCBuildConfiguration" ); 37 | // Debug.Log( testList.Count ); 38 | // Debug.Log( currentProject.rootGroup.guid + " " + currentProject.rootGroup.name + " " + currentProject.rootGroup.path); 39 | // string path1 = "Data/mainData"; 40 | 41 | // string path2 = "/Users/Elyn/Projects/UnityPlugins/Modules/GameCenter/Editor/iOS/"; 42 | // Debug.Log( "Objects: " + currentProject._objects.Count ); 43 | // Debug.Log( "Files: " + currentProject.buildFiles.Count ); 44 | // Debug.Log( "Groups: " + currentProject.groups.Count ); 45 | // string[] excludes = new string[] {"^.*\\.meta$", "^.*\\.mdown^", "^.*\\.pdf$"}; 46 | // currentProject.AddFolder( path2, null, excludes ); 47 | // currentProject.Consolidate(); 48 | // Debug.Log( "Objects: " + currentProject._objects.Count ); 49 | // currentProject.Save(); 50 | 51 | //ALTRO 52 | // currentProject.AddOtherCFlags( "TEST_FLAG" ); 53 | // 54 | // foreach( KeyValuePair config in currentProject.buildConfigurations ) { 55 | // Debug.Log( "C: " + config.Value.buildSettings["OTHER_CFLAGS"] ); 56 | // foreach( string keys in (PBXList)config.Value.buildSettings["OTHER_CFLAGS"] ) 57 | // Debug.Log( keys ); 58 | // } 59 | 60 | // currentProject.Save(); 61 | 62 | } 63 | 64 | 65 | //[MenuItem ("Build Tools/XCode Editor/DebugTest2 %y")] 66 | static void DebugTest2() 67 | { 68 | string path1 = "/Users/Elyn/Projects/UnityPlugins/Unity Sandbox Project/Assets/Modules/GameCenter/Editor/iOS/GameCenterManager.m"; 69 | string path2 = "/Users/Elyn/Projects/UnityPlugins/Unity Sandbox Project/XCode/."; 70 | 71 | System.Uri fileURI = new System.Uri( path1 ); 72 | System.Uri rootURI = new System.Uri( path2 ); 73 | Debug.Log( fileURI.MakeRelativeUri( rootURI ).ToString() ); 74 | Debug.Log( rootURI.MakeRelativeUri( fileURI ).ToString() ); 75 | 76 | // string projectPath = Path.Combine( Directory.GetParent( Application.dataPath ).ToString(), "XCode" ); 77 | 78 | // string[] files = System.IO.Directory.GetFiles( projectPath, "Info.plist" ); 79 | // string contents = System.IO.File.OpenText( files[0] ).ReadToEnd(); 80 | 81 | // string[] projects = System.IO.Directory.GetDirectories( projectPath, "*.xcodeproj" ); 82 | // string projPath = System.IO.Path.Combine( projects[0], "project.pbxproj" ); 83 | // string contents = System.IO.File.OpenText( projPath ).ReadToEnd(); 84 | // Debug.Log( System.IO.File.OpenText( projPath ).ReadToEnd ); 85 | 86 | // PBXParser parser = new PBXParser(); 87 | // Hashtable test = (Hashtable)parser.Decode( contents ); 88 | // PBXDictionary test = parser.Decode( contents ); 89 | // Debug.Log( MiniJSON.jsonEncode( test ) ); 90 | // Debug.Log( test + " - " + test.Count ); 91 | // Debug.Log( parser.Encode( test ) ); 92 | 93 | 94 | } 95 | 96 | } 97 | } -------------------------------------------------------------------------------- /XCodeEditorMenu.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e4ad4476f7c2c4dbd9441d710894cdc4 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | -------------------------------------------------------------------------------- /XMiniJSON.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Text; 4 | using System.Collections.Generic; 5 | 6 | 7 | /* Based on the JSON parser from 8 | * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html 9 | * 10 | * I simplified it so that it doesn't throw exceptions 11 | * and can be used in Unity iPhone with maximum code stripping. 12 | */ 13 | /// 14 | /// This class encodes and decodes JSON strings. 15 | /// Spec. details, see http://www.json.org/ 16 | /// 17 | /// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable. 18 | /// All numbers are parsed to doubles. 19 | /// 20 | public class XMiniJSON 21 | { 22 | private const int TOKEN_NONE = 0; 23 | private const int TOKEN_CURLY_OPEN = 1; 24 | private const int TOKEN_CURLY_CLOSE = 2; 25 | private const int TOKEN_SQUARED_OPEN = 3; 26 | private const int TOKEN_SQUARED_CLOSE = 4; 27 | private const int TOKEN_COLON = 5; 28 | private const int TOKEN_COMMA = 6; 29 | private const int TOKEN_STRING = 7; 30 | private const int TOKEN_NUMBER = 8; 31 | private const int TOKEN_TRUE = 9; 32 | private const int TOKEN_FALSE = 10; 33 | private const int TOKEN_NULL = 11; 34 | private const int BUILDER_CAPACITY = 2000; 35 | 36 | /// 37 | /// On decoding, this value holds the position at which the parse failed (-1 = no error). 38 | /// 39 | protected static int lastErrorIndex = -1; 40 | protected static string lastDecode = ""; 41 | 42 | 43 | /// 44 | /// Parses the string json into a value 45 | /// 46 | /// A JSON string. 47 | /// An ArrayList, a Hashtable, a double, a string, null, true, or false 48 | public static object jsonDecode(string json) 49 | { 50 | // save the string for debug information 51 | XMiniJSON.lastDecode = json; 52 | 53 | if (json != null) 54 | { 55 | char[] charArray = json.ToCharArray(); 56 | int index = 0; 57 | bool success = true; 58 | object value = XMiniJSON.parseValue(charArray, ref index, ref success); 59 | 60 | if (success) 61 | XMiniJSON.lastErrorIndex = -1; 62 | else 63 | XMiniJSON.lastErrorIndex = index; 64 | 65 | return value; 66 | } 67 | else 68 | { 69 | return null; 70 | } 71 | } 72 | 73 | 74 | /// 75 | /// Converts a Hashtable / ArrayList / Dictionary(string,string) object into a JSON string 76 | /// 77 | /// A Hashtable / ArrayList 78 | /// A JSON encoded string, or null if object 'json' is not serializable 79 | public static string jsonEncode(object json) 80 | { 81 | var builder = new StringBuilder(BUILDER_CAPACITY); 82 | var success = XMiniJSON.serializeValue(json, builder); 83 | 84 | return (success ? builder.ToString() : null); 85 | } 86 | 87 | 88 | /// 89 | /// On decoding, this function returns the position at which the parse failed (-1 = no error). 90 | /// 91 | /// 92 | public static bool lastDecodeSuccessful() 93 | { 94 | return (XMiniJSON.lastErrorIndex == -1); 95 | } 96 | 97 | 98 | /// 99 | /// On decoding, this function returns the position at which the parse failed (-1 = no error). 100 | /// 101 | /// 102 | public static int getLastErrorIndex() 103 | { 104 | return XMiniJSON.lastErrorIndex; 105 | } 106 | 107 | 108 | /// 109 | /// If a decoding error occurred, this function returns a piece of the JSON string 110 | /// at which the error took place. To ease debugging. 111 | /// 112 | /// 113 | public static string getLastErrorSnippet() 114 | { 115 | if (XMiniJSON.lastErrorIndex == -1) 116 | { 117 | return ""; 118 | } 119 | else 120 | { 121 | int startIndex = XMiniJSON.lastErrorIndex - 5; 122 | int endIndex = XMiniJSON.lastErrorIndex + 15; 123 | if (startIndex < 0) 124 | startIndex = 0; 125 | 126 | if (endIndex >= XMiniJSON.lastDecode.Length) 127 | endIndex = XMiniJSON.lastDecode.Length - 1; 128 | 129 | return XMiniJSON.lastDecode.Substring(startIndex, endIndex - startIndex + 1); 130 | } 131 | } 132 | 133 | 134 | #region Parsing 135 | 136 | protected static Hashtable parseObject(char[] json, ref int index) 137 | { 138 | Hashtable table = new Hashtable(); 139 | int token; 140 | 141 | // { 142 | nextToken(json, ref index); 143 | 144 | bool done = false; 145 | while (!done) 146 | { 147 | token = lookAhead(json, index); 148 | if (token == XMiniJSON.TOKEN_NONE) 149 | { 150 | return null; 151 | } 152 | else if (token == XMiniJSON.TOKEN_COMMA) 153 | { 154 | nextToken(json, ref index); 155 | } 156 | else if (token == XMiniJSON.TOKEN_CURLY_CLOSE) 157 | { 158 | nextToken(json, ref index); 159 | return table; 160 | } 161 | else 162 | { 163 | // name 164 | string name = parseString(json, ref index); 165 | if (name == null) 166 | { 167 | return null; 168 | } 169 | 170 | // : 171 | token = nextToken(json, ref index); 172 | if (token != XMiniJSON.TOKEN_COLON) 173 | return null; 174 | 175 | // value 176 | bool success = true; 177 | object value = parseValue(json, ref index, ref success); 178 | if (!success) 179 | return null; 180 | 181 | table[name] = value; 182 | } 183 | } 184 | 185 | return table; 186 | } 187 | 188 | 189 | protected static ArrayList parseArray(char[] json, ref int index) 190 | { 191 | ArrayList array = new ArrayList(); 192 | 193 | // [ 194 | nextToken(json, ref index); 195 | 196 | bool done = false; 197 | while (!done) 198 | { 199 | int token = lookAhead(json, index); 200 | if (token == XMiniJSON.TOKEN_NONE) 201 | { 202 | return null; 203 | } 204 | else if (token == XMiniJSON.TOKEN_COMMA) 205 | { 206 | nextToken(json, ref index); 207 | } 208 | else if (token == XMiniJSON.TOKEN_SQUARED_CLOSE) 209 | { 210 | nextToken(json, ref index); 211 | break; 212 | } 213 | else 214 | { 215 | bool success = true; 216 | object value = parseValue(json, ref index, ref success); 217 | if (!success) 218 | return null; 219 | 220 | array.Add(value); 221 | } 222 | } 223 | 224 | return array; 225 | } 226 | 227 | 228 | protected static object parseValue(char[] json, ref int index, ref bool success) 229 | { 230 | switch (lookAhead(json, index)) 231 | { 232 | case XMiniJSON.TOKEN_STRING: 233 | return parseString(json, ref index); 234 | case XMiniJSON.TOKEN_NUMBER: 235 | return parseNumber(json, ref index); 236 | case XMiniJSON.TOKEN_CURLY_OPEN: 237 | return parseObject(json, ref index); 238 | case XMiniJSON.TOKEN_SQUARED_OPEN: 239 | return parseArray(json, ref index); 240 | case XMiniJSON.TOKEN_TRUE: 241 | nextToken(json, ref index); 242 | return Boolean.Parse("TRUE"); 243 | case XMiniJSON.TOKEN_FALSE: 244 | nextToken(json, ref index); 245 | return Boolean.Parse("FALSE"); 246 | case XMiniJSON.TOKEN_NULL: 247 | nextToken(json, ref index); 248 | return null; 249 | case XMiniJSON.TOKEN_NONE: 250 | break; 251 | } 252 | 253 | success = false; 254 | return null; 255 | } 256 | 257 | 258 | protected static string parseString(char[] json, ref int index) 259 | { 260 | string s = ""; 261 | char c; 262 | 263 | eatWhitespace(json, ref index); 264 | 265 | // " 266 | c = json[index++]; 267 | 268 | bool complete = false; 269 | while (!complete) 270 | { 271 | if (index == json.Length) 272 | break; 273 | 274 | c = json[index++]; 275 | if (c == '"') 276 | { 277 | complete = true; 278 | break; 279 | } 280 | else if (c == '\\') 281 | { 282 | if (index == json.Length) 283 | break; 284 | 285 | c = json[index++]; 286 | if (c == '"') 287 | { 288 | s += '"'; 289 | } 290 | else if (c == '\\') 291 | { 292 | s += '\\'; 293 | } 294 | else if (c == '/') 295 | { 296 | s += '/'; 297 | } 298 | else if (c == 'b') 299 | { 300 | s += '\b'; 301 | } 302 | else if (c == 'f') 303 | { 304 | s += '\f'; 305 | } 306 | else if (c == 'n') 307 | { 308 | s += '\n'; 309 | } 310 | else if (c == 'r') 311 | { 312 | s += '\r'; 313 | } 314 | else if (c == 't') 315 | { 316 | s += '\t'; 317 | } 318 | else if (c == 'u') 319 | { 320 | int remainingLength = json.Length - index; 321 | if (remainingLength >= 4) 322 | { 323 | char[] unicodeCharArray = new char[4]; 324 | Array.Copy(json, index, unicodeCharArray, 0, 4); 325 | 326 | // Drop in the HTML markup for the unicode character 327 | s += "&#x" + new string(unicodeCharArray) + ";"; 328 | 329 | /* 330 | uint codePoint = UInt32.Parse(new string(unicodeCharArray), NumberStyles.HexNumber); 331 | // convert the integer codepoint to a unicode char and add to string 332 | s += Char.ConvertFromUtf32((int)codePoint); 333 | */ 334 | 335 | // skip 4 chars 336 | index += 4; 337 | } 338 | else 339 | { 340 | break; 341 | } 342 | 343 | } 344 | } 345 | else 346 | { 347 | s += c; 348 | } 349 | 350 | } 351 | 352 | if (!complete) 353 | return null; 354 | 355 | return s; 356 | } 357 | 358 | 359 | protected static double parseNumber(char[] json, ref int index) 360 | { 361 | eatWhitespace(json, ref index); 362 | 363 | int lastIndex = getLastIndexOfNumber(json, index); 364 | int charLength = (lastIndex - index) + 1; 365 | char[] numberCharArray = new char[charLength]; 366 | 367 | Array.Copy(json, index, numberCharArray, 0, charLength); 368 | index = lastIndex + 1; 369 | return Double.Parse(new string(numberCharArray)); // , CultureInfo.InvariantCulture); 370 | } 371 | 372 | 373 | protected static int getLastIndexOfNumber(char[] json, int index) 374 | { 375 | int lastIndex; 376 | for (lastIndex = index; lastIndex < json.Length; lastIndex++) 377 | if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) 378 | { 379 | break; 380 | } 381 | return lastIndex - 1; 382 | } 383 | 384 | 385 | protected static void eatWhitespace(char[] json, ref int index) 386 | { 387 | for (; index < json.Length; index++) 388 | if (" \t\n\r".IndexOf(json[index]) == -1) 389 | { 390 | break; 391 | } 392 | } 393 | 394 | 395 | protected static int lookAhead(char[] json, int index) 396 | { 397 | int saveIndex = index; 398 | return nextToken(json, ref saveIndex); 399 | } 400 | 401 | 402 | protected static int nextToken(char[] json, ref int index) 403 | { 404 | eatWhitespace(json, ref index); 405 | 406 | if (index == json.Length) 407 | { 408 | return XMiniJSON.TOKEN_NONE; 409 | } 410 | 411 | char c = json[index]; 412 | index++; 413 | switch (c) 414 | { 415 | case '{': 416 | return XMiniJSON.TOKEN_CURLY_OPEN; 417 | case '}': 418 | return XMiniJSON.TOKEN_CURLY_CLOSE; 419 | case '[': 420 | return XMiniJSON.TOKEN_SQUARED_OPEN; 421 | case ']': 422 | return XMiniJSON.TOKEN_SQUARED_CLOSE; 423 | case ',': 424 | return XMiniJSON.TOKEN_COMMA; 425 | case '"': 426 | return XMiniJSON.TOKEN_STRING; 427 | case '0': 428 | case '1': 429 | case '2': 430 | case '3': 431 | case '4': 432 | case '5': 433 | case '6': 434 | case '7': 435 | case '8': 436 | case '9': 437 | case '-': 438 | return XMiniJSON.TOKEN_NUMBER; 439 | case ':': 440 | return XMiniJSON.TOKEN_COLON; 441 | } 442 | index--; 443 | 444 | int remainingLength = json.Length - index; 445 | 446 | // false 447 | if (remainingLength >= 5) 448 | { 449 | if (json[index] == 'f' && 450 | json[index + 1] == 'a' && 451 | json[index + 2] == 'l' && 452 | json[index + 3] == 's' && 453 | json[index + 4] == 'e') 454 | { 455 | index += 5; 456 | return XMiniJSON.TOKEN_FALSE; 457 | } 458 | } 459 | 460 | // true 461 | if (remainingLength >= 4) 462 | { 463 | if (json[index] == 't' && 464 | json[index + 1] == 'r' && 465 | json[index + 2] == 'u' && 466 | json[index + 3] == 'e') 467 | { 468 | index += 4; 469 | return XMiniJSON.TOKEN_TRUE; 470 | } 471 | } 472 | 473 | // null 474 | if (remainingLength >= 4) 475 | { 476 | if (json[index] == 'n' && 477 | json[index + 1] == 'u' && 478 | json[index + 2] == 'l' && 479 | json[index + 3] == 'l') 480 | { 481 | index += 4; 482 | return XMiniJSON.TOKEN_NULL; 483 | } 484 | } 485 | 486 | return XMiniJSON.TOKEN_NONE; 487 | } 488 | 489 | #endregion 490 | 491 | 492 | #region Serialization 493 | 494 | protected static bool serializeObjectOrArray(object objectOrArray, StringBuilder builder) 495 | { 496 | if (objectOrArray is Hashtable) 497 | { 498 | return serializeObject((Hashtable)objectOrArray, builder); 499 | } 500 | else if (objectOrArray is ArrayList) 501 | { 502 | return serializeArray((ArrayList)objectOrArray, builder); 503 | } 504 | else 505 | { 506 | return false; 507 | } 508 | } 509 | 510 | 511 | protected static bool serializeObject(Hashtable anObject, StringBuilder builder) 512 | { 513 | builder.Append("{"); 514 | 515 | IDictionaryEnumerator e = anObject.GetEnumerator(); 516 | bool first = true; 517 | while (e.MoveNext()) 518 | { 519 | string key = e.Key.ToString(); 520 | object value = e.Value; 521 | 522 | if (!first) 523 | { 524 | builder.Append(", "); 525 | } 526 | 527 | serializeString(key, builder); 528 | builder.Append(":"); 529 | if (!serializeValue(value, builder)) 530 | { 531 | return false; 532 | } 533 | 534 | first = false; 535 | } 536 | 537 | builder.Append("}"); 538 | return true; 539 | } 540 | 541 | 542 | protected static bool serializeDictionary(Dictionary dict, StringBuilder builder) 543 | { 544 | builder.Append("{"); 545 | 546 | bool first = true; 547 | foreach (var kv in dict) 548 | { 549 | if (!first) 550 | builder.Append(", "); 551 | 552 | serializeString(kv.Key, builder); 553 | builder.Append(":"); 554 | serializeString(kv.Value, builder); 555 | 556 | first = false; 557 | } 558 | 559 | builder.Append("}"); 560 | return true; 561 | } 562 | 563 | 564 | protected static bool serializeArray(ArrayList anArray, StringBuilder builder) 565 | { 566 | builder.Append("["); 567 | 568 | bool first = true; 569 | for (int i = 0; i < anArray.Count; i++) 570 | { 571 | object value = anArray[i]; 572 | 573 | if (!first) 574 | { 575 | builder.Append(", "); 576 | } 577 | 578 | if (!serializeValue(value, builder)) 579 | { 580 | return false; 581 | } 582 | 583 | first = false; 584 | } 585 | 586 | builder.Append("]"); 587 | return true; 588 | } 589 | 590 | 591 | protected static bool serializeValue(object value, StringBuilder builder) 592 | { 593 | // Type t = value.GetType(); 594 | // Debug.Log("type: " + t.ToString() + " isArray: " + t.IsArray); 595 | 596 | if (value == null) 597 | { 598 | builder.Append("null"); 599 | } 600 | else if (value.GetType().IsArray) 601 | { 602 | serializeArray(new ArrayList((ICollection)value), builder); 603 | } 604 | else if (value is string) 605 | { 606 | serializeString((string)value, builder); 607 | } 608 | else if (value is Char) 609 | { 610 | serializeString(Convert.ToString((char)value), builder); 611 | } 612 | else if (value is Hashtable) 613 | { 614 | serializeObject((Hashtable)value, builder); 615 | } 616 | else if (value is Dictionary) 617 | { 618 | serializeDictionary((Dictionary)value, builder); 619 | } 620 | else if (value is ArrayList) 621 | { 622 | serializeArray((ArrayList)value, builder); 623 | } 624 | else if ((value is Boolean) && ((Boolean)value == true)) 625 | { 626 | builder.Append("true"); 627 | } 628 | else if ((value is Boolean) && ((Boolean)value == false)) 629 | { 630 | builder.Append("false"); 631 | } 632 | else if (value.GetType().IsPrimitive) 633 | { 634 | serializeNumber(Convert.ToDouble(value), builder); 635 | } 636 | else 637 | { 638 | return false; 639 | } 640 | 641 | return true; 642 | } 643 | 644 | 645 | protected static void serializeString(string aString, StringBuilder builder) 646 | { 647 | builder.Append("\""); 648 | 649 | char[] charArray = aString.ToCharArray(); 650 | for (int i = 0; i < charArray.Length; i++) 651 | { 652 | char c = charArray[i]; 653 | if (c == '"') 654 | { 655 | builder.Append("\\\""); 656 | } 657 | else if (c == '\\') 658 | { 659 | builder.Append("\\\\"); 660 | } 661 | else if (c == '\b') 662 | { 663 | builder.Append("\\b"); 664 | } 665 | else if (c == '\f') 666 | { 667 | builder.Append("\\f"); 668 | } 669 | else if (c == '\n') 670 | { 671 | builder.Append("\\n"); 672 | } 673 | else if (c == '\r') 674 | { 675 | builder.Append("\\r"); 676 | } 677 | else if (c == '\t') 678 | { 679 | builder.Append("\\t"); 680 | } 681 | else 682 | { 683 | int codepoint = Convert.ToInt32(c); 684 | if ((codepoint >= 32) && (codepoint <= 126)) 685 | { 686 | builder.Append(c); 687 | } 688 | else 689 | { 690 | builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0')); 691 | } 692 | } 693 | } 694 | 695 | builder.Append("\""); 696 | } 697 | 698 | 699 | protected static void serializeNumber(double number, StringBuilder builder) 700 | { 701 | builder.Append(Convert.ToString(number)); // , CultureInfo.InvariantCulture)); 702 | } 703 | 704 | #endregion 705 | 706 | } 707 | 708 | 709 | 710 | #region Extension methods 711 | 712 | public static class XMiniJSONExtensions 713 | { 714 | /*public static string toJson(this Hashtable obj) 715 | { 716 | return XMiniJSON.jsonEncode(obj); 717 | } 718 | 719 | 720 | public static string toJson(this Dictionary obj) 721 | { 722 | return XMiniJSON.jsonEncode(obj); 723 | } 724 | 725 | 726 | public static ArrayList arrayListFromJson(this string json) 727 | { 728 | return XMiniJSON.jsonDecode(json) as ArrayList; 729 | } 730 | 731 | 732 | public static Hashtable hashtableFromJson(this string json) 733 | { 734 | return XMiniJSON.jsonDecode(json) as Hashtable; 735 | }*/ 736 | } 737 | 738 | #endregion -------------------------------------------------------------------------------- /XMiniJSON.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 468eda41212fa224d814bff6fa19fd0e 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /sample_config.projmods: -------------------------------------------------------------------------------- 1 | { 2 | "group": "Services", 3 | "libs": ["libsqlite3.dylib"], 4 | "frameworks": ["MessageUI.framework","StoreKit.framework","iAd.framework","CoreData.framework","SystemConfiguration.framework","Social.framework:","Security.framework:","Accounts.framework:","AdSupport.framework:"], 5 | "headerpaths": [], 6 | "files": ["/Users/beannt/Documents/FacebookSDK/FacebookSDK.framework", "/Users/beannt/Documents/FacebookSDK/FacebookSDK.framework/Versions/A/Resources/FacebookSDKResources.bundle"], 7 | "folders": ["iOS/Store/","iOS/GoogleAnalytics/"], 8 | "excludes": ["^.*.DS_Store$","^.*.meta$", "^.*.mdown^", "^.*.pdf$", "^.*.svn$"], 9 | "buildSettings": { 10 | "GCC_ENABLE_CPP_EXCEPTIONS": "YES", 11 | "GCC_ENABLE_OBJC_EXCEPTIONS": "YES", 12 | "OTHER_LDFLAGS" : ["-ObjC"] 13 | }} --------------------------------------------------------------------------------