14
14
// limitations under the License.
15
15
// </copyright>
16
16
17
- #if UNITY_IOS
18
17
using Google ;
19
18
using GooglePlayServices ;
20
19
using Google . JarResolver ;
@@ -719,6 +718,123 @@ private static Assembly ResolveUnityEditoriOSXcodeExtension(
719
718
return assembly ;
720
719
}
721
720
721
+ private static Type pbxProjectType = null ;
722
+ private static bool loadedPbxProjectType = false ;
723
+ private static MethodInfo pbxProjectReadFromString = null ;
724
+ private static MethodInfo pbxProjectAddFileToBuild = null ;
725
+ private static MethodInfo pbxProjectAddFile = null ;
726
+ private static MethodInfo pbxProjectAddBuildProperty = null ;
727
+ private static MethodInfo pbxProjectSetBuildProperty = null ;
728
+ private static MethodInfo pbxProjectWriteToFile = null ;
729
+ private static MethodInfo pbxProjectWriteToString = null ;
730
+
731
+ private static MethodInfo LoadPbxMethodViaReflection ( string name , Type [ ] parameters ) {
732
+ var methodInfo = pbxProjectType . GetMethod ( name ,
733
+ BindingFlags . Public | BindingFlags . Instance ,
734
+ null , parameters , null ) ;
735
+ if ( methodInfo == null ) {
736
+ throw new Exception ( $ "Unable to load method: { name } ") ;
737
+ }
738
+ return methodInfo ;
739
+ }
740
+
741
+ private static Type GetPbxProjectType ( ) {
742
+ if ( loadedPbxProjectType ) {
743
+ return pbxProjectType ;
744
+ }
745
+
746
+ // The type name including its namespace
747
+ string fullTypeName = "UnityEditor.iOS.Xcode.PBXProject" ;
748
+ // The name of the assembly (without the .dll extension)
749
+ string assemblyName = "UnityEditor.iOS.Extensions.Xcode" ;
750
+
751
+ try {
752
+ // First, try to get the type assuming the assembly is already loaded.
753
+ // This is often the case if the iOS module is installed and active.
754
+ pbxProjectType = Type . GetType ( fullTypeName + ", " + assemblyName ) ;
755
+
756
+ /*
757
+ if (pbxProjectType == null) {
758
+ // If not found, iterate through all loaded assemblies.
759
+ // This is a more robust fallback if the assembly name guess
760
+ // or Type.GetType's search path isn't sufficient.
761
+ foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
762
+ // Check if this assembly is the one we're looking for.
763
+ // The actual assembly name might sometimes vary slightly or
764
+ // not be exactly what's expected, so checking the type directly
765
+ // can be more reliable.
766
+ if (assembly.GetName().Name == assemblyName) {
767
+ pbxProjectType = assembly.GetType(fullTypeName);
768
+ if (pbxProjectType != null) {
769
+ // Found it, exit out.
770
+ break;
771
+ }
772
+ }
773
+ }
774
+ }*/
775
+
776
+ // Get the Enum type loaded in first, since one of the methods needs it.
777
+ GetPbxSourceTreeEnumSource ( ) ;
778
+
779
+ // Load the various methods, throwing if failing to find any.
780
+ pbxProjectReadFromString = LoadPbxMethodViaReflection ( "ReadFromString" ,
781
+ new Type [ ] { typeof ( string ) } ) ;
782
+ pbxProjectAddFileToBuild = LoadPbxMethodViaReflection ( "AddFileToBuild" ,
783
+ new Type [ ] { typeof ( string ) , typeof ( string ) } ) ;
784
+ pbxProjectAddFile = LoadPbxMethodViaReflection ( "AddFile" ,
785
+ new Type [ ] { typeof ( string ) , typeof ( string ) , pbxSourceTreeEnumType } ) ;
786
+ pbxProjectAddBuildProperty = LoadPbxMethodViaReflection ( "AddBuildProperty" ,
787
+ new Type [ ] { typeof ( string ) , typeof ( string ) , typeof ( string ) } ) ;
788
+ pbxProjectSetBuildProperty = LoadPbxMethodViaReflection ( "SetBuildProperty" ,
789
+ new Type [ ] { typeof ( string ) , typeof ( string ) , typeof ( string ) } ) ;
790
+ pbxProjectWriteToFile = LoadPbxMethodViaReflection ( "WriteToFile" ,
791
+ new Type [ ] { typeof ( string ) } ) ;
792
+ pbxProjectWriteToString = LoadPbxMethodViaReflection ( "WriteToString" ,
793
+ Type . EmptyTypes ) ;
794
+ } catch ( Exception e ) {
795
+ Debug . LogWarning ( $ "Exception while trying to find PBXProject type: { e } ") ;
796
+ pbxProjectType = null ;
797
+ }
798
+ loadedPbxProjectType = true ;
799
+ return pbxProjectType ;
800
+ }
801
+
802
+ private static Type pbxSourceTreeEnumType = null ;
803
+ private static object pbxSourceTreeEnum_Source = null ;
804
+ private static bool loadedPbxSourceTreeEnum = false ;
805
+
806
+ private static object GetPbxSourceTreeEnumSource ( ) {
807
+ if ( loadedPbxSourceTreeEnum ) {
808
+ return pbxSourceTreeEnum_Source ;
809
+ }
810
+
811
+ // The type name including its namespace
812
+ string fullTypeName = "UnityEditor.iOS.Xcode.PBXSourceTree" ;
813
+ // The name of the assembly (without the .dll extension)
814
+ string assemblyName = "UnityEditor.iOS.Extensions.Xcode" ;
815
+
816
+ try {
817
+ // First, try to get the type assuming the assembly is already loaded.
818
+ // This is often the case if the iOS module is installed and active.
819
+ pbxSourceTreeEnumType = Type . GetType ( fullTypeName + ", " + assemblyName ) ;
820
+
821
+ if ( pbxSourceTreeEnumType == null ) {
822
+ pbxSourceTreeEnum_Source = null ;
823
+ loadedPbxSourceTreeEnum = true ;
824
+ return null ;
825
+ }
826
+
827
+ // Get and cache the specific PBXSourceTree.Source value
828
+ pbxSourceTreeEnum_Source = Enum . Parse ( pbxSourceTreeEnumType , "Source" ) ;
829
+ } catch ( Exception e ) {
830
+ Debug . LogWarning ( $ "Exception while trying to find PBXSourceTree enum: { e } ") ;
831
+ pbxSourceTreeEnumType = null ;
832
+ pbxSourceTreeEnum_Source = null ;
833
+ }
834
+ loadedPbxSourceTreeEnum = true ;
835
+ return pbxSourceTreeEnum_Source ;
836
+ }
837
+
722
838
/// <summary>
723
839
/// Initialize the module.
724
840
/// </summary>
@@ -843,7 +959,9 @@ public static void SettingsDialog() {
843
959
/// </summary>
844
960
internal static bool MultipleXcodeTargetsSupported {
845
961
get {
846
- return typeof ( UnityEditor . iOS . Xcode . PBXProject ) . GetMethod (
962
+ Type pbxProject = GetPbxProjectType ( ) ;
963
+ if ( pbxProject == null ) return false ;
964
+ return pbxProject . GetMethod (
847
965
"GetUnityMainTargetGuid" , Type . EmptyTypes ) != null ;
848
966
}
849
967
}
@@ -856,8 +974,9 @@ public static string XcodeMainTargetName {
856
974
// NOTE: Unity-iPhone is hard coded in UnityEditor.iOS.Xcode.PBXProject and will no
857
975
// longer be exposed via GetUnityTargetName(). It hasn't changed in many years though
858
976
// so we'll use this constant as a relatively safe default.
859
- return MultipleXcodeTargetsSupported ? "Unity-iPhone" :
860
- ( string ) VersionHandler . InvokeStaticMethod ( typeof ( UnityEditor . iOS . Xcode . PBXProject ) ,
977
+ Type pbxProject = GetPbxProjectType ( ) ;
978
+ return ( pbxProject == null || MultipleXcodeTargetsSupported ) ? "Unity-iPhone" :
979
+ ( string ) VersionHandler . InvokeStaticMethod ( GetPbxProjectType ( ) ,
861
980
"GetUnityTargetName" , null ) ;
862
981
}
863
982
}
@@ -2035,7 +2154,6 @@ public static IEnumerable<string> GetXcodeTargetGuids(object xcodeProject) {
2035
2154
/// <returns>List of target GUIDs.</returns>
2036
2155
public static IEnumerable < string > GetXcodeTargetGuids ( object xcodeProject ,
2037
2156
bool includeAllTargets ) {
2038
- var project = ( UnityEditor . iOS . Xcode . PBXProject ) xcodeProject ;
2039
2157
var targets = new List < string > ( ) ;
2040
2158
if ( MultipleXcodeTargetsSupported ) {
2041
2159
// In Unity 2019.3+ TargetGuidByName will throw an exception if the Unity-iPhone target
@@ -2047,7 +2165,7 @@ public static IEnumerable<string> GetXcodeTargetGuids(object xcodeProject,
2047
2165
guidMethods . Add ( "GetUnityMainTargetGuid" ) ;
2048
2166
}
2049
2167
foreach ( var guidMethod in guidMethods ) {
2050
- targets . Add ( ( string ) VersionHandler . InvokeInstanceMethod ( project , guidMethod ,
2168
+ targets . Add ( ( string ) VersionHandler . InvokeInstanceMethod ( xcodeProject , guidMethod ,
2051
2169
null ) ) ;
2052
2170
}
2053
2171
} catch ( Exception exception ) {
@@ -2062,7 +2180,7 @@ public static IEnumerable<string> GetXcodeTargetGuids(object xcodeProject,
2062
2180
// TargetGuidByName in Unity < 2019.3 can be used to lookup any target GUID.
2063
2181
foreach ( var targetName in XcodeTargetNames ) {
2064
2182
targets . Add ( ( string ) VersionHandler . InvokeInstanceMethod (
2065
- project , "TargetGuidByName" , new [ ] { ( object ) targetName } ) ) ;
2183
+ xcodeProject , "TargetGuidByName" , new [ ] { ( object ) targetName } ) ) ;
2066
2184
}
2067
2185
}
2068
2186
return targets ;
@@ -2083,53 +2201,86 @@ internal static void PatchProject(
2083
2201
}
2084
2202
// Configure project settings for CocoaPods.
2085
2203
string pbxprojPath = GetProjectPath ( pathToBuiltProject ) ;
2086
- var project = new UnityEditor . iOS . Xcode . PBXProject ( ) ;
2087
- project . ReadFromString ( File . ReadAllText ( pbxprojPath ) ) ;
2204
+ var pbxProjectType = GetPbxProjectType ( ) ;
2205
+ if ( pbxProjectType == null ) {
2206
+ return ;
2207
+ }
2208
+ var project = Activator . CreateInstance ( pbxProjectType ) ;
2209
+ pbxProjectReadFromString . Invoke ( project , new object [ ] { File . ReadAllText ( pbxprojPath ) } ) ;
2088
2210
foreach ( var target in GetXcodeTargetGuids ( project ) ) {
2089
- project . SetBuildProperty ( target , "CLANG_ENABLE_MODULES" , "YES" ) ;
2090
- project . AddBuildProperty ( target , "OTHER_LDFLAGS" , "-ObjC" ) ;
2211
+ pbxProjectSetBuildProperty . Invoke ( project , new object [ ] {
2212
+ target , "CLANG_ENABLE_MODULES" , "YES"
2213
+ } ) ;
2214
+ pbxProjectAddBuildProperty . Invoke ( target , new object [ ] {
2215
+ target , "OTHER_LDFLAGS" , "-ObjC"
2216
+ } ) ;
2091
2217
// GTMSessionFetcher requires Obj-C exceptions.
2092
- project . SetBuildProperty ( target , "GCC_ENABLE_OBJC_EXCEPTIONS" , "YES" ) ;
2218
+ pbxProjectSetBuildProperty . Invoke ( project , new object [ ] {
2219
+ target , "GCC_ENABLE_OBJC_EXCEPTIONS" , "YES"
2220
+ } ) ;
2093
2221
if ( bitcodeDisabled ) {
2094
- project . AddBuildProperty ( target , "ENABLE_BITCODE" , "NO" ) ;
2222
+ pbxProjectAddBuildProperty . Invoke ( project , new object [ ] {
2223
+ target , "ENABLE_BITCODE" , "NO"
2224
+ } ) ;
2095
2225
}
2096
2226
}
2097
- File . WriteAllText ( pbxprojPath , project . WriteToString ( ) ) ;
2227
+ var contents = pbxProjectWriteToString . Invoke ( project , null ) as string ;
2228
+ File . WriteAllText ( pbxprojPath , contents ) ;
2098
2229
}
2099
2230
2100
2231
internal static void AddDummySwiftFile (
2101
2232
BuildTarget buildTarget , string pathToBuiltProject ) {
2102
- string pbxprojPath = GetProjectPath ( pathToBuiltProject ) ;
2103
- var project = new UnityEditor . iOS . Xcode . PBXProject ( ) ;
2104
- project . ReadFromString ( File . ReadAllText ( pbxprojPath ) ) ;
2105
-
2106
- string DUMMY_SWIFT_FILE_NAME = "Dummy.swift" ;
2107
- string DUMMY_SWIFT_FILE_CONTENT =
2108
- "// Generated by External Dependency Manager for Unity\n " +
2109
- "import Foundation" ;
2110
- string dummySwiftPath = Path . Combine ( pathToBuiltProject , DUMMY_SWIFT_FILE_NAME ) ;
2111
- if ( ! File . Exists ( dummySwiftPath ) ) {
2112
- File . WriteAllText ( dummySwiftPath , DUMMY_SWIFT_FILE_CONTENT ) ;
2113
- }
2114
-
2115
- foreach ( var target in GetXcodeTargetGuids ( project , includeAllTargets : false ) ) {
2116
- project . AddFileToBuild (
2117
- target ,
2118
- project . AddFile ( DUMMY_SWIFT_FILE_NAME ,
2119
- DUMMY_SWIFT_FILE_NAME ,
2120
- UnityEditor . iOS . Xcode . PBXSourceTree . Source ) ) ;
2121
- if ( ! string . IsNullOrEmpty ( SwiftLanguageVersion ) ) {
2122
- project . SetBuildProperty ( target , "SWIFT_VERSION" , SwiftLanguageVersion ) ;
2233
+ try {
2234
+ string pbxprojPath = GetProjectPath ( pathToBuiltProject ) ;
2235
+ Type pbxProjectType = GetPbxProjectType ( ) ;
2236
+ if ( pbxProjectType == null ) {
2237
+ return ;
2238
+ }
2239
+ var project = Activator . CreateInstance ( pbxProjectType ) ;
2240
+ pbxProjectReadFromString . Invoke ( project , new object [ ] { File . ReadAllText ( pbxprojPath ) } ) ;
2241
+
2242
+ string DUMMY_SWIFT_FILE_NAME = "Dummy.swift" ;
2243
+ string DUMMY_SWIFT_FILE_CONTENT =
2244
+ "// Generated by External Dependency Manager for Unity\n " +
2245
+ "import Foundation" ;
2246
+ string dummySwiftPath = Path . Combine ( pathToBuiltProject , DUMMY_SWIFT_FILE_NAME ) ;
2247
+ if ( ! File . Exists ( dummySwiftPath ) ) {
2248
+ File . WriteAllText ( dummySwiftPath , DUMMY_SWIFT_FILE_CONTENT ) ;
2123
2249
}
2124
2250
2125
- // These build properties are only required for multi-target Xcode project, which is
2126
- // generated from 2019.3+.
2127
- if ( MultipleXcodeTargetsSupported ) {
2128
- project . SetBuildProperty ( target , "CLANG_ENABLE_MODULES" , "YES" ) ;
2251
+ foreach ( var target in GetXcodeTargetGuids ( project , includeAllTargets : false ) ) {
2252
+ pbxProjectAddFileToBuild . Invoke ( project , new object [ ] {
2253
+ target ,
2254
+ pbxProjectAddFile . Invoke ( project , new object [ ] {
2255
+ DUMMY_SWIFT_FILE_NAME ,
2256
+ DUMMY_SWIFT_FILE_NAME ,
2257
+ GetPbxSourceTreeEnumSource ( )
2258
+ } ) as string
2259
+ } ) ;
2260
+ if ( ! string . IsNullOrEmpty ( SwiftLanguageVersion ) ) {
2261
+ pbxProjectSetBuildProperty . Invoke ( project , new object [ ] {
2262
+ target ,
2263
+ "SWIFT_VERSION" ,
2264
+ SwiftLanguageVersion
2265
+ } ) ;
2266
+ }
2267
+
2268
+ // These build properties are only required for multi-target Xcode project, which is
2269
+ // generated from 2019.3+.
2270
+ if ( MultipleXcodeTargetsSupported ) {
2271
+ pbxProjectSetBuildProperty . Invoke ( project , new object [ ] {
2272
+ target ,
2273
+ "CLANG_ENABLE_MODULES" ,
2274
+ "YES"
2275
+ } ) ;
2276
+ }
2129
2277
}
2130
- }
2131
2278
2132
- File . WriteAllText ( pbxprojPath , project . WriteToString ( ) ) ;
2279
+ var contents = pbxProjectWriteToString . Invoke ( project , null ) as string ;
2280
+ File . WriteAllText ( pbxprojPath , contents ) ;
2281
+ } catch ( Exception ex ) {
2282
+ Debug . LogWarning ( $ "Failed to add Dummy Swift file to Xcode project: { ex } ") ;
2283
+ }
2133
2284
}
2134
2285
2135
2286
/// <summary>
@@ -2319,7 +2470,6 @@ public static void GenPodfile(BuildTarget buildTarget,
2319
2470
default :
2320
2471
throw new Exception ( "IOSResolver.GenPodfile() invoked for a " +
2321
2472
"build target other than iOS or tvOS." ) ;
2322
- break ;
2323
2473
}
2324
2474
2325
2475
foreach ( var target in XcodeTargetNames ) {
@@ -2866,16 +3016,24 @@ public static void UpdateProjectDeps(
2866
3016
}
2867
3017
2868
3018
var pbxprojPath = GetProjectPath ( pathToBuiltProject ) ;
2869
- var project = new UnityEditor . iOS . Xcode . PBXProject ( ) ;
2870
- project . ReadFromString ( File . ReadAllText ( pbxprojPath ) ) ;
3019
+ var pbxProjectType = GetPbxProjectType ( ) ;
3020
+ if ( pbxProjectType == null ) {
3021
+ return ;
3022
+ }
3023
+ var project = Activator . CreateInstance ( pbxProjectType ) ;
3024
+ pbxProjectReadFromString . Invoke ( project , new object [ ] { File . ReadAllText ( pbxprojPath ) } ) ;
2871
3025
foreach ( var target in GetXcodeTargetGuids ( project ) ) {
2872
- var guid = project . AddFile (
3026
+ var guid = pbxProjectAddFile . Invoke ( project , new object [ ] {
2873
3027
Path . Combine ( podsDir , PODS_PROJECT_NAME + ".xcodeproj" ) ,
2874
3028
"Pods.xcodeproj" ,
2875
- UnityEditor . iOS . Xcode . PBXSourceTree . Source ) ;
2876
- project . AddFileToBuild ( target , guid ) ;
3029
+ GetPbxSourceTreeEnumSource ( )
3030
+ } ) as string ;
3031
+
3032
+ pbxProjectAddFileToBuild . Invoke ( project , new object [ ] {
3033
+ target , guid
3034
+ } ) ;
2877
3035
}
2878
- project . WriteToFile ( pbxprojPath ) ;
3036
+ pbxProjectWriteToFile . Invoke ( project , new object [ ] { pbxprojPath } ) ;
2879
3037
}
2880
3038
2881
3039
/// <summary>
@@ -2900,5 +3058,3 @@ private static void RefreshXmlDependencies() {
2900
3058
}
2901
3059
2902
3060
} // namespace Google
2903
-
2904
- #endif // UNITY_IOS
0 commit comments