Example #1
0
 public static void SetComplicationGroup(this PDictionary dict, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         dict.Remove(ManifestKeys.CLKComplicationGroup);
     }
     else
     {
         dict [ManifestKeys.CLKComplicationGroup] = value;
     }
 }
Example #2
0
 public static void SetMinimumSystemVersion(this PDictionary dict, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         dict.Remove(ManifestKeys.LSMinimumSystemVersion);
     }
     else
     {
         dict[ManifestKeys.LSMinimumSystemVersion] = value;
     }
 }
Example #3
0
 public static void SetWKCompanionAppBundleIdentifier(this PDictionary dict, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         dict.Remove(ManifestKeys.WKCompanionAppBundleIdentifier);
     }
     else
     {
         dict[ManifestKeys.WKCompanionAppBundleIdentifier] = value;
     }
 }
Example #4
0
 public static void SetCLKComplicationPrincipalClass(this PDictionary dict, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         dict.Remove(ManifestKeys.CLKComplicationPrincipalClass);
     }
     else
     {
         dict [ManifestKeys.CLKComplicationPrincipalClass] = value;
     }
 }
Example #5
0
 public static void SetCFBundleShortVersionString(this PDictionary dict, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         dict.Remove(ManifestKeys.CFBundleShortVersionString);
     }
     else
     {
         dict[ManifestKeys.CFBundleShortVersionString] = value;
     }
 }
Example #6
0
 public static void SetCFBundleIcons(this PDictionary dict, PDictionary icons)
 {
     if (icons == null)
     {
         dict.Remove(ManifestKeys.CFBundleIcons);
     }
     else
     {
         dict[ManifestKeys.CFBundleIcons] = icons;
     }
 }
Example #7
0
 public static void SetCFBundleIconFiles(this PDictionary dict, PArray array)
 {
     if (array == null)
     {
         dict.Remove(ManifestKeys.CFBundleIconFiles);
     }
     else
     {
         dict[ManifestKeys.CFBundleIconFiles] = array;
     }
 }
Example #8
0
 public static void SetLaunchImageAssets(this PDictionary dict, string vpath)
 {
     if (string.IsNullOrEmpty(vpath))
     {
         dict.Remove(ManifestKeys.XSLaunchImageAssets);
     }
     else
     {
         dict[ManifestKeys.XSLaunchImageAssets] = vpath;
     }
 }
Example #9
0
 public static void SetBooleanOrRemove(this PDictionary dict, string key, bool value)
 {
     if (value)
     {
         dict[key] = new PBoolean(true);
     }
     else
     {
         dict.Remove(key);
     }
 }
Example #10
0
 public static void SetCFBundleIconFile(this PDictionary dict, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         dict.Remove(ManifestKeys.CFBundleIconFile);
     }
     else
     {
         dict[ManifestKeys.CFBundleIconFile] = value;
     }
 }
 public static void SetiCloudServices(this PDictionary dict, PArray value)
 {
     if (value == null)
     {
         dict.Remove(EntitlementKeys.iCloudServices);
     }
     else
     {
         dict[EntitlementKeys.iCloudServices] = value;
     }
 }
 public static void SetAssociatedDomains(this PDictionary dict, PArray value)
 {
     if (value == null)
     {
         dict.Remove(EntitlementKeys.AssociatedDomains);
     }
     else
     {
         dict[EntitlementKeys.AssociatedDomains] = value;
     }
 }
 public static void SetUbiquityKeyValueStore(this PDictionary dict, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         dict.Remove(EntitlementKeys.UbiquityKeyValueStore);
     }
     else
     {
         dict[EntitlementKeys.UbiquityKeyValueStore] = value;
     }
 }
 public static void SetApplicationGroups(this PDictionary dict, PArray value)
 {
     if (value == null)
     {
         dict.Remove(EntitlementKeys.ApplicationGroups);
     }
     else
     {
         dict[EntitlementKeys.ApplicationGroups] = value;
     }
 }
 public static void SetApplePayMerchants(this PDictionary dict, PArray value)
 {
     if (value == null)
     {
         dict.Remove(EntitlementKeys.InAppPayments);
     }
     else
     {
         dict[EntitlementKeys.InAppPayments] = value;
     }
 }
 public static void SetPassBookIdentifiers(this PDictionary dict, PArray value)
 {
     if (value == null)
     {
         dict.Remove(EntitlementKeys.PassBookIdentifiers);
     }
     else
     {
         dict[EntitlementKeys.PassBookIdentifiers] = value;
     }
 }
