#if UNITY_IOS || UNITY_TVOS using System; using System.Reflection; using UnityEditor.iOS.Xcode; namespace AppleAuth.Editor { public static class ProjectCapabilityManagerExtension { private const string EntitlementsArrayKey = "com.apple.developer.applesignin"; private const string DefaultAccessLevel = "Default"; private const string AuthenticationServicesFramework = "AuthenticationServices.framework"; private const BindingFlags NonPublicInstanceBinding = BindingFlags.NonPublic | BindingFlags.Instance; private const BindingFlags PublicInstanceBinding = BindingFlags.Public | BindingFlags.Instance; /// /// Extension method for ProjectCapabilityManager to add the Sign In With Apple capability in compatibility mode. /// In particular, adds the AuthenticationServices.framework as an Optional framework, preventing crashes in /// iOS versions previous to 13.0 /// /// The manager for the main target to use when adding the Sign In With Apple capability. /// The GUID for the UnityFramework target. If null, it will use the main target GUID. public static void AddSignInWithAppleWithCompatibility(this ProjectCapabilityManager manager, string unityFrameworkTargetGuid = null) { var managerType = typeof(ProjectCapabilityManager); var projectField = managerType.GetField("project", NonPublicInstanceBinding); var targetGuidField = managerType.GetField("m_TargetGuid", NonPublicInstanceBinding); var entitlementFilePathField = managerType.GetField("m_EntitlementFilePath", NonPublicInstanceBinding); var getOrCreateEntitlementDocMethod = managerType.GetMethod("GetOrCreateEntitlementDoc", NonPublicInstanceBinding); // in old unity versions PBXCapabilityType had internal ctor; that was changed to public afterwards - try both var constructorInfo = GetPBXCapabilityTypeConstructor(PublicInstanceBinding) ?? GetPBXCapabilityTypeConstructor(NonPublicInstanceBinding); if (projectField == null || targetGuidField == null || entitlementFilePathField == null || getOrCreateEntitlementDocMethod == null || constructorInfo == null) throw new Exception("Can't Add Sign In With Apple programatically in this Unity version"); var entitlementFilePath = entitlementFilePathField.GetValue(manager) as string; var entitlementDoc = getOrCreateEntitlementDocMethod.Invoke(manager, new object[] { }) as PlistDocument; if (entitlementDoc != null) { var plistArray = new PlistElementArray(); plistArray.AddString(DefaultAccessLevel); entitlementDoc.root[EntitlementsArrayKey] = plistArray; } var project = projectField.GetValue(manager) as PBXProject; if (project != null) { var mainTargetGuid = targetGuidField.GetValue(manager) as string; var capabilityType = constructorInfo.Invoke(new object[] { "com.apple.developer.applesignin.custom", true, string.Empty, true }) as PBXCapabilityType; var targetGuidToAddFramework = unityFrameworkTargetGuid; if (targetGuidToAddFramework == null) { targetGuidToAddFramework = mainTargetGuid; } project.AddFrameworkToProject(targetGuidToAddFramework, AuthenticationServicesFramework, true); project.AddCapability(mainTargetGuid, capabilityType, entitlementFilePath, false); } } private static ConstructorInfo GetPBXCapabilityTypeConstructor(BindingFlags flags) { return typeof(PBXCapabilityType).GetConstructor( flags, null, new[] {typeof(string), typeof(bool), typeof(string), typeof(bool)}, null); } } } #endif