using System; 
 | 
using System.IO; 
 | 
  
 | 
#if UNITY_XCODE_API_BUILD 
 | 
namespace UnityEditor.iOS.Xcode 
 | 
#else 
 | 
namespace UnityEditor.iOS.Xcode.Custom 
 | 
#endif 
 | 
{ 
 | 
    /// <summary> 
 | 
    /// The ProjectCapabilityManager class helps to add capabilities to the Xcode  
 | 
    /// project. This operation potentially involves modification of any of the  
 | 
    /// pbxproj file, the entitlements file(s) and Info.plist file(s). The  
 | 
    /// manager assumes ownership of all of these files until the last  
 | 
    /// WriteToFile() invocation. 
 | 
    /// </summary> 
 | 
    public class ProjectCapabilityManager 
 | 
    { 
 | 
        private readonly string m_BuildPath; 
 | 
        private readonly string m_TargetGuid; 
 | 
        private readonly string m_PBXProjectPath; 
 | 
        private readonly string m_EntitlementFilePath; 
 | 
        private PlistDocument m_Entitlements; 
 | 
        private PlistDocument m_InfoPlist; 
 | 
        protected internal PBXProject project; 
 | 
  
 | 
        /// <summary> 
 | 
        /// Creates a new instance of ProjectCapabilityManager. The returned  
 | 
        /// instance assumes ownership of the referenced pbxproj project file,  
 | 
        /// the entitlements file and project Info.plist files until the last  
 | 
        /// WriteToFile() call. 
 | 
        /// </summary> 
 | 
        /// <param name="pbxProjectPath">Path to the pbxproj file.</param> 
 | 
        /// <param name="entitlementFilePath">Path to the entitlements file.</param> 
 | 
        /// <param name="targetName">The name of the target to add entitlements for.</param> 
 | 
        public ProjectCapabilityManager(string pbxProjectPath, string entitlementFilePath, string targetName) 
 | 
        { 
 | 
            m_BuildPath = Directory.GetParent(Path.GetDirectoryName(pbxProjectPath)).FullName; 
 | 
  
 | 
            m_EntitlementFilePath = entitlementFilePath; 
 | 
            m_PBXProjectPath = pbxProjectPath; 
 | 
            project = new PBXProject(); 
 | 
            project.ReadFromString(File.ReadAllText(m_PBXProjectPath)); 
 | 
            m_TargetGuid = project.TargetGuidByName(targetName); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Writes the modifications to the project file, entitlements file and  
 | 
        /// the Info.plist file. Any external changes to these files after 
 | 
        /// the ProjectCapabilityManager instance has been created and before 
 | 
        /// the call to WriteToFile() will be overwritten. 
 | 
        /// </summary> 
 | 
        public void WriteToFile() 
 | 
        { 
 | 
            File.WriteAllText(m_PBXProjectPath, project.WriteToString()); 
 | 
            if (m_Entitlements != null) 
 | 
                m_Entitlements.WriteToFile(PBXPath.Combine(m_BuildPath, m_EntitlementFilePath)); 
 | 
            if (m_InfoPlist != null) 
 | 
                m_InfoPlist.WriteToFile(PBXPath.Combine(m_BuildPath, "Info.plist")); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds iCloud capability to project 
 | 
        /// </summary> 
 | 
        /// <param name="enableKeyValueStorage">Enables key-value storage option if set to true</param> 
 | 
        /// <param name="enableiCloudDocument">Enables iCloud document option if set to true</param> 
 | 
        /// <param name="customContainers">A list of custom containers to add</param> 
 | 
        public void AddiCloud(bool enableKeyValueStorage, bool enableiCloudDocument,  
 | 
                              string[] customContainers) 
 | 
        { 
 | 
            AddiCloud(enableKeyValueStorage, enableiCloudDocument, true, true,  
 | 
                      customContainers); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds iCloud capability to project 
 | 
        /// </summary> 
 | 
        /// <param name="enableKeyValueStorage">Enables key-value storage option if set to true</param> 
 | 
        /// <param name="enableiCloudDocument">Enables iCloud document option if set to true</param> 
 | 
        /// <param name="enablecloudKit">Enables cloudKit option if set to true</param> 
 | 
        /// <param name="addDefaultContainers">Default containers are added if this option is set to true</param> 
 | 
        /// <param name="customContainers">A list of custom containers to add</param> 
 | 
        public void AddiCloud(bool enableKeyValueStorage, bool enableiCloudDocument, bool enablecloudKit, bool addDefaultContainers, string[] customContainers) 
 | 
        { 
 | 
            var ent = GetOrCreateEntitlementDoc(); 
 | 
            var val = (ent.root[ICloudEntitlements.ContainerIdKey] = new PlistElementArray()) as PlistElementArray; 
 | 
  
 | 
            // Cloud document storage and CloudKit require specifying services. 
 | 
            PlistElementArray ser = null; 
 | 
            if (enableiCloudDocument || enablecloudKit) 
 | 
                ser = (ent.root[ICloudEntitlements.ServicesKey] = new PlistElementArray()) as PlistElementArray; 
 | 
  
 | 
            if (enableiCloudDocument) 
 | 
            { 
 | 
                val.values.Add(new PlistElementString(ICloudEntitlements.ContainerIdValue)); 
 | 
                ser.values.Add(new PlistElementString(ICloudEntitlements.ServicesDocValue)); 
 | 
                var ubiquity = (ent.root[ICloudEntitlements.UbiquityContainerIdKey] = new PlistElementArray()) as PlistElementArray; 
 | 
  
 | 
                if (addDefaultContainers) 
 | 
                    ubiquity.values.Add(new PlistElementString(ICloudEntitlements.UbiquityContainerIdValue)); 
 | 
  
 | 
                if (customContainers != null && customContainers.Length > 0) 
 | 
                { 
 | 
                    // For cloud document, custom containers go in the ubiquity values. 
 | 
                    for (var i = 0; i < customContainers.Length; i++) 
 | 
                        ubiquity.values.Add(new PlistElementString(customContainers[i])); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            if (enablecloudKit) 
 | 
            { 
 | 
                if (addDefaultContainers && !enableiCloudDocument) 
 | 
                    val.values.Add(new PlistElementString(ICloudEntitlements.ContainerIdValue)); 
 | 
  
 | 
                if (customContainers != null && customContainers.Length > 0) 
 | 
                { 
 | 
                    // For CloudKit, custom containers also go in the container id values. 
 | 
                    for (var i = 0; i < customContainers.Length; i++) 
 | 
                        val.values.Add(new PlistElementString(customContainers[i])); 
 | 
                } 
 | 
  
 | 
                ser.values.Add(new PlistElementString(ICloudEntitlements.ServicesKitValue)); 
 | 
            } 
 | 
  
 | 
            if (enableKeyValueStorage) 
 | 
                ent.root[ICloudEntitlements.KeyValueStoreKey] = new PlistElementString(ICloudEntitlements.KeyValueStoreValue); 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.iCloud, m_EntitlementFilePath, enablecloudKit); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Add Push (or remote) Notifications capability to the project 
 | 
        /// </summary> 
 | 
        /// <param name="development">Sets the development option if set to true</param> 
 | 
        public void AddPushNotifications(bool development) 
 | 
        { 
 | 
            GetOrCreateEntitlementDoc().root[PushNotificationEntitlements.Key] = new PlistElementString(development ? PushNotificationEntitlements.DevelopmentValue : PushNotificationEntitlements.ProductionValue); 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.PushNotifications, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Game Center capability to the project 
 | 
        /// </summary> 
 | 
        public void AddGameCenter() 
 | 
        { 
 | 
            var arr = (GetOrCreateInfoDoc().root[GameCenterInfo.Key] ?? (GetOrCreateInfoDoc().root[GameCenterInfo.Key] = new PlistElementArray())) as PlistElementArray; 
 | 
            arr.values.Add(new PlistElementString(GameCenterInfo.Value)); 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.GameCenter); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds wallet capability to the project. 
 | 
        /// </summary> 
 | 
        /// <param name="passSubset">Controls the allowed pass types. If null or 
 | 
        /// empty, then all team pass types are allowed. Otherwise, only the  
 | 
        /// specified subset of pass types is allowed</param> 
 | 
        public void AddWallet(string[] passSubset) 
 | 
        { 
 | 
            var arr = (GetOrCreateEntitlementDoc().root[WalletEntitlements.Key] = new PlistElementArray()) as PlistElementArray; 
 | 
            if ((passSubset == null || passSubset.Length == 0) && arr != null) 
 | 
            { 
 | 
                arr.values.Add(new PlistElementString(WalletEntitlements.BaseValue + WalletEntitlements.BaseValue)); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                for (var i = 0; i < passSubset.Length; i++) 
 | 
                { 
 | 
                    if (arr != null) 
 | 
                        arr.values.Add(new PlistElementString(WalletEntitlements.BaseValue + passSubset[i])); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.Wallet, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Siri capability to project. 
 | 
        /// </summary> 
 | 
        public void AddSiri() 
 | 
        { 
 | 
            GetOrCreateEntitlementDoc().root[SiriEntitlements.Key] = new PlistElementBoolean(true); 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.Siri, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Apple Pay capability to the project. 
 | 
        /// </summary> 
 | 
        /// <param name="merchants">The list of merchant IDs to configure</param> 
 | 
        public void AddApplePay(string[] merchants) 
 | 
        { 
 | 
            var arr = (GetOrCreateEntitlementDoc().root[ApplePayEntitlements.Key] = new PlistElementArray()) as PlistElementArray; 
 | 
            for (var i = 0; i < merchants.Length; i++) 
 | 
            { 
 | 
                arr.values.Add(new PlistElementString(merchants[i])); 
 | 
            } 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.ApplePay, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds In App Purchase capability to the project. 
 | 
        /// </summary> 
 | 
        public void AddInAppPurchase() 
 | 
        { 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.InAppPurchase); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Maps capability to the project. 
 | 
        /// </summary> 
 | 
        /// <param name="options">The routing options to configure.</param> 
 | 
        public void AddMaps(MapsOptions options) 
 | 
        { 
 | 
            var bundleArr = (GetOrCreateInfoDoc().root[MapsInfo.BundleKey] ?? (GetOrCreateInfoDoc().root[MapsInfo.BundleKey] = new PlistElementArray())) as PlistElementArray; 
 | 
            bundleArr.values.Add(new PlistElementDict()); 
 | 
            PlistElementDict bundleDic = GetOrCreateUniqueDictElementInArray(bundleArr); 
 | 
            bundleDic[MapsInfo.BundleNameKey] = new PlistElementString(MapsInfo.BundleNameValue); 
 | 
            var bundleTypeArr = (bundleDic[MapsInfo.BundleTypeKey] ?? (bundleDic[MapsInfo.BundleTypeKey]  = new PlistElementArray())) as PlistElementArray; 
 | 
            GetOrCreateStringElementInArray(bundleTypeArr, MapsInfo.BundleTypeValue); 
 | 
  
 | 
            var optionArr = (GetOrCreateInfoDoc().root[MapsInfo.ModeKey] ?? 
 | 
                            (GetOrCreateInfoDoc().root[MapsInfo.ModeKey] = new PlistElementArray())) as PlistElementArray; 
 | 
            if ((options & MapsOptions.Airplane) == MapsOptions.Airplane) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModePlaneValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Bike) == MapsOptions.Bike) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeBikeValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Bus) == MapsOptions.Bus) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeBusValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Car) == MapsOptions.Car) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeCarValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Ferry) == MapsOptions.Ferry) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeFerryValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Other) == MapsOptions.Other) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeOtherValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Pedestrian) == MapsOptions.Pedestrian) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModePedestrianValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.RideSharing) == MapsOptions.RideSharing) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeRideShareValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.StreetCar) == MapsOptions.StreetCar) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeStreetCarValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Subway) == MapsOptions.Subway) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeSubwayValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Taxi) == MapsOptions.Taxi) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeTaxiValue); 
 | 
            } 
 | 
            if ((options & MapsOptions.Train) == MapsOptions.Train) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, MapsInfo.ModeTrainValue); 
 | 
            } 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.Maps); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Personal VPN capability to the project. 
 | 
        /// </summary> 
 | 
        public void AddPersonalVPN() 
 | 
        { 
 | 
            var arr = (GetOrCreateEntitlementDoc().root[VPNEntitlements.Key] = new PlistElementArray()) as PlistElementArray; 
 | 
            arr.values.Add(new PlistElementString(VPNEntitlements.Value)); 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.PersonalVPN, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Background capability to the project. 
 | 
        /// </summary> 
 | 
        /// <param name="options">The list of background modes to configure.</param> 
 | 
        public void AddBackgroundModes(BackgroundModesOptions options) 
 | 
        { 
 | 
            var optionArr = (GetOrCreateInfoDoc().root[BackgroundInfo.Key] ?? 
 | 
                            (GetOrCreateInfoDoc().root[BackgroundInfo.Key] = new PlistElementArray())) as PlistElementArray; 
 | 
  
 | 
            if ((options & BackgroundModesOptions.ActsAsABluetoothLEAccessory) == BackgroundModesOptions.ActsAsABluetoothLEAccessory) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeActsBluetoothValue); 
 | 
            } 
 | 
            if ((options & BackgroundModesOptions.AudioAirplayPiP) == BackgroundModesOptions.AudioAirplayPiP) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeAudioValue); 
 | 
            } 
 | 
            if ((options & BackgroundModesOptions.BackgroundFetch) == BackgroundModesOptions.BackgroundFetch) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeFetchValue); 
 | 
            } 
 | 
            if ((options & BackgroundModesOptions.ExternalAccessoryCommunication) == BackgroundModesOptions.ExternalAccessoryCommunication) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeExtAccessoryValue); 
 | 
            } 
 | 
            if ((options & BackgroundModesOptions.LocationUpdates) == BackgroundModesOptions.LocationUpdates) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeLocationValue); 
 | 
            } 
 | 
            if ((options & BackgroundModesOptions.NewsstandDownloads) == BackgroundModesOptions.NewsstandDownloads) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeNewsstandValue); 
 | 
            } 
 | 
            if ((options & BackgroundModesOptions.RemoteNotifications) == BackgroundModesOptions.RemoteNotifications) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModePushValue); 
 | 
            } 
 | 
            if ((options & BackgroundModesOptions.VoiceOverIP) == BackgroundModesOptions.VoiceOverIP) 
 | 
            { 
 | 
                GetOrCreateStringElementInArray(optionArr, BackgroundInfo.ModeVOIPValue); 
 | 
            } 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.BackgroundModes); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Keychain Sharing capability to the project. 
 | 
        /// </summary> 
 | 
        /// <param name="accessGroups">The list of keychain access groups to configure.</param> 
 | 
        public void AddKeychainSharing(string[] accessGroups) 
 | 
        { 
 | 
            var arr = (GetOrCreateEntitlementDoc().root[KeyChainEntitlements.Key] = new PlistElementArray()) as PlistElementArray; 
 | 
            if (accessGroups != null) 
 | 
            { 
 | 
                for (var i = 0; i < accessGroups.Length; i++) 
 | 
                { 
 | 
                    arr.values.Add(new PlistElementString(accessGroups[i])); 
 | 
                } 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                arr.values.Add(new PlistElementString(KeyChainEntitlements.DefaultValue)); 
 | 
            } 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.KeychainSharing, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Inter App Audio capability to the project. 
 | 
        /// </summary> 
 | 
        public void AddInterAppAudio() 
 | 
        { 
 | 
            GetOrCreateEntitlementDoc().root[AudioEntitlements.Key] = new PlistElementBoolean(true); 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.InterAppAudio, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Associated Domains capability to the project. 
 | 
        /// </summary> 
 | 
        /// <param name="domains">The list of domains to configure.</param> 
 | 
        public void AddAssociatedDomains(string[] domains) 
 | 
        { 
 | 
            var arr = (GetOrCreateEntitlementDoc().root[AssociatedDomainsEntitlements.Key] = new PlistElementArray()) as PlistElementArray; 
 | 
            for (var i = 0; i < domains.Length; i++) 
 | 
            { 
 | 
                arr.values.Add(new PlistElementString(domains[i])); 
 | 
            } 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.AssociatedDomains, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds App Groups capability to the project. 
 | 
        /// </summary> 
 | 
        /// <param name="groups">The list of app groups to configure.</param> 
 | 
        public void AddAppGroups(string[] groups) 
 | 
        { 
 | 
            var arr = (GetOrCreateEntitlementDoc().root[AppGroupsEntitlements.Key] = new PlistElementArray()) as PlistElementArray; 
 | 
            for (var i = 0; i < groups.Length; i++) 
 | 
            { 
 | 
                arr.values.Add(new PlistElementString(groups[i])); 
 | 
            } 
 | 
  
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.AppGroups, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds HomeKit capability to the project. 
 | 
        /// </summary> 
 | 
        public void AddHomeKit() 
 | 
        { 
 | 
            GetOrCreateEntitlementDoc().root[HomeKitEntitlements.Key] = new PlistElementBoolean(true); 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.HomeKit, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Data Protection capability to the project. 
 | 
        /// </summary> 
 | 
        public void AddDataProtection() 
 | 
        { 
 | 
            GetOrCreateEntitlementDoc().root[DataProtectionEntitlements.Key] = new PlistElementString(DataProtectionEntitlements.Value); 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.DataProtection, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds HealthKit capability to the project. 
 | 
        /// </summary> 
 | 
        public void AddHealthKit() 
 | 
        { 
 | 
            var capabilityArr = (GetOrCreateInfoDoc().root[HealthInfo.Key] ?? 
 | 
                                (GetOrCreateInfoDoc().root[HealthInfo.Key] = new PlistElementArray())) as PlistElementArray; 
 | 
            GetOrCreateStringElementInArray(capabilityArr, HealthInfo.Value); 
 | 
            GetOrCreateEntitlementDoc().root[HealthKitEntitlements.Key] = new PlistElementBoolean(true); 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.HealthKit, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Adds Wireless Accessory Configuration capability to the project. 
 | 
        /// </summary> 
 | 
        public void AddWirelessAccessoryConfiguration() 
 | 
        { 
 | 
            GetOrCreateEntitlementDoc().root[WirelessAccessoryConfigurationEntitlements.Key] = new PlistElementBoolean(true); 
 | 
            project.AddCapability(m_TargetGuid, PBXCapabilityType.WirelessAccessoryConfiguration, m_EntitlementFilePath); 
 | 
        } 
 | 
  
 | 
        private PlistDocument GetOrCreateEntitlementDoc() 
 | 
        { 
 | 
            if (m_Entitlements == null) 
 | 
            { 
 | 
                m_Entitlements = new PlistDocument(); 
 | 
                string[] entitlementsFiles = Directory.GetFiles(m_BuildPath, m_EntitlementFilePath); 
 | 
                if (entitlementsFiles.Length > 0) 
 | 
                { 
 | 
                    m_Entitlements.ReadFromFile(entitlementsFiles[0]); 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    m_Entitlements.Create(); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            return m_Entitlements; 
 | 
        } 
 | 
  
 | 
        private PlistDocument GetOrCreateInfoDoc() 
 | 
        { 
 | 
            if (m_InfoPlist == null) 
 | 
            { 
 | 
                m_InfoPlist = new PlistDocument(); 
 | 
                string[] infoFiles = Directory.GetFiles(m_BuildPath + "/", "Info.plist"); 
 | 
                if (infoFiles.Length > 0) 
 | 
                { 
 | 
                    m_InfoPlist.ReadFromFile(infoFiles[0]); 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    m_InfoPlist.Create(); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            return m_InfoPlist; 
 | 
        } 
 | 
  
 | 
        private PlistElementString GetOrCreateStringElementInArray(PlistElementArray root, string value) 
 | 
        { 
 | 
            PlistElementString r = null; 
 | 
            var c = root.values.Count; 
 | 
            var exist = false; 
 | 
            for (var i = 0; i < c; i++) 
 | 
            { 
 | 
                if (root.values[i] is PlistElementString && (root.values[i] as PlistElementString).value == value) 
 | 
                { 
 | 
                    r = root.values[i] as PlistElementString; 
 | 
                    exist = true; 
 | 
                } 
 | 
            } 
 | 
            if (!exist) 
 | 
            { 
 | 
                r = new PlistElementString(value); 
 | 
                root.values.Add(r); 
 | 
            } 
 | 
            return r; 
 | 
        } 
 | 
  
 | 
        private PlistElementDict GetOrCreateUniqueDictElementInArray(PlistElementArray root) 
 | 
        { 
 | 
            PlistElementDict r; 
 | 
            if (root.values.Count == 0) 
 | 
            { 
 | 
                r = root.values[0] as PlistElementDict; 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                r = new PlistElementDict(); 
 | 
                root.values.Add(r); 
 | 
            } 
 | 
            return r; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    // The list of options available for Background Mode. 
 | 
    [Flags] 
 | 
    [Serializable] 
 | 
    public enum BackgroundModesOptions 
 | 
    { 
 | 
        None                           = 0, 
 | 
        AudioAirplayPiP                = 1<<0, 
 | 
        LocationUpdates                = 1<<1, 
 | 
        VoiceOverIP                    = 1<<2, 
 | 
        NewsstandDownloads             = 1<<3, 
 | 
        ExternalAccessoryCommunication = 1<<4, 
 | 
        UsesBluetoothLEAccessory       = 1<<5, 
 | 
        ActsAsABluetoothLEAccessory    = 1<<6, 
 | 
        BackgroundFetch                = 1<<7, 
 | 
        RemoteNotifications            = 1<<8 
 | 
    } 
 | 
  
 | 
    // The list of options available for Maps. 
 | 
    [Serializable] 
 | 
    [Flags] 
 | 
    public enum MapsOptions 
 | 
    { 
 | 
        None          = 0, 
 | 
        Airplane      = 1<<0, 
 | 
        Bike          = 1<<1, 
 | 
        Bus           = 1<<2, 
 | 
        Car           = 1<<3, 
 | 
        Ferry         = 1<<4, 
 | 
        Pedestrian    = 1<<5, 
 | 
        RideSharing   = 1<<6, 
 | 
        StreetCar     = 1<<7, 
 | 
        Subway        = 1<<8, 
 | 
        Taxi          = 1<<9, 
 | 
        Train         = 1<<10, 
 | 
        Other         = 1<<11 
 | 
    } 
 | 
  
 | 
    /* Follows the large quantity of string used as key and value all over the place in the info.plist or entitlements file. */ 
 | 
    internal class GameCenterInfo 
 | 
    { 
 | 
        internal static readonly string Key = "UIRequiredDeviceCapabilities"; 
 | 
        internal static readonly string Value = "gamekit"; 
 | 
    } 
 | 
  
 | 
    internal class MapsInfo 
 | 
    { 
 | 
        internal static readonly string BundleKey = "CFBundleDocumentTypes"; 
 | 
        internal static readonly string BundleNameKey = "CFBundleTypeName"; 
 | 
        internal static readonly string BundleNameValue = "MKDirectionsRequest"; 
 | 
        internal static readonly string BundleTypeKey = "LSItemContentTypes"; 
 | 
        internal static readonly string BundleTypeValue = "com.apple.maps.directionsrequest"; 
 | 
        internal static readonly string ModeKey = "MKDirectionsApplicationSupportedModes"; 
 | 
        internal static readonly string ModePlaneValue = "MKDirectionsModePlane"; 
 | 
        internal static readonly string ModeBikeValue = "MKDirectionsModeBike"; 
 | 
        internal static readonly string ModeBusValue = "MKDirectionsModeBus"; 
 | 
        internal static readonly string ModeCarValue = "MKDirectionsModeCar"; 
 | 
        internal static readonly string ModeFerryValue = "MKDirectionsModeFerry"; 
 | 
        internal static readonly string ModeOtherValue = "MKDirectionsModeOther"; 
 | 
        internal static readonly string ModePedestrianValue = "MKDirectionsModePedestrian"; 
 | 
        internal static readonly string ModeRideShareValue = "MKDirectionsModeRideShare"; 
 | 
        internal static readonly string ModeStreetCarValue = "MKDirectionsModeStreetCar"; 
 | 
        internal static readonly string ModeSubwayValue = "MKDirectionsModeSubway"; 
 | 
        internal static readonly string ModeTaxiValue = "MKDirectionsModeTaxi"; 
 | 
        internal static readonly string ModeTrainValue = "MKDirectionsModeTrain"; 
 | 
    } 
 | 
  
 | 
    internal class BackgroundInfo 
 | 
    { 
 | 
        internal static readonly string Key = "UIBackgroundModes"; 
 | 
        internal static readonly string ModeAudioValue = "audio"; 
 | 
        internal static readonly string ModeBluetoothValue = "bluetooth-central"; 
 | 
        internal static readonly string ModeActsBluetoothValue = "bluetooth-peripheral"; 
 | 
        internal static readonly string ModeExtAccessoryValue = "external-accessory"; 
 | 
        internal static readonly string ModeFetchValue = "fetch"; 
 | 
        internal static readonly string ModeLocationValue = "location"; 
 | 
        internal static readonly string ModeNewsstandValue = "newsstand-content"; 
 | 
        internal static readonly string ModePushValue = "remote-notification"; 
 | 
        internal static readonly string ModeVOIPValue = "voip"; 
 | 
    } 
 | 
  
 | 
    internal class HealthInfo 
 | 
    { 
 | 
        internal static readonly string Key = "UIRequiredDeviceCapabilities"; 
 | 
        internal static readonly string Value = "healthkit"; 
 | 
    } 
 | 
  
 | 
    internal class ICloudEntitlements 
 | 
    { 
 | 
        internal static readonly string ContainerIdKey = "com.apple.developer.icloud-container-identifiers"; 
 | 
        internal static readonly string ContainerIdValue = "iCloud.$(CFBundleIdentifier)"; 
 | 
        internal static readonly string UbiquityContainerIdKey = "com.apple.developer.ubiquity-container-identifiers"; 
 | 
        internal static readonly string UbiquityContainerIdValue = "iCloud.$(CFBundleIdentifier)"; 
 | 
        internal static readonly string ServicesKey = "com.apple.developer.icloud-services"; 
 | 
        internal static readonly string ServicesDocValue = "CloudDocuments"; 
 | 
        internal static readonly string ServicesKitValue = "CloudKit"; 
 | 
        internal static readonly string KeyValueStoreKey = "com.apple.developer.ubiquity-kvstore-identifier"; 
 | 
        internal static readonly string KeyValueStoreValue = "$(TeamIdentifierPrefix)$(CFBundleIdentifier)"; 
 | 
    } 
 | 
  
 | 
    internal class PushNotificationEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "aps-environment"; 
 | 
        internal static readonly string DevelopmentValue = "development"; 
 | 
        internal static readonly string ProductionValue = "production"; 
 | 
    } 
 | 
  
 | 
    internal class WalletEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "com.apple.developer.pass-type-identifiers"; 
 | 
        internal static readonly string BaseValue = "$(TeamIdentifierPrefix)"; 
 | 
        internal static readonly string DefaultValue = "*"; 
 | 
    } 
 | 
  
 | 
    internal class SiriEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "com.apple.developer.siri"; 
 | 
    } 
 | 
  
 | 
    internal class ApplePayEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "com.apple.developer.in-app-payments"; 
 | 
    } 
 | 
  
 | 
    internal class VPNEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "com.apple.developer.networking.vpn.api"; 
 | 
        internal static readonly string Value = "allow-vpn"; 
 | 
    } 
 | 
  
 | 
    internal class KeyChainEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "keychain-access-groups"; 
 | 
        internal static readonly string DefaultValue = "$(AppIdentifierPrefix)$(CFBundleIdentifier)"; 
 | 
    } 
 | 
  
 | 
    internal class AudioEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "inter-app-audio"; 
 | 
    } 
 | 
  
 | 
    internal class AssociatedDomainsEntitlements 
 | 
    { 
 | 
        // value is an array of string of domains 
 | 
        internal static readonly string Key = "com.apple.developer.associated-domains"; 
 | 
    } 
 | 
  
 | 
    internal class AppGroupsEntitlements 
 | 
    { 
 | 
        // value is an array of string of groups 
 | 
        internal static readonly string Key = "com.apple.security.application-groups"; 
 | 
    } 
 | 
  
 | 
    internal class HomeKitEntitlements 
 | 
    { 
 | 
        // value is bool true. 
 | 
        internal static readonly string Key = "com.apple.developer.homekit"; 
 | 
    } 
 | 
  
 | 
    internal class DataProtectionEntitlements 
 | 
    { 
 | 
        internal static readonly string Key = "com.apple.developer.default-data-protection"; 
 | 
        internal static readonly string Value = "NSFileProtectionComplete"; 
 | 
    } 
 | 
  
 | 
    internal class HealthKitEntitlements 
 | 
    { 
 | 
        // value is bool true. 
 | 
        internal static readonly string Key = "com.apple.developer.healthkit"; 
 | 
    } 
 | 
  
 | 
    internal class WirelessAccessoryConfigurationEntitlements 
 | 
    { 
 | 
        // value is bool true. 
 | 
        internal static readonly string Key = "com.apple.external-accessory.wireless-configuration"; 
 | 
    } 
 | 
} 
 |