Example #17
0
        public static void SetUIDeviceFamily(this PDictionary dict, IPhoneDeviceType deviceTypes)
        {
            if (deviceTypes == IPhoneDeviceType.NotSet)
            {
                dict.Remove(ManifestKeys.UIDeviceFamily);
                return;
            }

            PArray arr = new PArray();

            foreach (var family in deviceTypes.ToDeviceFamily())
            {
                arr.Add(new PNumber((int)family));
            }

            dict[ManifestKeys.UIDeviceFamily] = arr;
        }
        bool Compile(PDictionary plist)
        {
            var currentSDK = IPhoneSdks.GetSdk(Framework);

            if (!currentSDK.SdkIsInstalled(sdkVersion, SdkIsSimulator))
            {
                Log.LogError(null, null, null, null, 0, 0, 0, 0, "The {0} SDK for '{1}' is not installed.", Framework, sdkVersion);
                return(false);
            }

            supportedDevices = plist.GetUIDeviceFamily();

            if (!IsWatchApp)
            {
                var version = IPhoneSdks.MonoTouch.ExtendedVersion;
                // This key is our supported way of determining if an app
                // was built with Xamarin, so it needs to be present in all apps.

                var dict = new PDictionary();
                dict.Add("Version", new PString(string.Format("{0} ({1}: {2})", version.Version, version.Branch, version.Hash)));
                plist.Add("com.xamarin.ios", dict);
            }

            var sdkSettings = currentSDK.GetSdkSettings(sdkVersion, SdkIsSimulator);
            var dtSettings  = currentSDK.GetDTSettings();

            SetValue(plist, ManifestKeys.BuildMachineOSBuild, dtSettings.BuildMachineOSBuild);
            // We have an issue here, this is for consideration by the platform:
            // CFLocaleCopyCurrent(), used in the mono code to get the current locale (locale.c line 421), will return the value of the application's CFBundleDevelopmentRegion Info.plist key if all of the following conditions are true:
            //
            // * CFBundleDevelopmentRegion is present in the Info.plist
            // * The CFBundleDevelopmentRegion language is in the list of preferred languages on the iOS device, but isn't the first one
            // * There are no localized resources (i.e. no .lproj directory) in the app for the first preferred locale
            //
            // This differs from iOS 10 where the presence of the CFBundleDevelopmentRegion key had no effect. Commenting this line out, ensures that CurrentCulture is correct and behaves like the iOS 10 version.
            // plist.SetIfNotPresent (ManifestKeys.CFBundleDevelopmentRegion, "en");

            plist.SetIfNotPresent(ManifestKeys.CFBundleExecutable, AssemblyName);
            if (IsIOS)
            {
                var executable = plist.GetCFBundleExecutable();
                if (executable.EndsWith(".app", StringComparison.Ordinal))
                {
                    LogAppManifestError("The executable (CFBundleExecutable) name ({0}) cannot end with '.app', because iOS may fail to launch the app.", executable);
                }
            }

            if (IsIOS)
            {
                if (minimumOSVersion < IPhoneSdkVersion.V5_0 && plist.GetUIMainStoryboardFile(true) != null)
                {
                    LogAppManifestError("Applications using a storyboard as the Main Interface must have a deployment target greater than 5.0");
                }

                if (!plist.ContainsKey(ManifestKeys.CFBundleName))
                {
                    plist [ManifestKeys.CFBundleName] = plist.ContainsKey(ManifestKeys.CFBundleDisplayName) ? plist.GetString(ManifestKeys.CFBundleDisplayName).Clone() : new PString(AppBundleName);
                }
            }
            else
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleName, AppBundleName);
            }

            plist.SetIfNotPresent(ManifestKeys.CFBundleIdentifier, BundleIdentifier);
            plist.SetIfNotPresent(ManifestKeys.CFBundleInfoDictionaryVersion, "6.0");
            plist.SetIfNotPresent(ManifestKeys.CFBundlePackageType, IsAppExtension ? "XPC!" : "APPL");
            if (!string.IsNullOrEmpty(ResourceRules))
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleResourceSpecification, Path.GetFileName(ResourceRules));
            }
            plist.SetIfNotPresent(ManifestKeys.CFBundleSignature, "????");
            if (!plist.ContainsKey(ManifestKeys.CFBundleSupportedPlatforms))
            {
                plist[ManifestKeys.CFBundleSupportedPlatforms] = new PArray {
                    SdkPlatform
                }
            }
            ;
            plist.SetIfNotPresent(ManifestKeys.CFBundleVersion, "1.0");
            plist.SetIfNotPresent(ManifestKeys.CFBundleShortVersionString, plist.GetCFBundleVersion());

            string dtCompiler        = null;
            string dtPlatformBuild   = null;
            string dtSDKBuild        = null;
            string dtPlatformName    = null;
            string dtPlatformVersion = null;
            string dtXcode           = null;
            string dtXcodeBuild      = null;

            if (!SdkIsSimulator)
            {
                dtCompiler      = sdkSettings.DTCompiler;
                dtPlatformBuild = dtSettings.DTPlatformBuild;
                dtSDKBuild      = sdkSettings.DTSDKBuild;
            }

            dtPlatformName = SdkPlatform.ToLowerInvariant();
            if (!SdkIsSimulator)
            {
                dtPlatformVersion = dtSettings.DTPlatformVersion;
            }

            var dtSDKName = sdkSettings.CanonicalName;

            // older sdksettings didn't have a canonicalname for sim
            if (SdkIsSimulator && string.IsNullOrEmpty(dtSDKName))
            {
                var deviceSdkSettings = currentSDK.GetSdkSettings(sdkVersion, false);
                dtSDKName = deviceSdkSettings.AlternateSDK;
            }

            if (!SdkIsSimulator)
            {
                dtXcode      = AppleSdkSettings.DTXcode;
                dtXcodeBuild = dtSettings.DTXcodeBuild;
            }

            if (UseFakeWatchOS4_3Sdk)
            {
                // This is a workaround for https://github.com/xamarin/xamarin-macios/issues/4810
                if (Framework == PlatformFramework.WatchOS)
                {
                    if (dtPlatformBuild != null)
                    {
                        dtPlatformBuild = "15T212";
                    }
                    if (dtPlatformVersion != null)
                    {
                        dtPlatformVersion = "4.3";
                    }
                    if (dtSDKBuild != null)
                    {
                        dtSDKBuild = "15T212";
                    }
                    if (dtSDKName != null)
                    {
                        dtSDKName = "watchos4.3";
                    }
                    if (dtXcode != null)
                    {
                        dtXcode = "0940";
                    }
                    if (dtXcodeBuild != null)
                    {
                        dtXcodeBuild = "9F1027a";
                    }
                }
                else
                {
                    Log.LogWarning("Can only fake the watchOS 4.3 SDK when building for watchOS.");
                }
            }

            SetValueIfNotNull(plist, "DTCompiler", dtCompiler);
            SetValueIfNotNull(plist, "DTPlatformBuild", dtPlatformBuild);
            SetValueIfNotNull(plist, "DTSDKBuild", dtSDKBuild);
            plist.SetIfNotPresent("DTPlatformName", dtPlatformName);
            SetValueIfNotNull(plist, "DTPlatformVersion", dtPlatformVersion);
            SetValue(plist, "DTSDKName", dtSDKName);
            SetValueIfNotNull(plist, "DTXcode", dtXcode);
            SetValueIfNotNull(plist, "DTXcodeBuild", dtXcodeBuild);

            SetDeviceFamily(plist);

            plist.SetIfNotPresent(ManifestKeys.MinimumOSVersion, minimumOSVersion.ToString());

            if (IsWatchExtension)
            {
                // Note: Only watchOS1 Extensions target Xamarin.iOS
                if (Framework == PlatformFramework.iOS)
                {
                    PObject value;

                    if (!plist.TryGetValue(ManifestKeys.UIRequiredDeviceCapabilities, out value))
                    {
                        var capabilities = new PArray();
                        capabilities.Add(new PString("watch-companion"));

                        plist.Add(ManifestKeys.UIRequiredDeviceCapabilities, capabilities);
                    }
                    else if (value is PDictionary)
                    {
                        var capabilities = (PDictionary)value;

                        if (!capabilities.ContainsKey("watch-companion"))
                        {
                            capabilities.Add("watch-companion", new PBoolean(true));
                        }
                    }
                    else
                    {
                        var  capabilities = (PArray)value;
                        bool exists       = false;

                        foreach (var capability in capabilities.OfType <PString> ())
                        {
                            if (capability.Value != "watch-companion")
                            {
                                continue;
                            }

                            exists = true;
                            break;
                        }

                        if (!exists)
                        {
                            capabilities.Add(new PString("watch-companion"));
                        }
                    }
                }

                if (Debug)
                {
                    SetAppTransportSecurity(plist);
                }
            }

            // Remove any Xamarin Studio specific keys
            plist.Remove(ManifestKeys.XSLaunchImageAssets);
            plist.Remove(ManifestKeys.XSAppIconAssets);

            // Merge with any partial plists generated by the Asset Catalog compiler...
            MergePartialPlistTemplates(plist);

            SetRequiredArchitectures(plist);

            if (IsIOS)
            {
                Validation(plist);
            }

            CompiledAppManifest = new TaskItem(Path.Combine(AppBundleDir, "Info.plist"));
            plist.Save(CompiledAppManifest.ItemSpec, true, true);

            return(!Log.HasLoggedErrors);
        }

        void SetValueIfNotNull(PDictionary dict, string key, string value)
        {
            if (value == null)
            {
                return;
            }
            SetValue(dict, key, value);
        }

        void SetRequiredArchitectures(PDictionary plist)
        {
            PObject capabilities;

            if (plist.TryGetValue(ManifestKeys.UIRequiredDeviceCapabilities, out capabilities))
            {
                if (capabilities is PArray)
                {
                    var architectureValues = new HashSet <string> (new[] { "armv6", "armv7", "arm64" });
                    var array = (PArray)capabilities;

                    // Remove any architecture values
                    for (int i = 0; i < array.Count; i++)
                    {
                        var value = array[i] as PString;

                        if (value == null || !architectureValues.Contains(value.Value))
                        {
                            continue;
                        }

                        array.RemoveAt(i);
                    }

                    // If-and-only-if the TargetArchitecture is a single architecture, set it as a required device capability
                    switch (architectures)
                    {
                    case TargetArchitecture.ARM64:
                        array.Add(new PString("arm64"));
                        break;

                    case TargetArchitecture.ARMv7:
                        array.Add(new PString("armv7"));
                        break;
                    }
                }
                else if (capabilities is PDictionary)
                {
                    var dict = (PDictionary)capabilities;

                    switch (architectures)
                    {
                    case TargetArchitecture.ARM64:
                        dict["arm64"] = new PBoolean(true);
                        dict.Remove("armv6");
                        dict.Remove("armv7");
                        break;

                    case TargetArchitecture.ARMv7:
                        dict["armv7"] = new PBoolean(true);
                        dict.Remove("armv6");
                        dict.Remove("arm64");
                        break;

                    default:
                        dict.Remove("armv6");
                        dict.Remove("armv7");
                        dict.Remove("arm64");
                        break;
                    }
                }
            }
            else
            {
                var array = new PArray();

                // If-and-only-if the TargetArchitecture is a single architecture, set it as a required device capability
                switch (architectures)
                {
                case TargetArchitecture.ARM64:
                    array.Add(new PString("arm64"));
                    break;

                case TargetArchitecture.ARMv7:
                    array.Add(new PString("armv7"));
                    break;
                }

                if (array.Count > 0)
                {
                    plist.Add(ManifestKeys.UIRequiredDeviceCapabilities, array);
                }
            }
        }

        void SetDeviceFamily(PDictionary plist)
        {
            switch (Framework)
            {
            case PlatformFramework.iOS:
                SetIOSDeviceFamily(plist);
                break;

            case PlatformFramework.WatchOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                break;

            case PlatformFramework.TVOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.TV);
                break;
            }
        }

        void SetIOSDeviceFamily(PDictionary plist)
        {
            if (IsWatchApp)
            {
                if (SdkIsSimulator)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone | IPhoneDeviceType.Watch);
                }
                else
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                }
            }
            else
            {
                if (!IsAppExtension)
                {
                    plist.SetIfNotPresent(ManifestKeys.LSRequiresIPhoneOS, true);
                }

                if (minimumOSVersion >= IPhoneSdkVersion.V3_2 && supportedDevices == IPhoneDeviceType.NotSet)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone);
                }
            }
        }

        void SetAppTransportSecurity(PDictionary plist)
        {
            // Debugging over http has a couple of gotchas:
            // * We can't use https, because that requires a valid server certificate,
            //   which we can't ensure.
            //   It would also require a hostname for the mac, which it might not have either.
            // * NSAppTransportSecurity/NSExceptionDomains does not allow exceptions based
            //   on IP address (only hostname).
            // * Which means the only way to make sure watchOS allows connections from
            //   the app on device to the mac is to disable App Transport Security altogether.
            // Good news: watchOS 3 will apparently not apply ATS when connecting
            // directly to IP addresses, which means we won't have to do this at all
            // (sometime in the future).

            PDictionary ats;

            if (!plist.TryGetValue(ManifestKeys.NSAppTransportSecurity, out ats))
            {
                plist.Add(ManifestKeys.NSAppTransportSecurity, ats = new PDictionary());
            }

            if (ats.GetBoolean(ManifestKeys.NSAllowsArbitraryLoads))
            {
                Log.LogMessage(MessageImportance.Low, "All http loads are already allowed.");
            }
            else
            {
                Log.LogMessage(MessageImportance.Low, "Allowed arbitrary HTTP loads to support debugging.");
                ats.SetBooleanOrRemove(ManifestKeys.NSAllowsArbitraryLoads, true);
            }
        }

        void Validation(PDictionary plist)
        {
            var supportsIPhone = (supportedDevices & IPhoneDeviceType.IPhone) != 0 ||
                                 supportedDevices == IPhoneDeviceType.NotSet;
            var supportsIPad = (supportedDevices & IPhoneDeviceType.IPad) != 0;

            // Validation...
            if (!IsAppExtension && sdkVersion >= IPhoneSdkVersion.V3_2)
            {
                IPhoneOrientation orientation;

                if (supportsIPhone)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(false);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning("Supported iPhone orientations have not been set");
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning("Supported iPhone orientations are not matched pairs");
                    }
                }

                if (supportsIPad)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(true);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning("Supported iPad orientations have not been set");
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning("Supported iPad orientations are not matched pairs");
                    }
                }
            }
        }
    }
Example #19
0
        bool Compile(PDictionary plist)
        {
            var currentSDK = IPhoneSdks.GetSdk(Framework);

            if (!currentSDK.SdkIsInstalled(sdkVersion, SdkIsSimulator))
            {
                Log.LogError(null, null, null, null, 0, 0, 0, 0, "The {0} SDK for '{1}' is not installed.", Framework, sdkVersion);
                return(false);
            }

            supportedDevices = plist.GetUIDeviceFamily();

            if (!IsWatchApp)
            {
                var version = IPhoneSdks.MonoTouch.ExtendedVersion;
                // This key is our supported way of determining if an app
                // was built with Xamarin, so it needs to be present in all apps.

                var dict = new PDictionary();
                dict.Add("Version", new PString(string.Format("{0} ({1}: {2})", version.Version, version.Branch, version.Hash)));
                plist.Add("com.xamarin.ios", dict);
            }

            var sdkSettings = currentSDK.GetSdkSettings(sdkVersion, SdkIsSimulator);
            var dtSettings  = currentSDK.GetDTSettings();

            SetValue(plist, ManifestKeys.BuildMachineOSBuild, dtSettings.BuildMachineOSBuild);
            plist.SetIfNotPresent(ManifestKeys.CFBundleDevelopmentRegion, "en");

            plist.SetIfNotPresent(ManifestKeys.CFBundleExecutable, AssemblyName);
            if (IsIOS)
            {
                var executable = plist.GetCFBundleExecutable();
                if (executable.EndsWith(".app", StringComparison.Ordinal))
                {
                    LogAppManifestError("The executable (CFBundleExecutable) name ({0}) cannot end with '.app', because iOS may fail to launch the app.", executable);
                }
            }

            if (IsIOS)
            {
                if (minimumOSVersion < IPhoneSdkVersion.V5_0 && plist.GetUIMainStoryboardFile(true) != null)
                {
                    LogAppManifestError("Applications using a storyboard as the Main Interface must have a deployment target greater than 5.0");
                }

                if (!plist.ContainsKey(ManifestKeys.CFBundleName))
                {
                    plist [ManifestKeys.CFBundleName] = plist.ContainsKey(ManifestKeys.CFBundleDisplayName) ? plist.GetString(ManifestKeys.CFBundleDisplayName).Clone() : new PString(AppBundleName);
                }
            }
            else
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleName, AppBundleName);
            }

            plist.SetIfNotPresent(ManifestKeys.CFBundleIdentifier, BundleIdentifier);
            plist.SetIfNotPresent(ManifestKeys.CFBundleInfoDictionaryVersion, "6.0");
            plist.SetIfNotPresent(ManifestKeys.CFBundlePackageType, IsAppExtension ? "XPC!" : "APPL");
            if (!string.IsNullOrEmpty(ResourceRules))
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleResourceSpecification, Path.GetFileName(ResourceRules));
            }
            plist.SetIfNotPresent(ManifestKeys.CFBundleSignature, "????");
            if (!plist.ContainsKey(ManifestKeys.CFBundleSupportedPlatforms))
            {
                plist[ManifestKeys.CFBundleSupportedPlatforms] = new PArray {
                    SdkPlatform
                }
            }
            ;
            plist.SetIfNotPresent(ManifestKeys.CFBundleVersion, "1.0");
            plist.SetIfNotPresent(ManifestKeys.CFBundleShortVersionString, plist.GetCFBundleVersion());

            if (!SdkIsSimulator)
            {
                SetValue(plist, "DTCompiler", sdkSettings.DTCompiler);
                SetValue(plist, "DTPlatformBuild", dtSettings.DTPlatformBuild);
                SetValue(plist, "DTSDKBuild", sdkSettings.DTSDKBuild);
            }

            plist.SetIfNotPresent("DTPlatformName", SdkPlatform.ToLowerInvariant());
            if (!SdkIsSimulator)
            {
                SetValue(plist, "DTPlatformVersion", dtSettings.DTPlatformVersion);
            }

            var sdkName = sdkSettings.CanonicalName;

            // older sdksettings didn't have a canonicalname for sim
            if (SdkIsSimulator && string.IsNullOrEmpty(sdkName))
            {
                var deviceSdkSettings = currentSDK.GetSdkSettings(sdkVersion, false);
                sdkName = deviceSdkSettings.AlternateSDK;
            }
            SetValue(plist, "DTSDKName", sdkName);

            if (!SdkIsSimulator)
            {
                SetValue(plist, "DTXcode", AppleSdkSettings.DTXcode);
                SetValue(plist, "DTXcodeBuild", dtSettings.DTXcodeBuild);
            }

            SetDeviceFamily(plist);

            plist.SetIfNotPresent(ManifestKeys.MinimumOSVersion, minimumOSVersion.ToString());

            // Remove any Xamarin Studio specific keys
            plist.Remove(ManifestKeys.XSLaunchImageAssets);
            plist.Remove(ManifestKeys.XSAppIconAssets);

            // Merge with any partial plists generated by the Asset Catalog compiler...
            MergePartialPlistTemplates(plist);

            if (IsIOS)
            {
                Validation(plist);
            }

            CompiledAppManifest = new TaskItem(Path.Combine(AppBundleDir, "Info.plist"));
            plist.Save(CompiledAppManifest.ItemSpec, true, true);

            return(!Log.HasLoggedErrors);
        }

        void SetDeviceFamily(PDictionary plist)
        {
            switch (Framework)
            {
            case PlatformFramework.iOS:
                SetIOSDeviceFamily(plist);
                break;

            case PlatformFramework.WatchOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                break;

            case PlatformFramework.TVOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.TV);
                break;
            }
        }

        void SetIOSDeviceFamily(PDictionary plist)
        {
            if (IsWatchApp)
            {
                if (SdkIsSimulator)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone | IPhoneDeviceType.Watch);
                }
                else
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                }
            }
            else
            {
                if (!IsAppExtension)
                {
                    plist.SetIfNotPresent(ManifestKeys.LSRequiresIPhoneOS, true);
                }

                if (minimumOSVersion >= IPhoneSdkVersion.V3_2 && supportedDevices == IPhoneDeviceType.NotSet)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone);
                }
            }
        }

        void Validation(PDictionary plist)
        {
            var supportsIPhone = (supportedDevices & IPhoneDeviceType.IPhone) != 0 ||
                                 supportedDevices == IPhoneDeviceType.NotSet;
            var supportsIPad = (supportedDevices & IPhoneDeviceType.IPad) != 0;

            // Validation...
            if (!IsAppExtension && sdkVersion >= IPhoneSdkVersion.V3_2)
            {
                IPhoneOrientation orientation;

                if (supportsIPhone)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(false);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning("Supported iPhone orientations have not been set");
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning("Supported iPhone orientations are not matched pairs");
                    }
                }

                if (supportsIPad)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(true);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning("Supported iPad orientations have not been set");
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning("Supported iPad orientations are not matched pairs");
                    }
                }
            }
        }
    }
Example #20
0
		//-------------------------------------------------------------------------------------
		private void AddSortColumn(DataGridViewColumn col, ListSortDirection direction = ListSortDirection.Ascending)
		{
			if(this.DataSource == null)// || props.ContainsKey(col.DataPropertyName) == false)
				return;
			try
			{
				if(AllowMultipleSort == false)
				{
					if((this.DataSource as IBindingList) == null)
						throw new Exception(String.Format("»сточник данных [{0}] не поддерживает интерфейс IBindingList!",
																																								DataSource.GetType().FullName));
					IBindingList ibl = (IBindingList)this.DataSource;
					if(ibl.SupportsSorting == false)
						return;
					PropertyDescriptor pd = null;
					if(props.ContainsKey(col.DataPropertyName))
						pd = props[col.DataPropertyName];
					else
						pd = new UnboundColumnPropertyDescriptor(col);
					ListSortDirection lsd = direction;
					if(ibl.SortProperty != null && Object.Equals(ibl.SortProperty, pd))
						if(ibl.SortDirection == ListSortDirection.Ascending)
							lsd = ListSortDirection.Descending;
						else
							lsd = ListSortDirection.Ascending;
					ibl.ApplySort(pd, lsd);
					foreach(DataGridViewColumn c in Columns)
						c.HeaderCell.SortGlyphDirection = SortOrder.None;
					if(lsd == ListSortDirection.Ascending)
						col.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
					else
						col.HeaderCell.SortGlyphDirection = SortOrder.Descending;
					SortedColumn = col;
					SortOrder = lsd == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending;
				}
				else
				{
					if((this.DataSource as IBindingListView) == null)
						throw new Exception(String.Format("»сточник данных [{0}] не поддерживает интерфейс IBindingListView!",
																																								DataSource.GetType().FullName));
					if((this.DataSource as ITypedList) == null)
						throw new Exception(String.Format("»сточник данных [{0}] не поддерживает интерфейс ITypedList !",
																																								DataSource.GetType().FullName));
					if(((IBindingListView)DataSource).SupportsAdvancedSorting == false)
						throw new Exception(String.Format("»сточник данных [{0}] не поддерживает сортировку по нескольким столбцам!",
																																								DataSource.GetType().FullName));

					PDictionary<string, ListSortDescription> sl = new PDictionary<string, ListSortDescription>();

					if(((IBindingListView)DataSource).SortDescriptions != null)
						foreach(ListSortDescription lsd in ((IBindingListView)DataSource).SortDescriptions)
							sl.Add(lsd.PropertyDescriptor.Name, lsd);

					List<string> toDel = new List<string>();
					if(ModifierKeys != Keys.Control)
						foreach(string s in sl.Keys)
							if(s != (String.IsNullOrEmpty(col.DataPropertyName) ? col.Name : col.DataPropertyName))
								toDel.Add(s);
					foreach(string s in toDel)
						sl.Remove(s);

					PropertyDescriptor pd = null;
					if(props.ContainsKey(col.DataPropertyName))
						pd = props[col.DataPropertyName];
					else
						pd = new UnboundColumnPropertyDescriptor(col);
					if(sl.ContainsKey(pd.Name))
					{
						if(sl[pd.Name].SortDirection == ListSortDirection.Ascending)
							sl[pd.Name].SortDirection = ListSortDirection.Descending;
						else
							sl[pd.Name].SortDirection = ListSortDirection.Ascending;
					}
					else
						sl.Add(pd.Name, new ListSortDescription(pd, direction));
					SortedColumn = col;
					SortOrder = sl[pd.Name].SortDirection == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending;
					ListSortDescription[] sd = new ListSortDescription[sl.Count];
					int c = 0;
					foreach(var i in sl.Values)
						sd[c++] = i;
					((IBindingListView)DataSource).ApplySort(new ListSortDescriptionCollection(sd));

					DrawMultiSort();

				}
				this.Refresh();
			}
			catch(Exception Err)
			{
				ErrorBox.Show(Err);
			}
		}
        bool Compile(PDictionary plist)
        {
            var currentSDK = IPhoneSdks.GetSdk(Framework);

            if (!currentSDK.SdkIsInstalled(sdkVersion, SdkIsSimulator))
            {
                Log.LogError(null, null, null, null, 0, 0, 0, 0, "The {0} SDK for '{1}' is not installed.", Framework, sdkVersion);
                return(false);
            }

            supportedDevices = plist.GetUIDeviceFamily();

            if (!IsWatchApp)
            {
                var version = IPhoneSdks.MonoTouch.ExtendedVersion;
                // This key is our supported way of determining if an app
                // was built with Xamarin, so it needs to be present in all apps.

                var dict = new PDictionary();
                dict.Add("Version", new PString(string.Format("{0} ({1}: {2})", version.Version, version.Branch, version.Hash)));
                plist.Add("com.xamarin.ios", dict);
            }

            var sdkSettings = currentSDK.GetSdkSettings(sdkVersion, SdkIsSimulator);
            var dtSettings  = currentSDK.GetDTSettings();

            SetValue(plist, ManifestKeys.BuildMachineOSBuild, dtSettings.BuildMachineOSBuild);
            plist.SetIfNotPresent(ManifestKeys.CFBundleDevelopmentRegion, "en");

            plist.SetIfNotPresent(ManifestKeys.CFBundleExecutable, AssemblyName);
            if (IsIOS)
            {
                var executable = plist.GetCFBundleExecutable();
                if (executable.EndsWith(".app", StringComparison.Ordinal))
                {
                    LogAppManifestError("The executable (CFBundleExecutable) name ({0}) cannot end with '.app', because iOS may fail to launch the app.", executable);
                }
            }

            if (IsIOS)
            {
                if (minimumOSVersion < IPhoneSdkVersion.V5_0 && plist.GetUIMainStoryboardFile(true) != null)
                {
                    LogAppManifestError("Applications using a storyboard as the Main Interface must have a deployment target greater than 5.0");
                }

                if (!plist.ContainsKey(ManifestKeys.CFBundleName))
                {
                    plist [ManifestKeys.CFBundleName] = plist.ContainsKey(ManifestKeys.CFBundleDisplayName) ? plist.GetString(ManifestKeys.CFBundleDisplayName).Clone() : new PString(AppBundleName);
                }
            }
            else
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleName, AppBundleName);
            }

            plist.SetIfNotPresent(ManifestKeys.CFBundleIdentifier, BundleIdentifier);
            plist.SetIfNotPresent(ManifestKeys.CFBundleInfoDictionaryVersion, "6.0");
            plist.SetIfNotPresent(ManifestKeys.CFBundlePackageType, IsAppExtension ? "XPC!" : "APPL");
            if (!string.IsNullOrEmpty(ResourceRules))
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleResourceSpecification, Path.GetFileName(ResourceRules));
            }
            plist.SetIfNotPresent(ManifestKeys.CFBundleSignature, "????");
            if (!plist.ContainsKey(ManifestKeys.CFBundleSupportedPlatforms))
            {
                plist[ManifestKeys.CFBundleSupportedPlatforms] = new PArray {
                    SdkPlatform
                }
            }
            ;
            plist.SetIfNotPresent(ManifestKeys.CFBundleVersion, "1.0");
            plist.SetIfNotPresent(ManifestKeys.CFBundleShortVersionString, plist.GetCFBundleVersion());

            if (!SdkIsSimulator)
            {
                SetValue(plist, "DTCompiler", sdkSettings.DTCompiler);
                SetValue(plist, "DTPlatformBuild", dtSettings.DTPlatformBuild);
                SetValue(plist, "DTSDKBuild", sdkSettings.DTSDKBuild);
            }

            plist.SetIfNotPresent("DTPlatformName", SdkPlatform.ToLowerInvariant());
            if (!SdkIsSimulator)
            {
                SetValue(plist, "DTPlatformVersion", dtSettings.DTPlatformVersion);
            }

            var sdkName = sdkSettings.CanonicalName;

            // older sdksettings didn't have a canonicalname for sim
            if (SdkIsSimulator && string.IsNullOrEmpty(sdkName))
            {
                var deviceSdkSettings = currentSDK.GetSdkSettings(sdkVersion, false);
                sdkName = deviceSdkSettings.AlternateSDK;
            }
            SetValue(plist, "DTSDKName", sdkName);

            if (!SdkIsSimulator)
            {
                SetValue(plist, "DTXcode", AppleSdkSettings.DTXcode);
                SetValue(plist, "DTXcodeBuild", dtSettings.DTXcodeBuild);
            }

            SetDeviceFamily(plist);

            plist.SetIfNotPresent(ManifestKeys.MinimumOSVersion, minimumOSVersion.ToString());

            if (IsWatchExtension && Debug)
            {
                SetAppTransportSecurity(plist);
            }

            // Remove any Xamarin Studio specific keys
            plist.Remove(ManifestKeys.XSLaunchImageAssets);
            plist.Remove(ManifestKeys.XSAppIconAssets);

            // Merge with any partial plists generated by the Asset Catalog compiler...
            MergePartialPlistTemplates(plist);

            if (IsIOS)
            {
                Validation(plist);
            }

            CompiledAppManifest = new TaskItem(Path.Combine(AppBundleDir, "Info.plist"));
            plist.Save(CompiledAppManifest.ItemSpec, true, true);

            return(!Log.HasLoggedErrors);
        }

        void SetDeviceFamily(PDictionary plist)
        {
            switch (Framework)
            {
            case PlatformFramework.iOS:
                SetIOSDeviceFamily(plist);
                break;

            case PlatformFramework.WatchOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                break;

            case PlatformFramework.TVOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.TV);
                break;
            }
        }

        void SetIOSDeviceFamily(PDictionary plist)
        {
            if (IsWatchApp)
            {
                if (SdkIsSimulator)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone | IPhoneDeviceType.Watch);
                }
                else
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                }
            }
            else
            {
                if (!IsAppExtension)
                {
                    plist.SetIfNotPresent(ManifestKeys.LSRequiresIPhoneOS, true);
                }

                if (minimumOSVersion >= IPhoneSdkVersion.V3_2 && supportedDevices == IPhoneDeviceType.NotSet)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone);
                }
            }
        }

        void SetAppTransportSecurity(PDictionary plist)
        {
            // Debugging over http has a couple of gotchas:
            // * We can't use https, because that requires a valid server certificate,
            //   which we can't ensure.
            //   It would also require a hostname for the mac, which it might not have either.
            // * NSAppTransportSecurity/NSExceptionDomains does not allow exceptions based
            //   on IP address (only hostname).
            // * Which means the only way to make sure watchOS allows connections from
            //   the app on device to the mac is to disable App Transport Security altogether.
            // Good news: watchOS 3 will apparently not apply ATS when connecting
            // directly to IP addresses, which means we won't have to do this at all
            // (sometime in the future).

            PDictionary ats;

            if (!plist.TryGetValue(ManifestKeys.NSAppTransportSecurity, out ats))
            {
                plist.Add(ManifestKeys.NSAppTransportSecurity, ats = new PDictionary());
            }

            if (ats.GetBoolean(ManifestKeys.NSAllowsArbitraryLoads))
            {
                Log.LogMessage(MessageImportance.Low, "All http loads are already allowed.");
            }
            else
            {
                Log.LogMessage(MessageImportance.Low, "Allowed arbitrary HTTP loads to support debugging.");
                ats.SetBooleanOrRemove(ManifestKeys.NSAllowsArbitraryLoads, true);
            }
        }

        void Validation(PDictionary plist)
        {
            var supportsIPhone = (supportedDevices & IPhoneDeviceType.IPhone) != 0 ||
                                 supportedDevices == IPhoneDeviceType.NotSet;
            var supportsIPad = (supportedDevices & IPhoneDeviceType.IPad) != 0;

            // Validation...
            if (!IsAppExtension && sdkVersion >= IPhoneSdkVersion.V3_2)
            {
                IPhoneOrientation orientation;

                if (supportsIPhone)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(false);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning("Supported iPhone orientations have not been set");
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning("Supported iPhone orientations are not matched pairs");
                    }
                }

                if (supportsIPad)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(true);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning("Supported iPad orientations have not been set");
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning("Supported iPad orientations are not matched pairs");
                    }
                }
            }
        }
    }
Example #22
0
        bool Compile(PDictionary plist)
        {
            var currentSDK = IPhoneSdks.GetSdk (Framework);

            if (!currentSDK.SdkIsInstalled (sdkVersion, SdkIsSimulator)) {
                Log.LogError (null, null, null, null, 0, 0, 0, 0, "The {0} SDK for '{1}' is not installed.", Framework, sdkVersion);
                return false;
            }

            supportedDevices = plist.GetUIDeviceFamily ();

            if (!IsWatchApp) {
                var version = IPhoneSdks.MonoTouch.ExtendedVersion;
                // This key is our supported way of determining if an app
                // was built with Xamarin, so it needs to be present in all apps.

                var dict = new PDictionary ();
                dict.Add ("Version", new PString (string.Format ("{0} ({1}: {2})", version.Version, version.Branch, version.Hash)));
                plist.Add ("com.xamarin.ios", dict);
            }

            var sdkSettings = currentSDK.GetSdkSettings (sdkVersion, SdkIsSimulator);
            var dtSettings = currentSDK.GetDTSettings ();

            SetValue (plist, ManifestKeys.BuildMachineOSBuild, dtSettings.BuildMachineOSBuild);
            plist.SetIfNotPresent (ManifestKeys.CFBundleDevelopmentRegion, "en");

            plist.SetIfNotPresent (ManifestKeys.CFBundleExecutable, AssemblyName);
            if (IsIOS) {
                var executable = plist.GetCFBundleExecutable ();
                if (executable.EndsWith (".app", StringComparison.Ordinal))
                    LogAppManifestError ("The executable (CFBundleExecutable) name ({0}) cannot end with '.app', because iOS may fail to launch the app.", executable);
            }

            if (IsIOS) {
                if (minimumOSVersion < IPhoneSdkVersion.V5_0 && plist.GetUIMainStoryboardFile (true) != null)
                    LogAppManifestError ("Applications using a storyboard as the Main Interface must have a deployment target greater than 5.0");

                if (!plist.ContainsKey (ManifestKeys.CFBundleName))
                    plist [ManifestKeys.CFBundleName] = plist.ContainsKey (ManifestKeys.CFBundleDisplayName) ? plist.GetString (ManifestKeys.CFBundleDisplayName).Clone () : new PString (AppBundleName);
            } else {
                plist.SetIfNotPresent (ManifestKeys.CFBundleName, AppBundleName);
            }

            plist.SetIfNotPresent (ManifestKeys.CFBundleIdentifier, BundleIdentifier);
            plist.SetIfNotPresent (ManifestKeys.CFBundleInfoDictionaryVersion, "6.0");
            plist.SetIfNotPresent (ManifestKeys.CFBundlePackageType, IsAppExtension ? "XPC!" : "APPL");
            if (!string.IsNullOrEmpty (ResourceRules))
                plist.SetIfNotPresent (ManifestKeys.CFBundleResourceSpecification, Path.GetFileName (ResourceRules));
            plist.SetIfNotPresent (ManifestKeys.CFBundleSignature, "????");
            if (!plist.ContainsKey (ManifestKeys.CFBundleSupportedPlatforms))
                plist[ManifestKeys.CFBundleSupportedPlatforms] = new PArray { SdkPlatform };
            plist.SetIfNotPresent (ManifestKeys.CFBundleVersion, "1.0");

            if (!SdkIsSimulator) {
                SetValue (plist, "DTCompiler", sdkSettings.DTCompiler);
                SetValue (plist, "DTPlatformBuild", dtSettings.DTPlatformBuild);
                SetValue (plist, "DTSDKBuild", sdkSettings.DTSDKBuild);
            }

            plist.SetIfNotPresent ("DTPlatformName", SdkPlatform.ToLowerInvariant ());
            if (!SdkIsSimulator)
                SetValue (plist, "DTPlatformVersion", dtSettings.DTPlatformVersion);

            var sdkName = sdkSettings.CanonicalName;
            // older sdksettings didn't have a canonicalname for sim
            if (SdkIsSimulator && string.IsNullOrEmpty (sdkName)) {
                var deviceSdkSettings = currentSDK.GetSdkSettings (sdkVersion, false);
                sdkName = deviceSdkSettings.AlternateSDK;
            }
            SetValue (plist, "DTSDKName", sdkName);

            if (!SdkIsSimulator) {
                SetValue (plist, "DTXcode", AppleSdkSettings.DTXcode);
                SetValue (plist, "DTXcodeBuild", dtSettings.DTXcodeBuild);
            }

            SetDeviceFamily (plist);

            if (IsWatchExtension) {
                PObject capabilities;

                if (!plist.TryGetValue (ManifestKeys.UIRequiredDeviceCapabilities, out capabilities))
                    plist[ManifestKeys.UIRequiredDeviceCapabilities] = capabilities = new PArray ();
            }

            plist.SetIfNotPresent (ManifestKeys.MinimumOSVersion, minimumOSVersion.ToString ());

            // Remove any Xamarin Studio specific keys
            plist.Remove (ManifestKeys.XSLaunchImageAssets);
            plist.Remove (ManifestKeys.XSAppIconAssets);

            // Merge with any partial plists generated by the Asset Catalog compiler...
            MergePartialPlistTemplates (plist);

            if (IsIOS)
                Validation (plist);

            CompiledAppManifest = new TaskItem (Path.Combine (AppBundleDir, "Info.plist"));
            plist.Save (CompiledAppManifest.ItemSpec, true, true);

            return !Log.HasLoggedErrors;
        }
Example #23
0
        protected override bool Compile(PDictionary plist)
        {
            var currentSDK = Sdks.GetAppleSdk(Platform);

            sdkVersion = IPhoneSdkVersion.Parse(DefaultSdkVersion);
            if (!currentSDK.SdkIsInstalled(sdkVersion, SdkIsSimulator))
            {
                Log.LogError(null, null, null, null, 0, 0, 0, 0, MSBStrings.E0013, Platform, sdkVersion);
                return(false);
            }

            supportedDevices = plist.GetUIDeviceFamily();

            if (!IsWatchApp)
            {
                var version = Sdks.XamIOS.ExtendedVersion;
                // This key is our supported way of determining if an app
                // was built with Xamarin, so it needs to be present in all apps.

                var dict = new PDictionary();
                dict.Add("Version", new PString(string.Format("{0} ({1}: {2})", version.Version, version.Branch, version.Hash)));
                plist.Add("com.xamarin.ios", dict);
            }

            var sdkSettings = currentSDK.GetSdkSettings(sdkVersion, SdkIsSimulator);
            var dtSettings  = currentSDK.GetAppleDTSettings();

            SetValue(plist, ManifestKeys.BuildMachineOSBuild, dtSettings.BuildMachineOSBuild);
            // We have an issue here, this is for consideration by the platform:
            // CFLocaleCopyCurrent(), used in the mono code to get the current locale (locale.c line 421), will return the value of the application's CFBundleDevelopmentRegion Info.plist key if all of the following conditions are true:
            //
            // * CFBundleDevelopmentRegion is present in the Info.plist
            // * The CFBundleDevelopmentRegion language is in the list of preferred languages on the iOS device, but isn't the first one
            // * There are no localized resources (i.e. no .lproj directory) in the app for the first preferred locale
            //
            // This differs from iOS 10 where the presence of the CFBundleDevelopmentRegion key had no effect. Commenting this line out, ensures that CurrentCulture is correct and behaves like the iOS 10 version.
            // plist.SetIfNotPresent (ManifestKeys.CFBundleDevelopmentRegion, "en");

            if (IsIOS)
            {
                var executable = plist.GetCFBundleExecutable();
                if (executable.EndsWith(".app", StringComparison.Ordinal))
                {
                    LogAppManifestError(MSBStrings.E0014, executable);
                }
            }

            if (IsIOS)
            {
                if (!plist.ContainsKey(ManifestKeys.CFBundleName))
                {
                    plist [ManifestKeys.CFBundleName] = plist.ContainsKey(ManifestKeys.CFBundleDisplayName) ? plist.GetString(ManifestKeys.CFBundleDisplayName).Clone() : new PString(AppBundleName);
                }
            }
            else
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleName, AppBundleName);
            }

            if (!string.IsNullOrEmpty(ResourceRules))
            {
                plist.SetIfNotPresent(ManifestKeys.CFBundleResourceSpecification, Path.GetFileName(ResourceRules));
            }
            if (!plist.ContainsKey(ManifestKeys.CFBundleSupportedPlatforms))
            {
                plist[ManifestKeys.CFBundleSupportedPlatforms] = new PArray {
                    SdkPlatform
                }
            }
            ;
            plist.SetIfNotPresent(ManifestKeys.CFBundleShortVersionString, plist.GetCFBundleVersion());

            string dtCompiler        = null;
            string dtPlatformBuild   = null;
            string dtSDKBuild        = null;
            string dtPlatformName    = null;
            string dtPlatformVersion = null;
            string dtXcode           = null;
            string dtXcodeBuild      = null;

            if (!SdkIsSimulator)
            {
                dtCompiler      = sdkSettings.DTCompiler;
                dtPlatformBuild = dtSettings.DTPlatformBuild;
                dtSDKBuild      = sdkSettings.DTSDKBuild;
            }

            dtPlatformName = SdkPlatform.ToLowerInvariant();
            if (!SdkIsSimulator)
            {
                dtPlatformVersion = dtSettings.DTPlatformVersion;
            }

            var dtSDKName = sdkSettings.CanonicalName;

            // older sdksettings didn't have a canonicalname for sim
            if (SdkIsSimulator && string.IsNullOrEmpty(dtSDKName))
            {
                var deviceSdkSettings = currentSDK.GetSdkSettings(sdkVersion, false);
                dtSDKName = deviceSdkSettings.AlternateSDK;
            }

            if (!SdkIsSimulator)
            {
                dtXcode      = AppleSdkSettings.DTXcode;
                dtXcodeBuild = dtSettings.DTXcodeBuild;
            }

            SetValueIfNotNull(plist, "DTCompiler", dtCompiler);
            SetValueIfNotNull(plist, "DTPlatformBuild", dtPlatformBuild);
            SetValueIfNotNull(plist, "DTSDKBuild", dtSDKBuild);
            plist.SetIfNotPresent("DTPlatformName", dtPlatformName);
            SetValueIfNotNull(plist, "DTPlatformVersion", dtPlatformVersion);
            SetValue(plist, "DTSDKName", dtSDKName);
            SetValueIfNotNull(plist, "DTXcode", dtXcode);
            SetValueIfNotNull(plist, "DTXcodeBuild", dtXcodeBuild);

            SetDeviceFamily(plist);

            if (IsWatchExtension)
            {
                // Note: Only watchOS1 Extensions target Xamarin.iOS
                if (Platform == ApplePlatform.iOS)
                {
                    PObject value;

                    if (!plist.TryGetValue(ManifestKeys.UIRequiredDeviceCapabilities, out value))
                    {
                        var capabilities = new PArray();
                        capabilities.Add(new PString("watch-companion"));

                        plist.Add(ManifestKeys.UIRequiredDeviceCapabilities, capabilities);
                    }
                    else if (value is PDictionary)
                    {
                        var capabilities = (PDictionary)value;

                        if (!capabilities.ContainsKey("watch-companion"))
                        {
                            capabilities.Add("watch-companion", new PBoolean(true));
                        }
                    }
                    else
                    {
                        var  capabilities = (PArray)value;
                        bool exists       = false;

                        foreach (var capability in capabilities.OfType <PString> ())
                        {
                            if (capability.Value != "watch-companion")
                            {
                                continue;
                            }

                            exists = true;
                            break;
                        }

                        if (!exists)
                        {
                            capabilities.Add(new PString("watch-companion"));
                        }
                    }
                }

                if (Debug)
                {
                    SetAppTransportSecurity(plist);
                }
            }

            // Remove any Xamarin Studio specific keys
            plist.Remove(ManifestKeys.XSLaunchImageAssets);
            plist.Remove(ManifestKeys.XSAppIconAssets);

            SetRequiredArchitectures(plist);

            if (IsIOS)
            {
                Validation(plist);
            }

            return(!Log.HasLoggedErrors);
        }

        void SetValueIfNotNull(PDictionary dict, string key, string value)
        {
            if (value == null)
            {
                return;
            }
            SetValue(dict, key, value);
        }

        void SetRequiredArchitectures(PDictionary plist)
        {
            PObject capabilities;

            if (plist.TryGetValue(ManifestKeys.UIRequiredDeviceCapabilities, out capabilities))
            {
                if (capabilities is PArray)
                {
                    var architectureValues = new HashSet <string> (new[] { "armv6", "armv7", "arm64" });
                    var array = (PArray)capabilities;

                    // Remove any architecture values
                    for (int i = 0; i < array.Count; i++)
                    {
                        var value = array[i] as PString;

                        if (value == null || !architectureValues.Contains(value.Value))
                        {
                            continue;
                        }

                        array.RemoveAt(i);
                    }

                    // If-and-only-if the TargetArchitecture is a single architecture, set it as a required device capability
                    switch (architectures)
                    {
                    case TargetArchitecture.ARM64:
                        array.Add(new PString("arm64"));
                        break;

                    case TargetArchitecture.ARMv7:
                        array.Add(new PString("armv7"));
                        break;
                    }
                }
                else if (capabilities is PDictionary)
                {
                    var dict = (PDictionary)capabilities;

                    switch (architectures)
                    {
                    case TargetArchitecture.ARM64:
                        dict["arm64"] = new PBoolean(true);
                        dict.Remove("armv6");
                        dict.Remove("armv7");
                        break;

                    case TargetArchitecture.ARMv7:
                        dict["armv7"] = new PBoolean(true);
                        dict.Remove("armv6");
                        dict.Remove("arm64");
                        break;

                    default:
                        dict.Remove("armv6");
                        dict.Remove("armv7");
                        dict.Remove("arm64");
                        break;
                    }
                }
            }
            else
            {
                var array = new PArray();

                // If-and-only-if the TargetArchitecture is a single architecture, set it as a required device capability
                switch (architectures)
                {
                case TargetArchitecture.ARM64:
                    array.Add(new PString("arm64"));
                    break;

                case TargetArchitecture.ARMv7:
                    array.Add(new PString("armv7"));
                    break;
                }

                if (array.Count > 0)
                {
                    plist.Add(ManifestKeys.UIRequiredDeviceCapabilities, array);
                }
            }
        }

        void SetDeviceFamily(PDictionary plist)
        {
            switch (Platform)
            {
            case ApplePlatform.iOS:
                SetIOSDeviceFamily(plist);
                break;

            case ApplePlatform.WatchOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                break;

            case ApplePlatform.TVOS:
                plist.SetUIDeviceFamily(IPhoneDeviceType.TV);
                break;
            }
        }

        void SetIOSDeviceFamily(PDictionary plist)
        {
            if (IsWatchApp)
            {
                if (SdkIsSimulator)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone | IPhoneDeviceType.Watch);
                }
                else
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.Watch);
                }
            }
            else
            {
                if (!IsAppExtension)
                {
                    plist.SetIfNotPresent(ManifestKeys.LSRequiresIPhoneOS, true);
                }

                if (supportedDevices == IPhoneDeviceType.NotSet)
                {
                    plist.SetUIDeviceFamily(IPhoneDeviceType.IPhone);
                }
            }
        }

        void SetAppTransportSecurity(PDictionary plist)
        {
            // Debugging over http has a couple of gotchas:
            // * We can't use https, because that requires a valid server certificate,
            //   which we can't ensure.
            //   It would also require a hostname for the mac, which it might not have either.
            // * NSAppTransportSecurity/NSExceptionDomains does not allow exceptions based
            //   on IP address (only hostname).
            // * Which means the only way to make sure watchOS allows connections from
            //   the app on device to the mac is to disable App Transport Security altogether.
            // Good news: watchOS 3 will apparently not apply ATS when connecting
            // directly to IP addresses, which means we won't have to do this at all
            // (sometime in the future).

            PDictionary ats;

            if (!plist.TryGetValue(ManifestKeys.NSAppTransportSecurity, out ats))
            {
                plist.Add(ManifestKeys.NSAppTransportSecurity, ats = new PDictionary());
            }

            if (ats.GetBoolean(ManifestKeys.NSAllowsArbitraryLoads))
            {
                Log.LogMessage(MessageImportance.Low, MSBStrings.M0017);
            }
            else
            {
                Log.LogMessage(MessageImportance.Low, MSBStrings.M0018);
                ats.SetBooleanOrRemove(ManifestKeys.NSAllowsArbitraryLoads, true);
            }
        }

        void Validation(PDictionary plist)
        {
            var supportsIPhone = (supportedDevices & IPhoneDeviceType.IPhone) != 0 ||
                                 supportedDevices == IPhoneDeviceType.NotSet;
            var supportsIPad = (supportedDevices & IPhoneDeviceType.IPad) != 0;

            // Validation...
            if (!IsAppExtension && sdkVersion >= IPhoneSdkVersion.V3_2)
            {
                IPhoneOrientation orientation;

                if (supportsIPhone)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(false);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning(MSBStrings.W0019);
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning(MSBStrings.W0020);
                    }
                }

                if (supportsIPad)
                {
                    orientation = plist.GetUISupportedInterfaceOrientations(true);
                    if (orientation == IPhoneOrientation.None)
                    {
                        LogAppManifestWarning(MSBStrings.W0021);
                    }
                    else if (!orientation.IsValidPair())
                    {
                        LogAppManifestWarning(MSBStrings.W0022);
                    }
                }
            }
        }
    }