Exemple #1
0
        protected override IEnumerable<string> GetTargetDevices(PDictionary plist)
        {
            var devices = IPhoneDeviceType.NotSet;
            bool watch = false;

            if (plist != null) {
                if (!(watch = plist.GetWKWatchKitApp ())) {
                    // the project is either a normal iOS project or an extension
                    if ((devices = plist.GetUIDeviceFamily ()) == IPhoneDeviceType.NotSet) {
                        // library projects and extension projects will not have this key, but
                        // we'll want them to work for both iPhones and iPads if the
                        // xib or storyboard supports them
                        devices = IPhoneDeviceType.IPhoneAndIPad;
                    }

                    // if the project is a watch extension, we'll also want to incldue watch support
                    watch = IsWatchExtension (plist);
                } else {
                    // the project is a WatchApp, only include watch support
                }
            } else {
                devices = IPhoneDeviceType.IPhoneAndIPad;
            }

            if ((devices & IPhoneDeviceType.IPhone) != 0)
                yield return "iphone";

            if ((devices & IPhoneDeviceType.IPad) != 0)
                yield return "ipad";

            if (watch)
                yield return "watch";

            yield break;
        }
		public override void Load (string fileName)
		{
			ContentName = fileName;

			if (pobject == null) {
				var dict = new PDictionary ();
				if (dict.Reload (fileName)) {
					pobject = dict;
				} else {
					var arr = new PArray ();
					if (!arr.Reload (fileName)) {
						MessageService.ShowError (GettextCatalog.GetString ("Can't load plist file {0}.", fileName));
						return;
					}
					pobject = arr;
				}
				
				Buffer = null;
				widget.SetPListContainer (pobject);
				pobject.Changed += (sender, e) => {
					Buffer = null;
					IsDirty = true;
				};
			}
			this.IsDirty = false;
		}
		public PListEditorWidget (IPlistEditingHandler handler, Project proj, PDictionary plist)
		{
			var summaryScrolledWindow = new PListEditorSection ();
			AppendPage (summaryScrolledWindow, new Label (GettextCatalog.GetString ("Summary")));
			
			var advancedScrolledWindow = new PListEditorSection ();
			AppendPage (advancedScrolledWindow, new Label (GettextCatalog.GetString ("Advanced")));
			
			foreach (var section in handler.GetSections (proj, plist)) {
				var expander = new MacExpander () {
					ContentLabel = section.Name,
					Expandable = true,
				};
				expander.SetWidget (section.Widget);
				
				if (section.IsAdvanced) {
					advancedScrolledWindow.AddExpander (expander);
				} else {
					summaryScrolledWindow.AddExpander (expander);
				}
				
				if (section.CheckVisible != null) {
					expander.Visible = section.CheckVisible (plist);
					//capture section for closure
					var s = section;
					plist.Changed += delegate {
						expander.Visible = s.CheckVisible (plist);
					};
				}
			}
			Show ();
		}
Exemple #4
0
        public override bool Execute()
        {
            PDictionary metadata;

            Log.LogTaskName ("CompileITunesMetadata");
            Log.LogTaskProperty ("AppBundleDir", AppBundleDir);
            Log.LogTaskProperty ("ITunesMetadata", ITunesMetadata);
            Log.LogTaskProperty ("OutputPath", OutputPath);

            if (ITunesMetadata != null) {
                if (ITunesMetadata.Length > 1) {
                    Log.LogError ("Cannot have more than 1 iTunesMetadata.plist.");
                    return false;
                }

                var path = ITunesMetadata[0].GetMetadata ("FullPath");

                try {
                    metadata = PDictionary.FromFile (path);
                } catch (Exception ex) {
                    Log.LogError (null, null, null, path, 0, 0, 0, 0, "Error loading '{0}': {1}", path, ex.Message);
                    return false;
                }
            } else {
                var manifest = Path.Combine (AppBundleDir, "Info.plist");
                PDictionary plist;

                try {
                    plist = PDictionary.FromFile (manifest);
                } catch (Exception ex) {
                    Log.LogError (null, null, null, manifest, 0, 0, 0, 0, "Error loading '{0}': {1}", manifest, ex.Message);
                    return false;
                }

                var displayName = plist.GetCFBundleDisplayName ();
                var bundleVersion = plist.GetCFBundleVersion ();

                metadata = new PDictionary ();

                metadata.Add ("genre", new PString ("Application"));
                if (bundleVersion != null)
                    metadata.Add ("bundleVersion", (PString) bundleVersion);
                if (displayName != null)
                    metadata.Add ("itemName", (PString) displayName);
                metadata.Add ("kind", (PString) "software");
                if (displayName != null)
                    metadata.Add ("playlistName", (PString) displayName);
                metadata.Add ("softwareIconNeedsShine", (PBoolean) true);
                metadata.Add ("softwareVersionBundleId", (PString) plist.GetCFBundleIdentifier ());
            }

            Directory.CreateDirectory (Path.GetDirectoryName (OutputPath.ItemSpec));
            metadata.Save (OutputPath.ItemSpec, true);

            return !Log.HasLoggedErrors;
        }
Exemple #5
0
        protected override PDictionary GetCompiledEntitlements(MobileProvision profile, PDictionary template)
        {
            var entitlements = base.GetCompiledEntitlements (profile, template);
            PBoolean sandbox;

            if (Debug && entitlements.TryGetValue ("com.apple.security.app-sandbox", out sandbox) && sandbox.Value)
                entitlements["com.apple.security.network.client"] = new PBoolean (true);

            return entitlements;
        }
Exemple #6
0
        static bool IsWatchExtension(PDictionary plist)
        {
            PDictionary extension;
            PString id;

            if (!plist.TryGetValue ("NSExtension", out extension))
                return false;

            if (!extension.TryGetValue ("NSExtensionPointIdentifier", out id))
                return false;

            return id.Value == "com.apple.watchkit";
        }
Exemple #7
0
        protected void MergePartialPlistDictionary(PDictionary plist, PDictionary partial)
        {
            foreach (var property in partial) {
                if (plist.ContainsKey (property.Key)) {
                    var value = plist[property.Key];

                    if (value is PDictionary && property.Value is PDictionary) {
                        MergePartialPlistDictionary ((PDictionary) value, (PDictionary) property.Value);
                    } else {
                        plist[property.Key] = property.Value.Clone ();
                    }
                } else {
                    plist[property.Key] = property.Value.Clone ();
                }
            }
        }
Exemple #8
0
			public PObject Create ()
			{
				if (Type == PDictionary.Type) {
					var dictionary = new PDictionary ();
					foreach (var v in Values) {
						if (v.Required)
							dictionary.Add (v.Identifier, v.Create ());
					}
					
					// If nothing was required, create an initial one anyway
					if (dictionary.Count == 0) {
						var first = Values.FirstOrDefault ();
						if (first == null) {
							dictionary.Add ("newNode", PObject.Create (PString.Type));
						} else {
							dictionary.Add (first.Identifier ?? "newNode", first.Create ());
						}
					}
					return dictionary;
				} else if (Type == PArray.Type) {
					var array = new PArray ();
					foreach (var v in Values) {
						if (v.Required)
							array.Add (v.Create ());
					}
					
					// If nothing was required, create an initial one anyway
					if (array.Count == 0) {
						var first = Values.FirstOrDefault ();
						if (first == null) {
							array.Add (PObject.Create (ArrayType));
						} else {
							array.Add (first.Create ());
						}
					}
					return array;
				} else if (Values.Any ()){
					return Values.First ().Create ();
				} else {
					var obj = PObject.Create (Type);
					if (!string.IsNullOrEmpty (Identifier) && !(this is Key))
						obj.SetValue (Identifier);
					return obj;
				}
			}
Exemple #9
0
        public override void Setup()
        {
            base.Setup ();

            var extensionName = "MyActionExtension";
            BuildExtension ("MyTabbedApplication", extensionName, "iPhoneSimulator");

            task = CreateTask<ValidateAppBundleTask> ();
            task.AppBundlePath = AppBundlePath;
            task.SdkIsSimulator = true;
            task.TargetFrameworkIdentifier = "Xamarin.iOS";

            extensionBundlePath = Path.Combine (AppBundlePath, "PlugIns", extensionName + ".appex");

            mainAppPlistPath = Path.Combine (AppBundlePath, "Info.plist");
            extensionPlistPath = Path.Combine (extensionBundlePath, "Info.plist");

            sourcePlist = PDictionary.FromFile (mainAppPlistPath);
        }
Exemple #10
0
        public override bool Execute()
        {
            var manifestPath = Path.Combine (AppBundleDir.ItemSpec, "AssetPackManifestTemplate.plist");
            var onDemandResourcesPath = Path.Combine (AppBundleDir.ItemSpec, "OnDemandResources.plist");
            var onDemandResourcesDir = Path.Combine (OutputPath, "OnDemandResources");
            var onDemandResourcesStamp = File.GetLastWriteTime (onDemandResourcesPath);
            var initialInstallTags = new HashSet<string> (AssetPackUtils.ParseTags (InitialInstallTags));
            var prefetchOrder = AssetPackUtils.ParseTags (PrefetchOrder);
            var manifestStamp = File.GetLastWriteTime (manifestPath);
            var onDemandResources = new PDictionary ();
            var requestTags = new PDictionary ();
            bool updateOnDemandResources = false;
            var assetPacks = new PDictionary ();
            var manifest = new PDictionary ();
            var resources = new PArray ();
            bool updateManifest = false;

            Log.LogTaskName ("CreateAssetPackManifest");
            Log.LogTaskProperty ("AppBundleDir", AppBundleDir);
            Log.LogTaskProperty ("InitialInstallTags", InitialInstallTags);
            Log.LogTaskProperty ("OutputPath", OutputPath);
            Log.LogTaskProperty ("PrefetchOrder", PrefetchOrder);

            if (!Directory.Exists (onDemandResourcesDir))
                return !Log.HasLoggedErrors;

            onDemandResources.Add ("NSBundleResourceRequestAssetPacks", assetPacks);
            onDemandResources.Add ("NSBundleResourceRequestTags", requestTags);

            manifest.Add ("resources", resources);

            foreach (var dir in Directory.EnumerateDirectories (onDemandResourcesDir)) {
                var path = Path.Combine (dir, "Info.plist");
                PDictionary info;

                if (!File.Exists (path))
                    continue;

                var mtime = File.GetLastWriteTime (path);

                updateOnDemandResources = updateOnDemandResources || mtime > onDemandResourcesStamp;
                updateManifest = updateManifest || mtime > manifestStamp;

                try {
                    info = PDictionary.FromFile (path);
                } catch {
                    continue;
                }

                var bundleIdentifier = info.GetCFBundleIdentifier ();
                var primaryContentHash = new PDictionary ();
                var resource = new PDictionary ();
                var items = new PArray ();
                long size = 0;

                // update OnDemandResources.plist:NSBundleResourceRequestAssetPacks
                foreach (var file in Directory.EnumerateFiles (dir)) {
                    var name = Path.GetFileName (file);

                    if (name != "Info.plist")
                        items.Add (new PString (name));

                    size += new FileInfo (file).Length;
                }

                assetPacks.Add (bundleIdentifier, items);

                // update OnDemandResources.plist:NSBundleResourceRequestTags
                var tags = info.GetArray ("Tags").OfType<PString> ().Select (x => x.Value);
                var priority = double.NaN;

                foreach (var tag in tags) {
                    PDictionary dict;
                    PArray packs;

                    if (initialInstallTags.Contains (tag)) {
                        priority = 1.0f;
                    } else {
                        for (int i = 0; i < prefetchOrder.Length; i++) {
                            if (tag == prefetchOrder[i]) {
                                var value = GetDownloadPriority (i, prefetchOrder.Length);

                                priority = double.IsNaN (priority) ? value : Math.Max (priority, value);
                                break;
                            }
                        }
                    }

                    if (!requestTags.TryGetValue (tag, out dict)) {
                        dict = new PDictionary ();
                        dict.Add ("NSAssetPacks", new PArray ());

                        requestTags.Add (tag, dict);
                    }

                    packs = dict.GetArray ("NSAssetPacks");

                    packs.Add (new PString (bundleIdentifier));
                }

                // update AssetPackManifestTemplate.plist
                resource.Add ("URL", new PString ("http://127.0.0.1" + Path.GetFullPath (dir)));
                resource.Add ("bundleKey", new PString (bundleIdentifier));

                if (!double.IsNaN (priority))
                    resource.Add ("downloadPriority", new PReal (priority));

                resource.Add ("isStreamable", new PBoolean (true));
                primaryContentHash.Add ("hash", mtime.ToString ("yyyy-MM-dd HH:mm:ss.000"));
                primaryContentHash.Add ("strategy", "modtime");
                resource.Add ("primaryContentHash", primaryContentHash);
                resource.Add ("uncompressedSize", new PNumber ((int) ((size + 8191) & ~8191)));

                resources.Add (resource);
            }

            if (updateOnDemandResources) {
                try {
                    onDemandResources.Save (onDemandResourcesPath, true, true);
                } catch (Exception ex) {
                    Log.LogError ("Error saving `{0}': {1}", onDemandResourcesPath, ex.Message);
                }
            }

            if (updateManifest) {
                try {
                    manifest.Save (manifestPath, true, true);
                } catch (Exception ex) {
                    Log.LogError ("Error saving `{0}': {1}", manifestPath, ex.Message);
                }
            }

            return !Log.HasLoggedErrors;
        }
Exemple #11
0
        public override bool Execute()
        {
            Log.LogTaskName("Archive");
            Log.LogTaskProperty("AppBundleDir", AppBundleDir);
            Log.LogTaskProperty("AppExtensionReferences", AppExtensionReferences);
            Log.LogTaskProperty("ITunesSourceFiles", ITunesSourceFiles);
            Log.LogTaskProperty("OutputPath", OutputPath);
            Log.LogTaskProperty("ProjectName", ProjectName);
            Log.LogTaskProperty("SigningKey", SigningKey);
            Log.LogTaskProperty("SolutionPath", SolutionPath);

            var archiveDir = CreateArchiveDirectory();

            try {
                var plist       = PDictionary.FromFile(Path.Combine(AppBundleDir.ItemSpec, "Info.plist"));
                var productsDir = Path.Combine(archiveDir, "Products");

                // Archive the OnDemandResources...
                var resourcesDestDir = Path.Combine(productsDir, "OnDemandResources");
                var resourcesSrcDir  = Path.Combine(OutputPath, "OnDemandResources");

                if (Directory.Exists(resourcesSrcDir))
                {
                    Ditto(resourcesSrcDir, resourcesDestDir);
                }

                // Archive the Applications...
                var appDestDir = Path.Combine(productsDir, "Applications", Path.GetFileName(AppBundleDir.ItemSpec));
                Ditto(AppBundleDir.ItemSpec, appDestDir);

                // Archive the dSYMs...
                var dsymsDestDir = Path.Combine(archiveDir, "dSYMs", Path.GetFileName(DSYMDir));
                Ditto(DSYMDir, dsymsDestDir);

                // Archive the Bitcode symbol maps
                var bcSymbolMaps = Directory.GetFiles(Path.GetDirectoryName(DSYMDir), "*.bcsymbolmap");
                if (bcSymbolMaps.Length > 0)
                {
                    var bcSymbolMapsDir = Path.Combine(archiveDir, "BCSymbolMaps");

                    Directory.CreateDirectory(bcSymbolMapsDir);

                    for (int i = 0; i < bcSymbolMaps.Length; i++)
                    {
                        File.Copy(bcSymbolMaps[i], Path.Combine(bcSymbolMapsDir, Path.GetFileName(bcSymbolMaps[i])));
                    }
                }

                if (AppExtensionReferences != null)
                {
                    // Archive the dSYMs for each of the referenced App Extensions as well...
                    for (int i = 0; i < AppExtensionReferences.Length; i++)
                    {
                        ArchiveAppExtension(AppExtensionReferences[i], archiveDir);
                    }
                }

                if (ITunesSourceFiles != null)
                {
                    // Archive the iTunesMetadata.plist and iTunesArtwork files...
                    var iTunesMetadataDir = Path.Combine(archiveDir, "iTunesMetadata", Path.GetFileName(AppBundleDir.ItemSpec));
                    for (int i = 0; i < ITunesSourceFiles.Length; i++)
                    {
                        var archivedMetaFile = Path.Combine(iTunesMetadataDir, Path.GetFileName(ITunesSourceFiles[i].ItemSpec));

                        Directory.CreateDirectory(iTunesMetadataDir);
                        File.Copy(ITunesSourceFiles[i].ItemSpec, archivedMetaFile, true);
                    }
                }

                // Generate an archive Info.plist
                var arInfo = new PDictionary();
                // FIXME: figure out this value
                //arInfo.Add ("AppStoreFileSize", new PNumber (65535));

                var props = new PDictionary();
                props.Add("ApplicationPath", new PString(string.Format("Applications/{0}", Path.GetFileName(AppBundleDir.ItemSpec))));
                props.Add("CFBundleIdentifier", new PString(plist.GetCFBundleIdentifier()));
                if (plist.GetCFBundleShortVersionString() != null)
                {
                    props.Add("CFBundleShortVersionString", new PString(plist.GetCFBundleShortVersionString()));
                }
                else if (plist.GetCFBundleVersion() != null)
                {
                    props.Add("CFBundleShortVersionString", new PString(plist.GetCFBundleVersion()));
                }

                var iconFiles = plist.GetCFBundleIconFiles();
                var iconDict  = plist.GetCFBundleIcons();
                var icons     = new PArray();

                if (iconFiles != null)
                {
                    AddIconPaths(icons, iconFiles, Path.Combine(archiveDir, "Products"));
                }

                if (iconDict != null)
                {
                    var primary = iconDict.Get <PDictionary> (ManifestKeys.CFBundlePrimaryIcon);
                    if (primary != null && (iconFiles = primary.GetCFBundleIconFiles()) != null)
                    {
                        AddIconPaths(icons, iconFiles, Path.Combine(archiveDir, "Products"));
                    }
                }

                if (icons.Count > 0)
                {
                    props.Add("IconPaths", icons);
                }

                props.Add("SigningIdentity", new PString(SigningKey));

                arInfo.Add("ApplicationProperties", props);
                arInfo.Add("ArchiveVersion", new PNumber(2));
                arInfo.Add("CreationDate", new PDate(Now.ToUniversalTime()));
                arInfo.Add("Name", new PString(plist.GetCFBundleName() ?? plist.GetCFBundleDisplayName()));
                arInfo.Add("SchemeName", new PString(ProjectName));

                if (!string.IsNullOrEmpty(SolutionPath))
                {
                    arInfo.Add("SolutionName", new PString(Path.GetFileNameWithoutExtension(SolutionPath)));
                    arInfo.Add("SolutionPath", new PString(SolutionPath));
                }

                arInfo.Save(Path.Combine(archiveDir, "Info.plist"));

                ArchiveDir = archiveDir;
            } catch (Exception ex) {
                Log.LogErrorFromException(ex);
                Directory.Delete(archiveDir, true);
            }

            return(!Log.HasLoggedErrors);
        }
Exemple #12
0
 protected virtual IEnumerable<string> GetTargetDevices(PDictionary plist)
 {
     yield break;
 }
        public override bool Execute()
        {
            PDictionary plist;

            if (File.Exists(ProductDefinition))
            {
                try {
                    plist = PDictionary.FromFile(ProductDefinition);
                } catch (Exception ex) {
                    LogProductDefinitionError(MSBStrings.E0010, ProductDefinition, ex.Message);
                    return(false);
                }
            }
            else
            {
                plist = new PDictionary();
            }

            if (!string.IsNullOrEmpty(TargetArchitectures) && !Enum.TryParse(TargetArchitectures, out architectures))
            {
                LogProductDefinitionError(MSBStrings.E0012, TargetArchitectures);
                return(false);
            }

            // productbuild can do a guess of the targeted architectures if not provided, but the guess
            // is very simple : on Catalina and lower, it will suppose it's x86_64 (even with an arm64 slice).
            HashSet <string> archStrings = new HashSet <string> (architectures.ToArray().Select(a => a.ToNativeArchitecture()));

            if (plist.TryGetValue(ProductDefinitionKeys.Architectures, out PArray archArray))
            {
                var existingArchs = archArray.ToStringArray();
                if (!archStrings.SetEquals(existingArchs))
                {
                    LogProductDefinitionWarning(MSBStrings.E7072, string.Join(", ", existingArchs), string.Join(", ", archStrings));
                }
            }

            if (archArray == null)
            {
                archArray = new PArray();
                foreach (var arch in archStrings)
                {
                    archArray.Add(new PString(arch));
                }
            }
            plist [ProductDefinitionKeys.Architectures] = archArray;

            if (!plist.TryGetValue(ProductDefinitionKeys.MinimumSystemVersion, out PArray osVersionArray))
            {
                var minOSVersion = GetMinimumOSVersion();
                if (minOSVersion != null)
                {
                    osVersionArray = new PArray();
                    osVersionArray.Add(new PString(minOSVersion));
                }
            }
            if (osVersionArray != null)
            {
                plist [ProductDefinitionKeys.MinimumSystemVersion] = osVersionArray;
            }

            CompiledProductDefinition = new TaskItem(Path.Combine(OutputDirectory, "Product.plist"));
            plist.Save(CompiledProductDefinition.ItemSpec, true, false);

            return(!Log.HasLoggedErrors);
        }
		void AddToTree (Gtk.TreeStore treeStore, Gtk.TreeIter iter, PDictionary dict)
		{
			iterTable[dict] = iter;
			foreach (var item in dict) {
				var key = item.Key.ToString ();
				var subIter = iter.Equals (TreeIter.Zero) ? treeStore.AppendValues (key, item.Value) : treeStore.AppendValues (iter, key, item.Value);
				if (item.Value is PArray)
					AddToTree (treeStore, subIter, (PArray)item.Value);
				if (item.Value is PDictionary)
					AddToTree (treeStore, subIter, (PDictionary)item.Value);
				if (expandedObjects.Contains (item.Value))
					treeview.ExpandRow (treeStore.GetPath (subIter), true);
			}
			AddCreateNewEntry (iter);
			
			if (!rebuildArrays.Contains (dict)) {
				rebuildArrays.Add (dict);
				dict.Changed += HandleDictRebuild;
			}
		}
        public override bool Execute()
        {
            PDictionary plist;
            PString     value;

            try {
                plist = PDictionary.FromFile(AppManifest.ItemSpec);
            } catch (Exception ex) {
                Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, MSBStrings.E0055, ex.Message);
                return(false);
            }

//			deviceType = plist.GetUIDeviceFamily ();

            if (plist.TryGetValue(ManifestKeys.MinimumOSVersion, out value))
            {
                if (!IPhoneSdkVersion.TryParse(value.Value, out minimumOSVersion))
                {
                    Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, MSBStrings.E0011, value);
                    return(false);
                }
            }
            else
            {
                switch (Framework)
                {
                case ApplePlatform.iOS:
                    IPhoneSdkVersion sdkVersion;
                    if (!IPhoneSdkVersion.TryParse(SdkVersion, out sdkVersion))
                    {
                        Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, MSBStrings.E0056, SdkVersion);
                        return(false);
                    }

                    minimumOSVersion = sdkVersion;
                    break;

                case ApplePlatform.WatchOS:
                case ApplePlatform.TVOS:
                    minimumOSVersion = IPhoneSdkVersion.UseDefault;
                    break;

                default:
                    throw new InvalidOperationException(string.Format("Invalid framework: {0}", Framework));
                }
            }

            Directory.CreateDirectory(AppBundleDir);

            var executableLastWriteTime = default(DateTime);
            var executable = Path.Combine(AppBundleDir, ExecutableName);

            if (File.Exists(executable))
            {
                executableLastWriteTime = File.GetLastWriteTimeUtc(executable);
            }

            var result = base.Execute();

            CopiedFrameworks = GetCopiedFrameworks();

            if (File.Exists(executable) && File.GetLastWriteTimeUtc(executable) != executableLastWriteTime)
            {
                NativeExecutable = new TaskItem(executable);
            }

            return(result);
        }
Exemple #16
0
        void Init()
        {
            string currentLocation = IsInstalled ? MmpPath : null;

            IsInstalled = false;
            versions    = null;

            FrameworkDirectory = "/Library/Frameworks/Xamarin.Mac.framework/Versions/Current";
            var envFrameworkDir = Environment.GetEnvironmentVariable("XAMMAC_FRAMEWORK_PATH");

            if (envFrameworkDir != null && Directory.Exists(envFrameworkDir))
            {
                FrameworkDirectory = envFrameworkDir;
            }

            var versionPath = Path.Combine(FrameworkDirectory, "Version");

            if (File.Exists(versionPath))
            {
                Version = ReadVersion(versionPath);
                lastWriteTimes [versionPath] = File.GetLastWriteTimeUtc(versionPath);

                var path = Path.Combine(FrameworkDirectory, "Versions.plist");
                if (File.Exists(path))
                {
                    try {
                        versions = PDictionary.FromFile(path);
                    } catch {
                        LoggingService.LogWarning("Xamarin.Mac installation is corrupt: invalid Versions.plist at {0}.", path);
                    }
                }

                if (versions == null)
                {
                    versions = CreateDefaultVersionsPlist(Version);
                }
            }
            else
            {
                NotInstalled(versionPath, error: false);
                AnalyticsService.ReportSdkVersion("XS.Core.SDK.Mac.Version", string.Empty);
                return;
            }

            var paths = Version >= new MacOSXSdkVersion(1, 9, 0)
                                ? Detect2x()
                                : Detect1x();

            foreach (var path in paths)
            {
                if (!File.Exists(path))
                {
                    NotInstalled(path);
                    return;
                }

                lastWriteTimes [path] = File.GetLastWriteTimeUtc(path);
            }

            IsInstalled = true;
            LoggingService.LogInfo("Found Xamarin.Mac, version {0}.", Version);
            AnalyticsService.ReportSdkVersion("XS.Core.SDK.Mac.Version", Version.ToString());

            if (Changed != null && currentLocation != MmpPath)
            {
                Changed(this, EventArgs.Empty);
            }
        }
Exemple #17
0
        public override bool Execute()
        {
            PDictionary plist;

            var path = Path.Combine(AppBundleDir, "Settings.bundle", "Root.plist");

            if (File.Exists(path))
            {
                try {
                    plist = PDictionary.FromFile(path);
                } catch (Exception ex) {
                    Log.LogError(MSBStrings.E0024, Path.GetFileName(AppBundleDir), ex.Message);
                    return(false);
                }
            }
            else
            {
                plist = new PDictionary();
            }

            plist.SetIfNotPresent("Title", "AppSettings");
            plist.SetIfNotPresent("StringsTable", "Root");

            var specifiers = plist.GetArray("PreferenceSpecifiers");

            // check that we haven't already merged in our debug settings...
            foreach (var specifier in specifiers.OfType <PDictionary> ())
            {
                if (specifier.Get <PString> ("Type") == "PSToggleSwitchSpecifier" && specifier.Get <PString> ("Key") == "__monotouch_debug_enabled")
                {
                    return(!Log.HasLoggedErrors);
                }
            }

            specifiers.Add(new PDictionary {
                { "Type", "PSGroupSpecifier" },
                { "Title", "Debug Settings" }
            });

            specifiers.Add(new PDictionary {
                { "Type", "PSToggleSwitchSpecifier" },
                { "Title", "Enabled" },
                { "Key", "__monotouch_debug_enabled" },
                { "DefaultValue", "1" },
                { "TrueValue", "1" },
                { "FalseValue", "0" }
            });

            specifiers.Add(new PDictionary {
                { "Type", "PSTextFieldSpecifier" },
                { "Title", "Xamarin Studio Host" },
                { "Key", "__monodevelop_host" },
                { "AutocapitalizationType", "None" },
                { "AutocorrectionType", "No" },
                { "DefaultValue", "automatic" }
            });

            if (!Directory.Exists(Path.GetDirectoryName(path)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(path));
            }

            plist.Save(path, true, true);

            return(!Log.HasLoggedErrors);
        }
Exemple #18
0
        public override bool Execute()
        {
            MobileProvisionPlatform platform;
            MobileProvision         profile;
            PDictionary             template;
            PDictionary             compiled;
            PDictionary             archived;
            string path;

            switch (SdkPlatform)
            {
            case "AppleTVSimulator":
            case "AppleTVOS":
                platform = MobileProvisionPlatform.tvOS;
                break;

            case "iPhoneSimulator":
            case "WatchSimulator":
            case "iPhoneOS":
            case "WatchOS":
                platform = MobileProvisionPlatform.iOS;
                break;

            case "MacOSX":
                platform = MobileProvisionPlatform.MacOS;
                break;

            case "MacCatalyst":
                platform = MobileProvisionPlatform.MacOS;
                break;

            default:
                Log.LogError(MSBStrings.E0048, SdkPlatform);
                return(false);
            }

            if (!string.IsNullOrEmpty(ProvisioningProfile))
            {
                if ((profile = GetMobileProvision(platform, ProvisioningProfile)) == null)
                {
                    Log.LogError(MSBStrings.E0049, ProvisioningProfile);
                    return(false);
                }
            }
            else
            {
                profile = null;
            }

            if (!string.IsNullOrEmpty(Entitlements))
            {
                if (!File.Exists(Entitlements))
                {
                    Log.LogError(MSBStrings.E0112, Entitlements);
                    return(false);
                }

                path = Entitlements;
            }
            else
            {
                path = DefaultEntitlementsPath;
            }

            try {
                template = PDictionary.FromFile(path);
            } catch (Exception ex) {
                Log.LogError(MSBStrings.E0113, path, ex.Message);
                return(false);
            }

            compiled = GetCompiledEntitlements(profile, template);
            archived = GetArchivedExpandedEntitlements(template, compiled);

            try {
                Directory.CreateDirectory(Path.GetDirectoryName(CompiledEntitlements.ItemSpec));
                WriteXcent(compiled, CompiledEntitlements.ItemSpec);
            } catch (Exception ex) {
                Log.LogError(MSBStrings.E0114, CompiledEntitlements, ex.Message);
                return(false);
            }

            SaveArchivedExpandedEntitlements(archived);

            if (SdkIsSimulator)
            {
                if (compiled.Count > 0)
                {
                    EntitlementsInExecutable = CompiledEntitlements;
                }
            }
            else
            {
                EntitlementsInSignature = CompiledEntitlements;
            }

            return(!Log.HasLoggedErrors);
        }
Exemple #19
0
        protected override string GenerateCommandLineCommands()
        {
            var  args = new CommandLineArgumentBuilder();
            bool msym;

            if (Debug)
            {
                args.AddLine("/debug");
            }

            if (!string.IsNullOrEmpty(OutputPath))
            {
                args.AddQuotedLine("/output:" + Path.GetFullPath(OutputPath));
            }

            if (!string.IsNullOrEmpty(ApplicationName))
            {
                args.AddQuotedLine("/name:" + ApplicationName);
            }

            if (TargetFrameworkIdentifier == "Xamarin.Mac")
            {
                args.AddLine("/profile:Xamarin.Mac,Version=v2.0,Profile=Mobile");
            }
            else if (UseXamMacFullFramework)
            {
                args.AddLine($"/profile:Xamarin.Mac,Version={TargetFrameworkVersion},Profile=Full");
            }
            else
            {
                args.AddLine($"/profile:Xamarin.Mac,Version={TargetFrameworkVersion},Profile=System");
            }

            XamMacArch arch;

            if (!Enum.TryParse(Architecture, true, out arch))
            {
                arch = XamMacArch.Default;
            }

            if (arch == XamMacArch.Default)
            {
                arch = XamMacArch.x86_64;
            }

            if (arch.HasFlag(XamMacArch.i386))
            {
                args.AddLine("/arch:i386");
            }

            if (arch.HasFlag(XamMacArch.x86_64))
            {
                args.AddLine("/arch:x86_64");
            }

            if (!string.IsNullOrEmpty(ArchiveSymbols) && bool.TryParse(ArchiveSymbols.Trim(), out msym))
            {
                args.AddLine("--msym:" + (msym ? "yes" : "no"));
            }

            args.AddLine(string.Format("--http-message-handler={0}", HttpClientHandler));

            if (AppManifest != null)
            {
                try {
                    var plist = PDictionary.FromFile(AppManifest.ItemSpec);

                    PString v;
                    string  minimumDeploymentTarget;

                    if (!plist.TryGetValue(ManifestKeys.LSMinimumSystemVersion, out v) || string.IsNullOrEmpty(v.Value))
                    {
                        minimumDeploymentTarget = SdkVersion;
                    }
                    else
                    {
                        minimumDeploymentTarget = v.Value;
                    }

                    args.AddLine(string.Format("/minos={0}", minimumDeploymentTarget));
                }
                catch (Exception ex) {
                    Log.LogWarning(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "Error loading '{0}': {1}", AppManifest.ItemSpec, ex.Message);
                }
            }

            if (Profiling)
            {
                args.AddLine("/profiling");
            }

            if (EnableSGenConc)
            {
                args.AddLine("/sgen-conc");
            }

            switch ((LinkMode ?? string.Empty).ToLower())
            {
            case "full":
                break;

            case "sdkonly":
                args.AddLine("/linksdkonly");
                break;

            case "platform":
                args.AddLine("/linkplatform");
                break;

            default:
                args.AddLine("/nolink");
                break;
            }

            if (!string.IsNullOrEmpty(AotMode) && AotMode != "None")
            {
                var aot = $"--aot:{AotMode.ToLower ()}";
                if (HybridAOT)
                {
                    aot += "|hybrid";
                }

                if (!string.IsNullOrEmpty(ExplicitAotAssemblies))
                {
                    aot += $",{ExplicitAotAssemblies}";
                }

                args.AddLine(aot);
            }

            if (!string.IsNullOrEmpty(I18n))
            {
                args.AddQuotedLine("/i18n:" + I18n);
            }

            if (ExplicitReferences != null)
            {
                foreach (var asm in ExplicitReferences)
                {
                    args.AddQuotedLine("/assembly:" + Path.GetFullPath(asm.ItemSpec));
                }
            }

            if (!string.IsNullOrEmpty(ApplicationAssembly.ItemSpec))
            {
                args.AddQuotedLine("/root-assembly:" + Path.GetFullPath(ApplicationAssembly.ItemSpec));
            }

            if (NativeReferences != null)
            {
                foreach (var nr in NativeReferences)
                {
                    args.AddQuotedLine("/native-reference:" + Path.GetFullPath(nr.ItemSpec));
                }
            }

            if (IsAppExtension)
            {
                args.AddQuotedLine("/extension");
            }
            if (IsXPCService)
            {
                args.AddQuotedLine("/xpc");
            }

            args.AddQuotedLine("/sdkroot:" + SdkRoot);

            if (!string.IsNullOrEmpty(IntermediateOutputPath))
            {
                Directory.CreateDirectory(IntermediateOutputPath);

                args.AddQuotedLine("--cache:" + Path.GetFullPath(IntermediateOutputPath));
            }

            // Generate a response file
            var responseFile = Path.GetFullPath(ResponseFilePath);

            if (File.Exists(responseFile))
            {
                File.Delete(responseFile);
            }

            try {
                using (var fs = File.Create(responseFile)) {
                    using (var writer = new StreamWriter(fs))
                        writer.Write(args);
                }
            } catch (Exception ex) {
                Log.LogWarning("Failed to create response file '{0}': {1}", responseFile, ex);
            }

            // Some arguments can not safely go in the response file and are
            // added separately. They must go _after_ the response file
            // as they may override options passed in the response file
            var actualArgs = new CommandLineArgumentBuilder();

            actualArgs.AddQuoted($"@{responseFile}");

            if (!string.IsNullOrWhiteSpace(ExtraArguments))
            {
                actualArgs.Add(ExtraArguments);
            }

            var verbosity = VerbosityUtils.Merge(ExtraArguments, (LoggerVerbosity)Verbosity);

            // for compatibility with earlier versions nothing means one /v
            actualArgs.AddLine(verbosity.Length > 0 ? verbosity : "/verbose");

            return(actualArgs.ToString());
        }
Exemple #20
0
        protected virtual PDictionary GetCompiledEntitlements(MobileProvision profile, PDictionary template)
        {
            var entitlements = new PDictionary();

            if (profile != null && MergeProfileEntitlements)
            {
                // start off with the settings from the provisioning profile
                foreach (var item in profile.Entitlements)
                {
                    if (!AllowedProvisioningKeys.Contains(item.Key))
                    {
                        continue;
                    }

                    var value = item.Value;

                    if (item.Key == "com.apple.developer.icloud-container-environment")
                    {
                        value = new PString("Development");
                    }
                    else if (value is PDictionary)
                    {
                        value = MergeEntitlementDictionary((PDictionary)value, profile);
                    }
                    else if (value is PString)
                    {
                        value = MergeEntitlementString((PString)value, profile, item.Key == ApplicationIdentifierKey);
                    }
                    else if (value is PArray)
                    {
                        value = MergeEntitlementArray((PArray)value, profile);
                    }
                    else
                    {
                        value = value.Clone();
                    }

                    if (value != null)
                    {
                        entitlements.Add(item.Key, value);
                    }
                }
            }

            // merge in the user's values
            foreach (var item in template)
            {
                var value = item.Value;

                if (item.Key == "com.apple.developer.ubiquity-container-identifiers" ||
                    item.Key == "com.apple.developer.icloud-container-identifiers" ||
                    item.Key == "com.apple.developer.icloud-container-environment" ||
                    item.Key == "com.apple.developer.icloud-services")
                {
                    if (profile == null)
                    {
                        Log.LogWarning(null, null, null, Entitlements, 0, 0, 0, 0, MSBStrings.W0110, item.Key);
                    }
                    else if (!profile.Entitlements.ContainsKey(item.Key))
                    {
                        Log.LogWarning(null, null, null, Entitlements, 0, 0, 0, 0, MSBStrings.W0111, item.Key);
                    }
                }
                else if (item.Key == ApplicationIdentifierKey)
                {
                    var str = value as PString;

                    // Ignore ONLY if it is empty, otherwise take the user's value
                    if (str == null || string.IsNullOrEmpty(str.Value))
                    {
                        continue;
                    }
                }

                if (value is PDictionary)
                {
                    value = MergeEntitlementDictionary((PDictionary)value, profile);
                }
                else if (value is PString)
                {
                    value = MergeEntitlementString((PString)value, profile, item.Key == ApplicationIdentifierKey);
                }
                else if (value is PArray)
                {
                    value = MergeEntitlementArray((PArray)value, profile);
                }
                else
                {
                    value = value.Clone();
                }

                if (value != null)
                {
                    entitlements[item.Key] = value;
                }
            }

            switch (Platform)
            {
            case ApplePlatform.MacOSX:
            case ApplePlatform.MacCatalyst:
                if (Debug && entitlements.TryGetValue("com.apple.security.app-sandbox", out PBoolean sandbox) && sandbox.Value)
                {
                    entitlements ["com.apple.security.network.client"] = new PBoolean(true);
                }
                break;
            }

            return(entitlements);
        }
Exemple #21
0
        public override bool Execute()
        {
            if (IsWatchApp && AppleSdkSettings.XcodeVersion < new Version(6, 2))
            {
                Log.LogError(MSBStrings.E0160, AppleSdkSettings.XcodeVersion);

                return(!Log.HasLoggedErrors);
            }

            var  ibtoolManifestDir = Path.Combine(IntermediateOutputPath, "ibtool-manifests");
            var  ibtoolOutputDir   = Path.Combine(IntermediateOutputPath, "ibtool");
            var  outputManifests   = new List <ITaskItem> ();
            var  compiled          = new List <ITaskItem> ();
            bool changed;

            if (InterfaceDefinitions.Length > 0)
            {
                if (AppManifest != null)
                {
                    plist = PDictionary.FromFile(AppManifest.ItemSpec);
                    PString value;

                    if (!plist.TryGetValue(MinimumDeploymentTargetKey, out value) || string.IsNullOrEmpty(value.Value))
                    {
                        minimumDeploymentTarget = SdkVersion;
                    }
                    else
                    {
                        minimumDeploymentTarget = value.Value;
                    }
                }
                else
                {
                    minimumDeploymentTarget = SdkVersion;
                }

                Directory.CreateDirectory(ibtoolManifestDir);
                Directory.CreateDirectory(ibtoolOutputDir);

                if (!CompileInterfaceDefinitions(ibtoolManifestDir, ibtoolOutputDir, compiled, outputManifests, out changed))
                {
                    return(false);
                }

                if (CanLinkStoryboards)
                {
                    var storyboards = new List <ITaskItem> ();
                    var linked      = new List <ITaskItem> ();
                    var unique      = new HashSet <string> ();

                    for (int i = 0; i < compiled.Count; i++)
                    {
                        // pretend that non-storyboardc items (e.g. *.nib) are already 'linked'
                        if (compiled[i].ItemSpec.EndsWith(".storyboardc", StringComparison.Ordinal))
                        {
                            var interfaceDefinition = compiled[i].GetMetadata("InterfaceDefinition");
                            unique.Add(interfaceDefinition);
                            storyboards.Add(compiled[i]);
                            continue;
                        }

                        // just pretend any *nib's have already been 'linked'...
                        compiled[i].RemoveMetadata("InterfaceDefinition");
                        linked.Add(compiled[i]);
                    }

                    // only link the storyboards if there are multiple unique storyboards
                    if (unique.Count > 1)
                    {
                        var linkOutputDir = Path.Combine(IntermediateOutputPath, "ibtool-link");

                        if (!LinkStoryboards(ibtoolManifestDir, linkOutputDir, storyboards, linked, outputManifests, changed))
                        {
                            return(false);
                        }

                        compiled = linked;
                    }
                }
                else
                {
                    for (int i = 0; i < compiled.Count; i++)
                    {
                        compiled[i].RemoveMetadata("InterfaceDefinition");
                    }
                }
            }

            var bundleResources = new List <ITaskItem> ();

            foreach (var compiledItem in compiled)
            {
                if (Directory.Exists(compiledItem.ItemSpec))
                {
                    bundleResources.AddRange(GetBundleResources(compiledItem));
                }
                else if (File.Exists(compiledItem.ItemSpec))
                {
                    bundleResources.Add(compiledItem);
                }
            }

            BundleResources = bundleResources.ToArray();
            OutputManifests = outputManifests.ToArray();

            Log.LogTaskProperty("BundleResources Output", BundleResources);
            Log.LogTaskProperty("OutputManifests Output", OutputManifests);

            return(!Log.HasLoggedErrors);
        }
Exemple #22
0
        bool CompileInterfaceDefinitions(string baseManifestDir, string baseOutputDir, List <ITaskItem> compiled, IList <ITaskItem> manifests, out bool changed)
        {
            var mapping = new Dictionary <string, IDictionary> ();
            var unique  = new Dictionary <string, ITaskItem> ();
            var targets = GetTargetDevices(plist).ToList();

            changed = false;

            foreach (var item in InterfaceDefinitions)
            {
                var       bundleName  = GetBundleRelativeOutputPath(item);
                var       manifest    = new TaskItem(Path.Combine(baseManifestDir, bundleName));
                var       manifestDir = Path.GetDirectoryName(manifest.ItemSpec);
                ITaskItem duplicate;
                string    output;

                if (!File.Exists(item.ItemSpec))
                {
                    Log.LogError(null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0158, item.ItemSpec);
                    continue;
                }

                if (unique.TryGetValue(bundleName, out duplicate))
                {
                    Log.LogError(null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0159, item.ItemSpec, duplicate.ItemSpec);
                    continue;
                }

                unique.Add(bundleName, item);

                var resourceTags = item.GetMetadata("ResourceTags");
                var path         = Path.Combine(baseOutputDir, bundleName);
                var outputDir    = Path.GetDirectoryName(path);
                var name         = GetPathWithoutExtension(path);
                var extension    = Path.GetExtension(path);
                var expected     = new TaskItem(path);

                expected.SetMetadata("InterfaceDefinition", item.ItemSpec);
                expected.SetMetadata("LogicalName", bundleName);
                expected.SetMetadata("Optimize", "false");

                if (EnableOnDemandResources && !string.IsNullOrEmpty(resourceTags))
                {
                    expected.SetMetadata("ResourceTags", resourceTags);
                }

                if (UseCompilationDirectory)
                {
                    // Note: When using --compilation-directory, we need to specify the output path as the parent directory
                    output = Path.GetDirectoryName(path);
                }
                else
                {
                    output = expected.ItemSpec;
                }

                if (InterfaceDefinitionChanged(item, manifest))
                {
                    Directory.CreateDirectory(manifestDir);
                    Directory.CreateDirectory(outputDir);

                    if ((Compile(new[] { item }, output, manifest)) != 0)
                    {
                        return(false);
                    }

                    changed = true;
                }
                else
                {
                    Log.LogMessage(MessageImportance.Low, MSBStrings.M0119, item.ItemSpec, manifest.ItemSpec);
                }

                try {
                    var dict = PDictionary.FromFile(manifest.ItemSpec);

                    LogWarningsAndErrors(dict, item);
                } catch (Exception ex) {
                    Log.LogError(MSBStrings.E0094, ToolName, manifest.ItemSpec, ex.Message);
                    if (File.Exists(manifest.ItemSpec))
                    {
                        Log.LogError("ibtool log: {0}", File.ReadAllText(manifest.ItemSpec));
                    }
                    continue;
                }

                if (UseCompilationDirectory)
                {
                    // Note: When using a compilation-directory, we'll scan dir the baseOutputDir later as
                    // an optimization to collect all of the compiled output in one fell swoop.
                    var metadata = expected.CloneCustomMetadata();

                    foreach (var target in targets)
                    {
                        var key = name + "~" + target + extension;

                        // Note: we don't blindly .Add() here because there may already be a mapping for this file if the
                        // source file is named something like "MyView.xib" and we've already processed "MyView~ipad.xib".
                        //
                        // When a situation like this occurs, we don't want to override the metadata.
                        if (!mapping.ContainsKey(key))
                        {
                            mapping.Add(key, metadata);
                        }
                    }

                    // Note: we don't use .Add() here because there may already be a mapping for this file if the
                    // source file is named something like "MyView~ipad.xib" and we've already processed "MyView.xib".
                    //
                    // In this case, we want to override the metadata for "MyView.xib" with the metadata for
                    // "MyView~ipad.xib".
                    mapping[path] = metadata;
                }
                else
                {
                    compiled.AddRange(GetCompilationOutput(expected));
                }

                manifests.Add(manifest);
            }

            if (UseCompilationDirectory)
            {
                compiled.AddRange(GetCompilationDirectoryOutput(baseOutputDir, mapping));
            }

            return(!Log.HasLoggedErrors);
        }
        public override bool Execute()
        {
            var    intermediate          = Path.Combine(IntermediateOutputPath, ToolName);
            var    intermediateBundleDir = Path.Combine(intermediate, "bundle");
            var    intermediateCloneDir  = Path.Combine(intermediate, "cloned-assets");
            var    manifest         = new TaskItem(Path.Combine(intermediate, "asset-manifest.plist"));
            var    bundleResources  = new List <ITaskItem> ();
            var    outputManifests  = new List <ITaskItem> ();
            var    catalogs         = new List <ITaskItem> ();
            var    unique           = new HashSet <string> ();
            string bundleIdentifier = null;
            var    knownSpecs       = new HashSet <string> ();
            var    clones           = new HashSet <string> ();
            var    items            = new List <ITaskItem> ();
            var    specs            = new PArray();

            switch (SdkPlatform)
            {
            case "iPhoneSimulator":
            case "iPhoneOS":
            case "MacOSX":
            case "WatchSimulator":
            case "WatchOS":
            case "AppleTVSimulator":
            case "AppleTVOS":
                break;

            default:
                Log.LogError("Unrecognized platform: {0}", SdkPlatform);
                return(false);
            }

            if (AppManifest != null)
            {
                try {
                    plist = PDictionary.FromFile(AppManifest.ItemSpec);
                } catch (Exception ex) {
                    Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "{0}", ex.Message);
                    return(false);
                }

                bundleIdentifier = plist.GetCFBundleIdentifier();
            }

            for (int i = 0; i < ImageAssets.Length; i++)
            {
                var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, ImageAssets[i], !string.IsNullOrEmpty(SessionId));

                // Ignore MacOS .DS_Store files...
                if (Path.GetFileName(vpath).Equals(".DS_Store", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc)
                var catalog = Path.GetDirectoryName(vpath);

                // keep walking up the directory structure until we get to the .xcassets directory
                while (!string.IsNullOrEmpty(catalog) && Path.GetExtension(catalog) != ".xcassets")
                {
                    catalog = Path.GetDirectoryName(catalog);
                }

                if (string.IsNullOrEmpty(catalog))
                {
                    Log.LogWarning(null, null, null, ImageAssets[i].ItemSpec, 0, 0, 0, 0, "Asset not part of an asset catalog: {0}", ImageAssets[i].ItemSpec);
                    continue;
                }

                if (ImageAssets[i].GetMetadata("Link") != null)
                {
                    // Note: if any of the files within a catalog are linked, we'll have to clone the *entire* catalog
                    clones.Add(catalog);
                    continue;
                }

                // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these
                if (Path.GetFileName(vpath) != "Contents.json")
                {
                    continue;
                }

                items.Add(ImageAssets[i]);
            }

            // clone any *.xcassets dirs that need cloning
            if (clones.Count > 0)
            {
                if (Directory.Exists(intermediateCloneDir))
                {
                    Directory.Delete(intermediateCloneDir, true);
                }

                Directory.CreateDirectory(intermediateCloneDir);

                items.Clear();

                for (int i = 0; i < ImageAssets.Length; i++)
                {
                    var       vpath = BundleResource.GetVirtualProjectPath(ProjectDir, ImageAssets[i], !string.IsNullOrEmpty(SessionId));
                    var       clone = false;
                    ITaskItem item;

                    // Ignore MacOS .DS_Store files...
                    if (Path.GetFileName(vpath).Equals(".DS_Store", StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    foreach (var catalog in clones)
                    {
                        if (vpath.Length > catalog.Length && vpath[catalog.Length] == '/' && vpath.StartsWith(catalog, StringComparison.Ordinal))
                        {
                            clone = true;
                            break;
                        }
                    }

                    if (clone)
                    {
                        var src = ImageAssets[i].GetMetadata("FullPath");

                        if (!File.Exists(src))
                        {
                            Log.LogError(null, null, null, src, 0, 0, 0, 0, "File not found: {0}", src);
                            return(false);
                        }

                        var dest = Path.Combine(intermediateCloneDir, vpath);
                        var dir  = Path.GetDirectoryName(dest);

                        Directory.CreateDirectory(dir);

                        File.Copy(src, dest, true);

                        // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these
                        if (Path.GetFileName(vpath) != "Contents.json")
                        {
                            continue;
                        }

                        item = new TaskItem(dest);
                        ImageAssets[i].CopyMetadataTo(item);
                        item.SetMetadata("Link", vpath);
                    }
                    else
                    {
                        // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these
                        if (Path.GetFileName(vpath) != "Contents.json")
                        {
                            continue;
                        }

                        item = ImageAssets[i];
                    }

                    items.Add(item);
                }
            }

            // Note: `items` contains only the Contents.json files at this point
            for (int i = 0; i < items.Count; i++)
            {
                var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, items[i], !string.IsNullOrEmpty(SessionId));
                var path  = items[i].GetMetadata("FullPath");

                // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc)
                var catalog = Path.GetDirectoryName(vpath);
                path = Path.GetDirectoryName(path);

                // keep walking up the directory structure until we get to the .xcassets directory
                while (!string.IsNullOrEmpty(catalog) && Path.GetExtension(catalog) != ".xcassets")
                {
                    catalog = Path.GetDirectoryName(catalog);
                    path    = Path.GetDirectoryName(path);
                }

                if (unique.Add(catalog))
                {
                    var item = new TaskItem(path);
                    item.SetMetadata("Link", catalog);

                    catalogs.Add(item);
                }

                if (AppleSdkSettings.XcodeVersion.Major >= 7 && !string.IsNullOrEmpty(bundleIdentifier) && SdkPlatform != "WatchSimulator")
                {
                    var text = File.ReadAllText(items[i].ItemSpec);

                    if (string.IsNullOrEmpty(text))
                    {
                        continue;
                    }

                    JsonDocument json;
                    JsonElement  value;

                    try {
                        var options = new JsonDocumentOptions()
                        {
                            AllowTrailingCommas = true,
                        };
                        json = JsonDocument.Parse(text, options);
                    } catch (JsonException je) {
                        var line = (int)(je.LineNumber + 1 ?? 0);
                        var col  = (int)(je.BytePositionInLine + 1 ?? 0);
                        Log.LogError(null, null, null, items [i].ItemSpec, line, col, line, col, "{0}", je.Message);
                        return(false);
                    } catch (Exception e) {
                        Log.LogError(null, null, null, items[i].ItemSpec, 0, 0, 0, 0, "Invalid json: {0}", e.Message);
                        return(false);
                    }

                    if (!json.RootElement.TryGetProperty("properties", out value) || value.ValueKind != JsonValueKind.Object)
                    {
                        continue;
                    }

                    var properties = value;

                    if (!properties.TryGetProperty("on-demand-resource-tags", out value) || value.ValueKind != JsonValueKind.Array)
                    {
                        continue;
                    }

                    var    resourceTags = value;
                    var    tags         = new HashSet <string> ();
                    string hash;

                    foreach (var tag in resourceTags.EnumerateArray())
                    {
                        if (tag.ValueKind == JsonValueKind.String)
                        {
                            tags.Add(tag.GetString());
                        }
                    }

                    var tagList = tags.ToList();
                    tagList.Sort();

                    var assetDir = AssetPackUtils.GetAssetPackDirectory(intermediate, bundleIdentifier, tagList, out hash);

                    if (knownSpecs.Add(hash))
                    {
                        var assetpack = new PDictionary();
                        var ptags     = new PArray();

                        Directory.CreateDirectory(assetDir);

                        for (int j = 0; j < tagList.Count; j++)
                        {
                            ptags.Add(new PString(tagList[j]));
                        }

                        assetpack.Add("bundle-id", new PString(string.Format("{0}.asset-pack-{1}", bundleIdentifier, hash)));
                        assetpack.Add("bundle-path", new PString(Path.GetFullPath(assetDir)));
                        assetpack.Add("tags", ptags);
                        specs.Add(assetpack);
                    }
                }
            }

            if (catalogs.Count == 0)
            {
                // There are no (supported?) asset catalogs
                return(!Log.HasLoggedErrors);
            }

            partialAppManifest = new TaskItem(Path.Combine(intermediate, "partial-info.plist"));

            if (specs.Count > 0)
            {
                outputSpecs = Path.Combine(intermediate, "output-specifications.plist");
                specs.Save(outputSpecs, true);
            }

            Directory.CreateDirectory(intermediateBundleDir);

            // Note: Compile() will set the PartialAppManifest property if it is used...
            if ((Compile(catalogs.ToArray(), intermediateBundleDir, manifest)) != 0)
            {
                return(false);
            }

            if (PartialAppManifest != null && !File.Exists(PartialAppManifest.GetMetadata("FullPath")))
            {
                Log.LogError("Partial Info.plist file was not generated: {0}", PartialAppManifest.GetMetadata("FullPath"));
            }

            try {
                var manifestOutput = PDictionary.FromFile(manifest.ItemSpec);

                LogWarningsAndErrors(manifestOutput, catalogs[0]);

                bundleResources.AddRange(GetCompiledBundleResources(manifestOutput, intermediateBundleDir));
                outputManifests.Add(manifest);
            } catch (Exception ex) {
                Log.LogError("Failed to load {0} log file `{1}`: {2}", ToolName, manifest.ItemSpec, ex.Message);
            }

            foreach (var assetpack in specs.OfType <PDictionary> ())
            {
                var path       = Path.Combine(assetpack.GetString("bundle-path").Value, "Info.plist");
                var bundlePath = PathUtils.AbsoluteToRelative(intermediate, path);
                var outputPath = Path.Combine(OutputPath, bundlePath);
                var rpath      = Path.Combine(intermediate, bundlePath);
                var dict       = new PDictionary();

                dict.SetCFBundleIdentifier(assetpack.GetString("bundle-id").Value);
                dict.Add("Tags", assetpack.GetArray("tags").Clone());

                dict.Save(path, true, true);

                var item = new TaskItem(rpath);
                item.SetMetadata("LogicalName", bundlePath);
                item.SetMetadata("OutputPath", outputPath);
                item.SetMetadata("Optimize", "false");

                bundleResources.Add(item);
            }

            BundleResources = bundleResources.ToArray();
            OutputManifests = outputManifests.ToArray();

            return(!Log.HasLoggedErrors);
        }
        public override bool Execute()
        {
            PDictionary plist;
            PString     value;

            Log.LogTaskName("MTouch");
            Log.LogTaskProperty("AppBundleDir", AppBundleDir);
            Log.LogTaskProperty("AppExtensionReferences", AppExtensionReferences);
            Log.LogTaskProperty("AppManifest", AppManifest);
            Log.LogTaskProperty("Architectures", Architectures);
            Log.LogTaskProperty("ArchiveSymbols", ArchiveSymbols);
            Log.LogTaskProperty("BitcodeEnabled", EnableBitcode);
            Log.LogTaskProperty("CompiledEntitlements", CompiledEntitlements);
            Log.LogTaskProperty("Debug", Debug);
            Log.LogTaskProperty("EnableGenericValueTypeSharing", EnableGenericValueTypeSharing);
            Log.LogTaskProperty("EnableSGenConc", EnableSGenConc);
            Log.LogTaskProperty("Entitlements", Entitlements);
            Log.LogTaskProperty("ExecutableName", ExecutableName);
            Log.LogTaskProperty("ExtraArgs", ExtraArgs);
            Log.LogTaskProperty("FastDev", FastDev);
            Log.LogTaskProperty("HttpClientHandler", HttpClientHandler);
            Log.LogTaskProperty("I18n", I18n);
            Log.LogTaskProperty("IntermediateOutputPath", IntermediateOutputPath);
            Log.LogTaskProperty("IsAppExtension", IsAppExtension);
            Log.LogTaskProperty("LinkerDumpDependencies", LinkerDumpDependencies);
            Log.LogTaskProperty("LinkMode", LinkMode);
            Log.LogTaskProperty("MainAssembly", MainAssembly);
            Log.LogTaskProperty("NativeReferences", NativeReferences);
            Log.LogTaskProperty("OutputPath", OutputPath);
            Log.LogTaskProperty("Profiling", Profiling);
            Log.LogTaskProperty("ProjectDir", ProjectDir);
            Log.LogTaskProperty("References", References);
            Log.LogTaskProperty("SdkIsSimulator", SdkIsSimulator);
            Log.LogTaskProperty("SdkRoot", SdkRoot);
            Log.LogTaskProperty("SdkVersion", SdkVersion);
            Log.LogTaskProperty("SymbolsList", SymbolsList);
            Log.LogTaskProperty("TargetFrameworkIdentifier", TargetFrameworkIdentifier);
            Log.LogTaskProperty("UseFloat32", UseFloat32);
            Log.LogTaskProperty("UseLlvm", UseLlvm);
            Log.LogTaskProperty("UseThumb", UseThumb);
            Log.LogTaskProperty("Verbosity", Verbosity.ToString());

            try {
                plist = PDictionary.FromFile(AppManifest.ItemSpec);
            } catch (Exception ex) {
                Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "Could not load Info.plist: {0}", ex.Message);
                return(false);
            }

//			deviceType = plist.GetUIDeviceFamily ();

            if (plist.TryGetValue(ManifestKeys.MinimumOSVersion, out value))
            {
                if (!IPhoneSdkVersion.TryParse(value.Value, out minimumOSVersion))
                {
                    Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "Could not parse MinimumOSVersion '{0}'", value);
                    return(false);
                }
            }
            else
            {
                switch (Framework)
                {
                case PlatformFramework.iOS:
                    IPhoneSdkVersion sdkVersion;
                    if (!IPhoneSdkVersion.TryParse(SdkVersion, out sdkVersion))
                    {
                        Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "Could not parse SdkVersion '{0}'", SdkVersion);
                        return(false);
                    }

                    minimumOSVersion = sdkVersion;
                    break;

                case PlatformFramework.WatchOS:
                case PlatformFramework.TVOS:
                    minimumOSVersion = IPhoneSdkVersion.UseDefault;
                    break;

                default:
                    throw new InvalidOperationException(string.Format("Invalid framework: {0}", Framework));
                }
            }

            Directory.CreateDirectory(AppBundleDir);

            var mtouchExecution = base.Execute();

            try {
                var nativeLibrariesPath = Directory.EnumerateFiles(AppBundleDir, "*.dylib", SearchOption.AllDirectories);
                var nativeLibraryItems  = new List <ITaskItem> ();

                foreach (var nativeLibrary in nativeLibrariesPath)
                {
                    nativeLibraryItems.Add(new TaskItem(nativeLibrary));
                }

                NativeLibraries = nativeLibraryItems.ToArray();
            } catch (Exception ex) {
                Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "Could not get native libraries: {0}", ex.Message);
                return(false);
            }

            return(mtouchExecution);
        }
Exemple #25
0
		//-------------------------------------------------------------------------------------
		private void DrawMultiSort()
		{
			try
			{
				if(this.DataSource == null)
					return;
				if((this.DataSource as IBindingListView) == null)
					return;
				if(((IBindingListView)DataSource).SupportsAdvancedSorting == false)
					return;

				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);

				foreach(DataGridViewColumn col in this.Columns)
					if(sl.ContainsKey(col.Name))
					{
						if(sl[col.Name].SortDirection == ListSortDirection.Ascending)
							col.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
						else
							col.HeaderCell.SortGlyphDirection = SortOrder.Descending;
					}
					else if(sl.ContainsKey(col.DataPropertyName))
					{
						if(sl[col.DataPropertyName].SortDirection == ListSortDirection.Ascending)
							col.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
						else
							col.HeaderCell.SortGlyphDirection = SortOrder.Descending;
					}
					else if(col.HeaderCell.SortGlyphDirection != SortOrder.None)
						col.HeaderCell.SortGlyphDirection = SortOrder.None;
			}
			catch
			{
			}
		}
        void ValidateWatchApp(string path, string mainBundleIdentifier, string mainShortVersionString, string mainVersion)
        {
            var name = Path.GetFileNameWithoutExtension(path);
            var info = Path.Combine(path, "Info.plist");

            if (!File.Exists(info))
            {
                Log.MTError(7014, $"The Watch App '{name}' does not contain an Info.plist.");
                return;
            }

            var plist            = PDictionary.FromFile(info);
            var bundleIdentifier = plist.GetCFBundleIdentifier();

            if (string.IsNullOrEmpty(bundleIdentifier))
            {
                Log.MTError(7015, $"The Watch App '{name}' does not specify a CFBundleIdentifier.");
                return;
            }

            if (!bundleIdentifier.StartsWith(mainBundleIdentifier + ".", StringComparison.Ordinal))
            {
                Log.MTError(7016, $"The Watch App '{name}' has an invalid CFBundleIdentifier ({bundleIdentifier}), it does not begin with the main app bundle's CFBundleIdentifier ({mainBundleIdentifier}).");
            }

            var shortVersionString = plist.GetCFBundleShortVersionString();

            if (string.IsNullOrEmpty(shortVersionString))
            {
                Log.LogWarning("The Watch App '{0}' does not specify a CFBundleShortVersionString", name);
            }

            if (shortVersionString != mainShortVersionString)
            {
                Log.LogWarning("The Watch App '{0}' has a CFBundleShortVersionString ({1}) that does not match the main app bundle's CFBundleShortVersionString ({2})", name, shortVersionString, mainShortVersionString);
            }

            var version = plist.GetCFBundleVersion();

            if (string.IsNullOrEmpty(version))
            {
                Log.LogWarning("The Watch App '{0}' does not specify a CFBundleVersion", name);
            }

            if (version != mainVersion)
            {
                Log.LogWarning("The Watch App '{0}' has a CFBundleVersion ({1}) that does not match the main app bundle's CFBundleVersion ({2})", name, version, mainVersion);
            }

            var watchDeviceFamily = plist.GetUIDeviceFamily();

            if (watchDeviceFamily != IPhoneDeviceType.Watch)
            {
                Log.MTError(7017, $"The Watch App '{name}' does not have a valid UIDeviceFamily value. Expected 'Watch (4)' but found '{watchDeviceFamily.ToString ()} ({(int)watchDeviceFamily})'.");
            }

            var watchExecutable = plist.GetCFBundleExecutable();

            if (string.IsNullOrEmpty(watchExecutable))
            {
                Log.MTError(7018, $"The Watch App '{name}' does not specify a CFBundleExecutable");
            }

            var wkCompanionAppBundleIdentifier = plist.GetString("WKCompanionAppBundleIdentifier").Value;

            if (wkCompanionAppBundleIdentifier != mainBundleIdentifier)
            {
                Log.MTError(7019, $"The Watch App '{name}' has an invalid WKCompanionAppBundleIdentifier value ('{wkCompanionAppBundleIdentifier}'), it does not match the main app bundle's CFBundleIdentifier ('{mainBundleIdentifier}').");
            }

            PBoolean watchKitApp;

            if (!plist.TryGetValue("WKWatchKitApp", out watchKitApp) || !watchKitApp.Value)
            {
                Log.MTError(7020, $"The Watch App '{name}' has an invalid Info.plist: the WKWatchKitApp key must be present and have a value of 'true'.");
            }

            if (plist.ContainsKey("LSRequiresIPhoneOS"))
            {
                Log.MTError(7021, $"The Watch App '{name}' has an invalid Info.plist: the LSRequiresIPhoneOS key must not be present.");
            }

            var pluginsDir = Path.Combine(path, "PlugIns");

            if (!Directory.Exists(pluginsDir))
            {
                Log.MTError(7022, $"The Watch App '{name}' does not contain any Watch Extensions.");
                return;
            }

            int count = 0;

            foreach (var plugin in Directory.EnumerateDirectories(pluginsDir, "*.appex"))
            {
                ValidateWatchExtension(plugin, bundleIdentifier, shortVersionString, version);
                count++;
            }

            if (count == 0)
            {
                Log.MTError(7022, $"The Watch App '{name}' does not contain a Watch Extension.");
            }
        }
        protected override string GenerateCommandLineCommands()
        {
            var args = GenerateCommandLineArguments();

            if (!string.IsNullOrEmpty(OutputPath))
            {
                args.AddQuotedLine("/output:" + Path.GetFullPath(OutputPath));
            }

            if (!string.IsNullOrEmpty(ApplicationName))
            {
                args.AddQuotedLine("/name:" + ApplicationName);
            }

            args.AddLine($"/profile:{TargetFrameworkMoniker}");

            XamMacArch arch;

            if (!Enum.TryParse(Architecture, true, out arch))
            {
                arch = XamMacArch.Default;
            }

            if (arch == XamMacArch.Default)
            {
                arch = XamMacArch.x86_64;
            }

            if (arch.HasFlag(XamMacArch.i386))
            {
                args.AddLine("/arch:i386");
            }

            if (arch.HasFlag(XamMacArch.x86_64))
            {
                args.AddLine("/arch:x86_64");
            }

            if (AppManifest != null)
            {
                try {
                    var plist = PDictionary.FromFile(AppManifest.ItemSpec);

                    PString v;
                    string  minimumDeploymentTarget;

                    if (!plist.TryGetValue(ManifestKeys.LSMinimumSystemVersion, out v) || string.IsNullOrEmpty(v.Value))
                    {
                        minimumDeploymentTarget = SdkVersion;
                    }
                    else
                    {
                        minimumDeploymentTarget = v.Value;
                    }

                    args.AddLine(string.Format("/minos={0}", minimumDeploymentTarget));
                }
                catch (Exception ex) {
                    Log.LogWarning(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, MSBStrings.E0010, AppManifest.ItemSpec, ex.Message);
                }
            }

            switch ((LinkMode ?? string.Empty).ToLower())
            {
            case "full":
                break;

            case "sdkonly":
                args.AddLine("/linksdkonly");
                break;

            case "platform":
                args.AddLine("/linkplatform");
                break;

            default:
                args.AddLine("/nolink");
                break;
            }

            if (!string.IsNullOrEmpty(AotMode) && AotMode != "None")
            {
                var aot = $"--aot:{AotMode.ToLower ()}";
                if (HybridAOT)
                {
                    aot += "|hybrid";
                }

                if (!string.IsNullOrEmpty(ExplicitAotAssemblies))
                {
                    aot += $",{ExplicitAotAssemblies}";
                }

                args.AddLine(aot);
            }

            if (References != null)
            {
                foreach (var asm in References)
                {
                    args.AddQuotedLine("/assembly:" + Path.GetFullPath(asm.ItemSpec));
                }
            }

            if (NativeReferences != null)
            {
                foreach (var nr in NativeReferences)
                {
                    args.AddQuotedLine("/native-reference:" + Path.GetFullPath(nr.ItemSpec));
                }
            }

            if (IsAppExtension)
            {
                args.AddQuotedLine("/extension");
            }
            if (IsXPCService)
            {
                args.AddQuotedLine("/xpc");
            }

            return(CreateResponseFile(args, ExtraArgs == null ? null : CommandLineArgumentBuilder.Parse(ExtraArgs)));
        }
        void ValidateWatchExtension(string path, string watchAppBundleIdentifier, string mainShortVersionString, string mainVersion)
        {
            var name = Path.GetFileNameWithoutExtension(path);
            var info = Path.Combine(path, "Info.plist");

            if (!File.Exists(info))
            {
                Log.MTError(7023, $"The Watch Extension '{name}' does not contain an Info.plist.");
                return;
            }

            var plist = PDictionary.FromFile(info);

            var bundleIdentifier = plist.GetCFBundleIdentifier();

            if (string.IsNullOrEmpty(bundleIdentifier))
            {
                Log.MTError(7024, $"The Watch Extension '{name}' does not specify a CFBundleIdentifier.");
                return;
            }

            // The filename of the extension path is the extension's bundle identifier, which turns out ugly
            // in error messages. Try to get something more friendly-looking.
            name = plist.GetCFBundleDisplayName() ?? name;

            var executable = plist.GetCFBundleExecutable();

            if (string.IsNullOrEmpty(executable))
            {
                Log.MTError(7025, $"The Watch Extension '{name}' does not specify a CFBundleExecutable.");
            }

            if (!bundleIdentifier.StartsWith(watchAppBundleIdentifier + ".", StringComparison.Ordinal))
            {
                Log.MTError(7026, $"The Watch Extension '{name}' has an invalid CFBundleIdentifier ({bundleIdentifier}), it does not begin with the main app bundle's CFBundleIdentifier ({watchAppBundleIdentifier}).");
            }

            if (bundleIdentifier.EndsWith(".key", StringComparison.Ordinal))
            {
                Log.MTError(7027, $"The Watch Extension '{name}' has a CFBundleIdentifier ({bundleIdentifier}) that ends with the illegal suffix \".key\".");
            }

            var shortVersionString = plist.GetCFBundleShortVersionString();

            if (string.IsNullOrEmpty(shortVersionString))
            {
                Log.LogWarning("The Watch Extension '{0}' does not specify a CFBundleShortVersionString", name);
            }

            if (shortVersionString != mainShortVersionString)
            {
                Log.LogWarning("The Watch Extension '{0}' has a CFBundleShortVersionString ({1}) that does not match the main app bundle's CFBundleShortVersionString ({2})", name, shortVersionString, mainShortVersionString);
            }

            var version = plist.GetCFBundleVersion();

            if (string.IsNullOrEmpty(version))
            {
                Log.LogWarning("The Watch Extension '{0}' does not specify a CFBundleVersion", name);
            }

            if (version != mainVersion)
            {
                Log.LogWarning("The Watch Extension '{0}' has a CFBundleVersion ({1}) that does not match the main app bundle's CFBundleVersion ({2})", name, version, mainVersion);
            }

            var extension = plist.Get <PDictionary> ("NSExtension");

            if (extension == null)
            {
                Log.MTError(7028, $"The Watch Extension '{name}' has an invalid Info.plist: it does not contain an NSExtension dictionary.");
                return;
            }

            var extensionPointIdentifier = extension.Get <PString> ("NSExtensionPointIdentifier");

            if (extensionPointIdentifier != null)
            {
                if (extensionPointIdentifier.Value != "com.apple.watchkit")
                {
                    Log.MTError(7029, $"The Watch Extension '{name}' has an invalid Info.plist: the NSExtensionPointIdentifier must be \"com.apple.watchkit\".");
                }
            }
            else
            {
                Log.MTError(7029, $"The Watch Extension '{name}' has an invalid Info.plist: the NSExtension dictionary must contain an NSExtensionPointIdentifier.");
            }

            PDictionary attributes;

            if (!extension.TryGetValue("NSExtensionAttributes", out attributes))
            {
                Log.MTError(7030, $"The Watch Extension '{name}' has an invalid Info.plist: the NSExtension dictionary must contain NSExtensionAttributes.");
                return;
            }

            var appBundleIdentifier = attributes.Get <PString> ("WKAppBundleIdentifier");

            if (appBundleIdentifier != null)
            {
                if (appBundleIdentifier.Value != watchAppBundleIdentifier)
                {
                    Log.MTError(7031, $"The Watch Extension '{name}' has an invalid WKAppBundleIdentifier value ('{appBundleIdentifier.Value}'), it does not match the parent Watch App bundle's CFBundleIdentifier ('{watchAppBundleIdentifier}').");
                }
            }
            else
            {
                Log.MTError(7031, $"The Watch Extension '{name}' has an invalid Info.plist: the NSExtensionAttributes dictionary must contain a WKAppBundleIdentifier.");
            }

            PObject requiredDeviceCapabilities;

            if (plist.TryGetValue("UIRequiredDeviceCapabilities", out requiredDeviceCapabilities))
            {
                var requiredDeviceCapabilitiesDictionary = requiredDeviceCapabilities as PDictionary;
                var requiredDeviceCapabilitiesArray      = requiredDeviceCapabilities as PArray;

                if (requiredDeviceCapabilitiesDictionary != null)
                {
                    PBoolean watchCompanion;

                    if (requiredDeviceCapabilitiesDictionary.TryGetValue("watch-companion", out watchCompanion))
                    {
                        Log.MTError(7032, $"The WatchKit Extension '{name}' has an invalid Info.plist: the UIRequiredDeviceCapabilities dictionary should not contain the 'watch-companion' capability.");
                    }
                }
                else if (requiredDeviceCapabilitiesArray != null)
                {
                    if (requiredDeviceCapabilitiesArray.OfType <PString> ().Any(x => x.Value == "watch-companion"))
                    {
                        Log.MTError(7032, $"The WatchKit Extension '{name}' has an invalid Info.plist: the UIRequiredDeviceCapabilities array should not contain the 'watch-companion' capability.");
                    }
                }
            }
        }
Exemple #29
0
        static PDictionary GetArchivedExpandedEntitlements(PDictionary template, PDictionary compiled)
        {
            var allowed = new HashSet<string> ();

            // the template (user-supplied Entitlements.plist file) is used to create a whitelist of keys
            allowed.Add ("com.apple.developer.icloud-container-environment");
            foreach (var item in template)
                allowed.Add (item.Key);

            // now we duplicate the allowed keys from the compiled xcent file
            var archived = new PDictionary ();

            foreach (var item in compiled) {
                if (allowed.Contains (item.Key))
                    archived.Add (item.Key, item.Value.Clone ());
            }

            return archived;
        }
        void ValidateAppExtension(string path, string mainBundleIdentifier, string mainShortVersionString, string mainVersion)
        {
            var name = Path.GetFileNameWithoutExtension(path);
            var info = Path.Combine(path, "Info.plist");

            if (!File.Exists(info))
            {
                Log.MTError(7003, $"The App Extension '{name}' does not contain an Info.plist.");
                return;
            }

            var plist = PDictionary.FromFile(info);

            var bundleIdentifier = plist.GetCFBundleIdentifier();

            if (string.IsNullOrEmpty(bundleIdentifier))
            {
                Log.MTError(7004, $"The App Extension '{name}' does not specify a CFBundleIdentifier.");
                return;
            }

            // The filename of the extension path is the extension's bundle identifier, which turns out ugly
            // in error messages. Try to get something more friendly-looking.
            name = plist.GetCFBundleDisplayName() ?? name;

            var executable = plist.GetCFBundleExecutable();

            if (string.IsNullOrEmpty(executable))
            {
                Log.MTError(7005, $"The App Extension '{name}' does not specify a CFBundleExecutable.");
            }

            if (!bundleIdentifier.StartsWith(mainBundleIdentifier + ".", StringComparison.Ordinal))
            {
                Log.MTError(7006, $"The App Extension '{name}' has an invalid CFBundleIdentifier ({bundleIdentifier}), it does not begin with the main app bundle's CFBundleIdentifier ({mainBundleIdentifier}).");
            }

            if (bundleIdentifier.EndsWith(".key", StringComparison.Ordinal))
            {
                Log.MTError(7007, $"The App Extension '{name}' has a CFBundleIdentifier ({bundleIdentifier}) that ends with the illegal suffix \".key\".");
            }

            var shortVersionString = plist.GetCFBundleShortVersionString();

            if (string.IsNullOrEmpty(shortVersionString))
            {
                Log.MTError(7008, $"The App Extension '{name}' does not specify a CFBundleShortVersionString.");
            }

            if (shortVersionString != mainShortVersionString)
            {
                Log.LogWarning("The App Extension '{0}' has a CFBundleShortVersionString ({1}) that does not match the main app bundle's CFBundleShortVersionString ({2})", name, shortVersionString, mainShortVersionString);
            }

            var version = plist.GetCFBundleVersion();

            if (string.IsNullOrEmpty(version))
            {
                Log.LogWarning("The App Extension '{0}' does not specify a CFBundleVersion", name);
            }

            if (version != mainVersion)
            {
                Log.LogWarning("The App Extension '{0}' has a CFBundleVersion ({1}) that does not match the main app bundle's CFBundleVersion ({2})", name, version, mainVersion);
            }

            var extension = plist.Get <PDictionary> ("NSExtension");

            if (extension == null)
            {
                Log.MTError(7009, $"The App Extension '{name}' has an invalid Info.plist: it does not contain an NSExtension dictionary.");
                return;
            }

            var extensionPointIdentifier = extension.GetString("NSExtensionPointIdentifier").Value;

            if (string.IsNullOrEmpty(extensionPointIdentifier))
            {
                Log.MTError(7010, $"The App Extension '{name}' has an invalid Info.plist: the NSExtension dictionary does not contain an NSExtensionPointIdentifier value.");
                return;
            }

            // https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/SystemExtensionKeys.html#//apple_ref/doc/uid/TP40014212-SW9
            switch (extensionPointIdentifier)
            {
            case "com.apple.ui-services":                         // iOS+OSX
            case "com.apple.services":                            // iOS
            case "com.apple.keyboard-service":                    // iOS
            case "com.apple.fileprovider-ui":                     // iOS
            case "com.apple.fileprovider-nonui":                  // iOS
            case "com.apple.FinderSync":                          // OSX
            case "com.apple.photo-editing":                       // iOS
            case "com.apple.share-services":                      // iOS+OSX
            case "com.apple.widget-extension":                    // iOS+OSX
            case "com.apple.Safari.content-blocker":              // iOS
            case "com.apple.Safari.sharedlinks-service":          // iOS
            case "com.apple.spotlight.index":                     // iOS
            case "com.apple.AudioUnit-UI":                        // iOS
            case "com.apple.tv-services":                         // tvOS
            case "com.apple.broadcast-services":                  // iOS+tvOS
            case "com.apple.callkit.call-directory":              // iOS
            case "com.apple.message-payload-provider":            // iOS
            case "com.apple.intents-service":                     // iOS
            case "com.apple.intents-ui-service":                  // iOS
            case "com.apple.usernotifications.content-extension": // iOS
            case "com.apple.usernotifications.service":           // iOS
            case "com.apple.networkextension.packet-tunnel":      // iOS+OSX
                break;

            case "com.apple.watchkit":             // iOS8.2
                var attributes = extension.Get <PDictionary> ("NSExtensionAttributes");

                if (attributes == null)
                {
                    Log.MTError(7011, $"The WatchKit Extension '{name}' has an invalid Info.plist: the NSExtension dictionary does not contain an NSExtensionAttributes dictionary.");
                    return;
                }

                var wkAppBundleIdentifier = attributes.GetString("WKAppBundleIdentifier").Value;
                var apps = Directory.GetDirectories(path, "*.app");
                if (apps.Length == 0)
                {
                    Log.MTError(7012, $"The WatchKit Extension '{name}' does not contain any watch apps.");
                }
                else if (apps.Length > 1)
                {
                    Log.MTError(7012, $"The WatchKit Extension '{name}' contain more than one watch apps.");
                }
                else
                {
                    PObject requiredDeviceCapabilities;

                    if (plist.TryGetValue("UIRequiredDeviceCapabilities", out requiredDeviceCapabilities))
                    {
                        var requiredDeviceCapabilitiesDictionary = requiredDeviceCapabilities as PDictionary;
                        var requiredDeviceCapabilitiesArray      = requiredDeviceCapabilities as PArray;

                        if (requiredDeviceCapabilitiesDictionary != null)
                        {
                            PBoolean watchCompanion;

                            if (!requiredDeviceCapabilitiesDictionary.TryGetValue("watch-companion", out watchCompanion) || !watchCompanion.Value)
                            {
                                Log.MTError(7013, $"The WatchKit Extension '{name}' has an invalid Info.plist: the UIRequiredDeviceCapabilities dictionary must contain the 'watch-companion' capability with a value of 'true'.");
                            }
                        }
                        else if (requiredDeviceCapabilitiesArray != null)
                        {
                            if (!requiredDeviceCapabilitiesArray.OfType <PString> ().Any(x => x.Value == "watch-companion"))
                            {
                                Log.MTError(7013, $"The WatchKit Extension '{name}' has an invalid Info.plist: the UIRequiredDeviceCapabilities array must contain the 'watch-companion' capability.");
                            }
                        }
                        else
                        {
                            Log.MTError(7013, $"The WatchKit Extension '{name}' has an invalid Info.plist: the UIRequiredDeviceCapabilities key must be present and contain the 'watch-companion' capability.");
                        }
                    }
                    else
                    {
                        Log.MTError(7013, $"The WatchKit Extension '{name}' has an invalid Info.plist: the UIRequiredDeviceCapabilities key must be present and contain the 'watch-companion' capability.");
                    }

                    ValidateWatchOS1App(apps[0], name, mainBundleIdentifier, wkAppBundleIdentifier);
                }
                break;

            default:
                Log.LogWarning("The App Extension '{0}' has an unrecognized NSExtensionPointIdentifier value ('{1}').", name, extensionPointIdentifier);
                break;
            }
        }
Exemple #31
0
        public override bool Execute()
        {
            var intermediate = Path.Combine (IntermediateOutputPath, ToolName);
            var intermediateBundleDir = Path.Combine (intermediate, "bundle");
            var manifest = new TaskItem (Path.Combine (intermediate, "asset-manifest.plist"));
            var bundleResources = new List<ITaskItem> ();
            var outputManifests = new List<ITaskItem> ();
            var catalogs = new List<ITaskItem> ();
            var unique = new HashSet<string> ();
            string bundleIdentifier = null;
            var knownSpecs = new HashSet<string> ();
            var specs = new PArray ();
            int rc;

            Log.LogTaskName ("ACTool");
            Log.LogTaskProperty ("AppManifest", AppManifest);
            Log.LogTaskProperty ("DeviceModel", DeviceModel);
            Log.LogTaskProperty ("DeviceOSVersion", DeviceOSVersion);
            Log.LogTaskProperty ("ImageAssets", ImageAssets);
            Log.LogTaskProperty ("IntermediateOutputPath", IntermediateOutputPath);
            Log.LogTaskProperty ("IsWatchApp", IsWatchApp);
            Log.LogTaskProperty ("OptimizePNGs", OptimizePNGs);
            Log.LogTaskProperty ("OutputPath", OutputPath);
            Log.LogTaskProperty ("ProjectDir", ProjectDir);
            Log.LogTaskProperty ("ResourcePrefix", ResourcePrefix);
            Log.LogTaskProperty ("SdkBinPath", SdkBinPath);
            Log.LogTaskProperty ("SdkPlatform", SdkPlatform);
            Log.LogTaskProperty ("SdkVersion", SdkVersion);

            switch (SdkPlatform) {
            case "iPhoneSimulator":
            case "iPhoneOS":
            case "MacOSX":
            case "WatchSimulator":
            case "WatchOS":
            case "AppleTVSimulator":
            case "AppleTVOS":
                break;
            default:
                Log.LogError ("Unrecognized platform: {0}", SdkPlatform);
                return false;
            }

            if (AppManifest != null) {
                try {
                    plist = PDictionary.FromFile (AppManifest.ItemSpec);
                } catch (Exception ex) {
                    Log.LogError (null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "{0}", ex.Message);
                    return false;
                }

                bundleIdentifier = plist.GetCFBundleIdentifier ();
            }

            foreach (var asset in ImageAssets) {
                var vpath = BundleResource.GetVirtualProjectPath (ProjectDir, asset);
                if (Path.GetFileName (vpath) != "Contents.json")
                    continue;

                // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc)
                var catalog = Path.GetDirectoryName (vpath);

                // keep walking up the directory structure until we get to the .xcassets directory
                while (!string.IsNullOrEmpty (catalog) && Path.GetExtension (catalog) != ".xcassets")
                    catalog = Path.GetDirectoryName (catalog);

                if (string.IsNullOrEmpty (catalog)) {
                    Log.LogWarning (null, null, null, asset.ItemSpec, 0, 0, 0, 0, "Asset not part of an asset catalog: {0}", asset.ItemSpec);
                    continue;
                }

                if (unique.Add (catalog))
                    catalogs.Add (new TaskItem (catalog));

                if (AppleSdkSettings.XcodeVersion.Major >= 7 && !string.IsNullOrEmpty (bundleIdentifier) && SdkPlatform != "WatchSimulator") {
                    var text = File.ReadAllText (asset.ItemSpec);

                    if (string.IsNullOrEmpty (text))
                        continue;

                    var json = JsonConvert.DeserializeObject (text) as JObject;

                    if (json == null)
                        continue;

                    var properties = json.Property ("properties");

                    if (properties == null)
                        continue;

                    var resourceTags = properties.Value.ToObject<JObject> ().Property ("on-demand-resource-tags");

                    if (resourceTags == null || resourceTags.Value.Type != JTokenType.Array)
                        continue;

                    var tagArray = resourceTags.Value.ToObject<JArray> ();
                    var tags = new HashSet<string> ();
                    string hash;

                    foreach (var tag in tagArray.Select (token => token.ToObject<string> ()))
                        tags.Add (tag);

                    var tagList = tags.ToList ();
                    tagList.Sort ();

                    var path = AssetPackUtils.GetAssetPackDirectory (intermediate, bundleIdentifier, tagList, out hash);

                    if (knownSpecs.Add (hash)) {
                        var assetpack = new PDictionary ();
                        var ptags = new PArray ();

                        Directory.CreateDirectory (path);

                        for (int i = 0; i < tags.Count; i++)
                            ptags.Add (new PString (tagList[i]));

                        assetpack.Add ("bundle-id", new PString (string.Format ("{0}.asset-pack-{1}", bundleIdentifier, hash)));
                        assetpack.Add ("bundle-path", new PString (Path.GetFullPath (path)));
                        assetpack.Add ("tags", ptags);
                        specs.Add (assetpack);
                    }
                }
            }

            if (catalogs.Count == 0) {
                // There are no (supported?) asset catalogs
                return true;
            }

            partialAppManifest = new TaskItem (Path.Combine (intermediate, "partial-info.plist"));

            if (specs.Count > 0) {
                outputSpecs = Path.Combine (intermediate, "output-specifications.plist");
                specs.Save (outputSpecs, true);
            }

            var output = new TaskItem (intermediateBundleDir);

            Directory.CreateDirectory (intermediateBundleDir);

            // Note: Compile() will set the PartialAppManifest property if it is used...
            if ((rc = Compile (catalogs.ToArray (), output, manifest)) != 0) {
                if (File.Exists (manifest.ItemSpec)) {
                    try {
                        var log = PDictionary.FromFile (manifest.ItemSpec);

                        LogWarningsAndErrors (log, catalogs[0]);
                    } catch (FormatException) {
                        Log.LogError ("actool exited with code {0}", rc);
                    }

                    File.Delete (manifest.ItemSpec);
                }

                return false;
            }

            if (PartialAppManifest != null && !File.Exists (PartialAppManifest.GetMetadata ("FullPath")))
                Log.LogError ("Partial Info.plist file was not generated: {0}", PartialAppManifest.GetMetadata ("FullPath"));

            try {
                var manifestOutput = PDictionary.FromFile (manifest.ItemSpec);

                LogWarningsAndErrors (manifestOutput, catalogs[0]);

                bundleResources.AddRange (GetCompiledBundleResources (manifestOutput, intermediateBundleDir));
                outputManifests.Add (manifest);
            } catch (Exception ex) {
                Log.LogError ("Failed to load output manifest for {0} for the file {2}: {1}", ToolName, ex.Message, manifest.ItemSpec);
            }

            foreach (var assetpack in specs.OfType<PDictionary> ()) {
                var path = Path.Combine (assetpack.GetString ("bundle-path").Value, "Info.plist");
                var bundlePath = PathUtils.AbsoluteToRelative (intermediate, path);
                var outputPath = Path.Combine (OutputPath, bundlePath);
                var rpath = Path.Combine (intermediate, bundlePath);
                var dict = new PDictionary ();

                dict.SetCFBundleIdentifier (assetpack.GetString ("bundle-id").Value);
                dict.Add ("Tags", assetpack.GetArray ("tags").Clone ());

                dict.Save (path, true, true);

                var item = new TaskItem (rpath);
                item.SetMetadata ("LogicalName", bundlePath);
                item.SetMetadata ("OutputPath", outputPath);
                item.SetMetadata ("Optimize", "false");

                bundleResources.Add (item);
            }

            BundleResources = bundleResources.ToArray ();
            OutputManifests = outputManifests.ToArray ();

            return !Log.HasLoggedErrors;
        }
        void ValidateWatchOS1App(string path, string extensionName, string mainBundleIdentifier, string wkAppBundleIdentifier)
        {
            var name = Path.GetFileNameWithoutExtension(path);
            var info = Path.Combine(path, "Info.plist");

            if (!File.Exists(info))
            {
                Log.MTError(7033, $"The Watch App '{name}' does not contain an Info.plist.");
                return;
            }

            var plist            = PDictionary.FromFile(info);
            var bundleIdentifier = plist.GetCFBundleIdentifier();

            if (string.IsNullOrEmpty(bundleIdentifier))
            {
                Log.MTError(7034, $"The Watch App '{name}' does not specify a CFBundleIdentifier.");
                return;
            }

            var deviceFamily = plist.GetUIDeviceFamily();
            IPhoneDeviceType expectedDeviceFamily;
            string           expectedDeviceFamilyString;

            if (SdkIsSimulator)
            {
                expectedDeviceFamily       = IPhoneDeviceType.Watch | IPhoneDeviceType.IPhone;
                expectedDeviceFamilyString = "IPhone, Watch (1, 4)";
            }
            else
            {
                expectedDeviceFamily       = IPhoneDeviceType.Watch;
                expectedDeviceFamilyString = "Watch (4)";
            }

            if (deviceFamily != expectedDeviceFamily)
            {
                Log.MTError(7035, $"The Watch App '{name}' does not have a valid UIDeviceFamily value. Expected '{expectedDeviceFamilyString}' but found '{deviceFamily.ToString ()} ({(int)deviceFamily})'.");
            }

            var executable = plist.GetCFBundleExecutable();

            if (string.IsNullOrEmpty(executable))
            {
                Log.MTError(7036, $"The Watch App '{name}' does not specify a CFBundleExecutable.");
            }

            if (bundleIdentifier != wkAppBundleIdentifier)
            {
                Log.MTError(7037, $"The WatchKit Extension '{extensionName}' has an invalid WKAppBundleIdentifier value ('{wkAppBundleIdentifier}'), it does not match the Watch App's CFBundleIdentifier ('{bundleIdentifier}').");
            }

            var companionAppBundleIdentifier = plist.Get <PString> ("WKCompanionAppBundleIdentifier");

            if (companionAppBundleIdentifier != null)
            {
                if (companionAppBundleIdentifier.Value != mainBundleIdentifier)
                {
                    Log.MTError(7038, $"The Watch App '{name}' has an invalid WKCompanionAppBundleIdentifier value ('{companionAppBundleIdentifier.Value}'), it does not match the main app bundle's CFBundleIdentifier ('{mainBundleIdentifier}').");
                }
            }
            else
            {
                Log.MTError(7038, $"The Watch App '{name}' has an invalid Info.plist: the WKCompanionAppBundleIdentifier must exist and must match the main app bundle's CFBundleIdentifier.");
            }

            if (plist.ContainsKey("LSRequiresIPhoneOS"))
            {
                Log.MTError(7039, $"The Watch App '{name}' has an invalid Info.plist: the LSRequiresIPhoneOS key must not be present.");
            }
        }
Exemple #33
0
        protected void LogWarningsAndErrors(PDictionary plist, ITaskItem file)
        {
            PDictionary dictionary;
            PString message;
            PArray array;

            if (plist.TryGetValue (string.Format ("com.apple.{0}.document.notices", ToolName), out array)) {
                foreach (var item in array.OfType<PDictionary> ()) {
                    if (item.TryGetValue ("message", out message))
                        Log.LogMessage (MessageImportance.Low, "{0}", message.Value);
                }
            }

            if (plist.TryGetValue (string.Format ("com.apple.{0}.document.warnings", ToolName), out array)) {
                foreach (var item in array.OfType<PDictionary> ()) {
                    if (item.TryGetValue ("message", out message))
                        Log.LogWarning (ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                }
            }

            if (plist.TryGetValue (string.Format ("com.apple.{0}.document.errors", ToolName), out array)) {
                foreach (var item in array.OfType<PDictionary> ()) {
                    if (item.TryGetValue ("message", out message))
                        Log.LogError (ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                }
            }

            //Trying to parse document warnings and erros using a PDictionary first since it's what ibtool is returning when building a storyboard.
            if (plist.TryGetValue (string.Format ("com.apple.{0}.document.notices", ToolName), out dictionary)) {
                foreach (var valuePair in dictionary) {
                    array = valuePair.Value as PArray;
                    foreach (var item in array.OfType<PDictionary> ()) {
                        if (item.TryGetValue ("message", out message))
                            Log.LogMessage (MessageImportance.Low, "{0}", message.Value);
                    }
                }
            }

            if (plist.TryGetValue (string.Format ("com.apple.{0}.document.warnings", ToolName), out dictionary)) {
                foreach (var valuePair in dictionary) {
                    array = valuePair.Value as PArray;
                    foreach (var item in array.OfType<PDictionary> ()) {
                        if (item.TryGetValue ("message", out message))
                            Log.LogWarning (ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                    }
                }
            }

            if (plist.TryGetValue (string.Format ("com.apple.{0}.document.errors", ToolName), out dictionary)) {
                foreach (var valuePair in dictionary) {
                    array = valuePair.Value as PArray;
                    foreach (var item in array.OfType<PDictionary> ()) {
                        if (item.TryGetValue ("message", out message))
                            Log.LogError (ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                    }
                }
            }

            if (plist.TryGetValue (string.Format ("com.apple.{0}.errors", ToolName), out array)) {
                foreach (var item in array.OfType<PDictionary> ()) {
                    if (item.TryGetValue ("description", out message))
                        Log.LogError (ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                }
            }

            if (plist.TryGetValue (string.Format ("com.apple.{0}.notices", ToolName), out array)) {
                foreach (var item in array.OfType<PDictionary> ()) {
                    if (item.TryGetValue ("description", out message))
                        Log.LogError (ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                }
            }
        }
        public override bool Execute()
        {
            Log.LogTaskName("ValidateAppBundle");
            Log.LogTaskProperty("AppBundlePath", Path.GetFullPath(AppBundlePath));
            Log.LogTaskProperty("SdkIsSimulator", SdkIsSimulator);
            Log.LogTaskProperty("TargetFrameworkIdentifier", TargetFrameworkIdentifier);

            var mainInfoPath = Path.Combine(AppBundlePath, "Info.plist");

            if (!File.Exists(mainInfoPath))
            {
                Log.MTError(7040, $"The app bundle {AppBundlePath} does not contain an Info.plist.");
                return(false);
            }

            var plist = PDictionary.FromFile(mainInfoPath);

            var bundleIdentifier = plist.GetCFBundleIdentifier();

            if (string.IsNullOrEmpty(bundleIdentifier))
            {
                Log.MTError(7041, $"{mainInfoPath} does not specify a CFBundleIdentifier.");
                return(false);
            }

            var executable = plist.GetCFBundleExecutable();

            if (string.IsNullOrEmpty(executable))
            {
                Log.MTError(7042, $"{mainInfoPath} does not specify a CFBundleExecutable.");
            }

            var supportedPlatforms = plist.GetArray(ManifestKeys.CFBundleSupportedPlatforms);
            var platform           = string.Empty;

            if (supportedPlatforms == null || supportedPlatforms.Count == 0)
            {
                Log.MTError(7043, $"{mainInfoPath} does not specify a CFBundleSupportedPlatforms.");
            }
            else
            {
                platform = (PString)supportedPlatforms[0];
            }

            // Validate UIDeviceFamily
            var deviceTypes    = plist.GetUIDeviceFamily();
            var deviceFamilies = deviceTypes.ToDeviceFamily();

            AppleDeviceFamily[] validFamilies = null;

            switch (Framework)
            {
            case PlatformFramework.iOS:
                validFamilies = new AppleDeviceFamily[] {
                    AppleDeviceFamily.IPhone,
                    AppleDeviceFamily.IPad,
                    AppleDeviceFamily.Watch
                };
                break;

            case PlatformFramework.WatchOS:
                validFamilies = new AppleDeviceFamily[] { AppleDeviceFamily.Watch };
                break;

            case PlatformFramework.TVOS:
                validFamilies = new AppleDeviceFamily[] { AppleDeviceFamily.TV };
                break;

            default:
                Log.LogError("Invalid framework: {0}", Framework);
                break;
            }

            if (validFamilies != null)
            {
                if (validFamilies.Length == 0)
                {
                    Log.MTError(7044, $"{mainInfoPath} does not specify a UIDeviceFamily.");
                }
                else
                {
                    foreach (var family in deviceFamilies)
                    {
                        if (Array.IndexOf(validFamilies, family) == -1)
                        {
                            Log.MTError(7044, $"{mainInfoPath} is invalid: the UIDeviceFamily key must contain a value for '{family}'.");
                        }
                    }
                }
            }

            var mainShortVersionString = plist.GetCFBundleShortVersionString();
            var mainVersion            = plist.GetCFBundleVersion();

            if (Directory.Exists(Path.Combine(AppBundlePath, "PlugIns")))
            {
                foreach (var plugin in Directory.GetDirectories(Path.Combine(AppBundlePath, "PlugIns"), "*.appex"))
                {
                    ValidateAppExtension(plugin, bundleIdentifier, mainShortVersionString, mainVersion);
                }
            }

            if (Directory.Exists(Path.Combine(AppBundlePath, "Watch")))
            {
                foreach (var watchApp in Directory.GetDirectories(Path.Combine(AppBundlePath, "Watch"), "*.app"))
                {
                    ValidateWatchApp(watchApp, bundleIdentifier, mainShortVersionString, mainVersion);
                }
            }

            return(!Log.HasLoggedErrors);
        }
Exemple #35
0
        static bool IsWatchAppExtension(ITaskItem appex, PDictionary plist, out string watchAppBundleDir)
        {
            PString     expectedBundleIdentifier, bundleIdentifier, extensionPoint;
            PDictionary extension, attributes;

            watchAppBundleDir = null;

            if (!plist.TryGetValue("NSExtension", out extension))
            {
                return(false);
            }

            if (!extension.TryGetValue("NSExtensionPointIdentifier", out extensionPoint))
            {
                return(false);
            }

            if (extensionPoint.Value != "com.apple.watchkit")
            {
                return(false);
            }

            // Okay, we've found the WatchKit App Extension...
            if (!extension.TryGetValue("NSExtensionAttributes", out attributes))
            {
                return(false);
            }

            if (!attributes.TryGetValue("WKAppBundleIdentifier", out expectedBundleIdentifier))
            {
                return(false);
            }

            var pwd = PathUtils.ResolveSymbolicLink(Environment.CurrentDirectory);

            // Scan the *.app subdirectories to find the WatchApp bundle...
            foreach (var bundle in Directory.GetDirectories(appex.ItemSpec, "*.app"))
            {
                if (!File.Exists(Path.Combine(bundle, "Info.plist")))
                {
                    continue;
                }

                plist = PDictionary.FromFile(Path.Combine(bundle, "Info.plist"));

                if (!plist.TryGetValue("CFBundleIdentifier", out bundleIdentifier))
                {
                    continue;
                }

                if (bundleIdentifier.Value != expectedBundleIdentifier.Value)
                {
                    continue;
                }

                watchAppBundleDir = PathUtils.AbsoluteToRelative(pwd, PathUtils.ResolveSymbolicLink(bundle));

                return(true);
            }

            return(false);
        }
		void AddNewDictionaryElement (PDictionary dict)
		{
			var values = PListScheme.AvailableKeys (dict, CurrentTree);
			if (values == null) {
				string name = "newProperty";
				while (dict.ContainsKey (name))
					name += "_";
				dict.Add (name, PObject.Create (DefaultNewObjectType));
			} else if (values.Any ()) {
				var value = values.FirstOrDefault ();
				dict.Add (value.Identifier, value.Create ());
			}
		}
Exemple #37
0
        protected void SetValue(PDictionary dict, string key, string value)
        {
            if (dict.ContainsKey (key))
                return;

            if (string.IsNullOrEmpty (value))
                LogAppManifestWarning ("Could not determine value for manifest key '{0}'", key);
            else
                dict[key] = value;
        }
Exemple #38
0
        static bool IsWatchAppExtension(ITaskItem appex, PDictionary plist, out string watchAppBundleDir)
        {
            PString expectedBundleIdentifier, bundleIdentifier, extensionPoint;
            PDictionary extension, attributes;

            watchAppBundleDir = null;

            if (!plist.TryGetValue ("NSExtension", out extension))
                return false;

            if (!extension.TryGetValue ("NSExtensionPointIdentifier", out extensionPoint))
                return false;

            if (extensionPoint.Value != "com.apple.watchkit")
                return false;

            // Okay, we've found the WatchKit App Extension...
            if (!extension.TryGetValue ("NSExtensionAttributes", out attributes))
                return false;

            if (!attributes.TryGetValue ("WKAppBundleIdentifier", out expectedBundleIdentifier))
                return false;

            var pwd = PathUtils.ResolveSymbolicLink (Environment.CurrentDirectory);

            // Scan the *.app subdirectories to find the WatchApp bundle...
            foreach (var bundle in Directory.GetDirectories (appex.ItemSpec, "*.app")) {
                if (!File.Exists (Path.Combine (bundle, "Info.plist")))
                    continue;

                plist = PDictionary.FromFile (Path.Combine (bundle, "Info.plist"));

                if (!plist.TryGetValue ("CFBundleIdentifier", out bundleIdentifier))
                    continue;

                if (bundleIdentifier.Value != expectedBundleIdentifier.Value)
                    continue;

                watchAppBundleDir = PathUtils.AbsoluteToRelative (pwd, PathUtils.ResolveSymbolicLink (bundle));

                return true;
            }

            return false;
        }
Exemple #39
0
        protected void MergePartialPlistTemplates(PDictionary plist)
        {
            if (PartialAppManifests == null)
                return;

            foreach (var template in PartialAppManifests) {
                PDictionary partial;

                try {
                    partial = PDictionary.FromFile (template.ItemSpec);
                } catch (Exception ex) {
                    Log.LogError ("Error loading partial Info.plist template file '{0}': {1}", template.ItemSpec, ex.Message);
                    continue;
                }

                MergePartialPlistDictionary (plist, partial);
            }
        }
Exemple #40
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;
        }
Exemple #41
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);
			}
		}
Exemple #42
0
        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);
            }
        }
        static void Init()
        {
            string devroot = null, vplist = null, xcode = null;
            bool   foundSdk = false;

            SetInvalid();

            DeveloperRoot = Environment.GetEnvironmentVariable("MD_APPLE_SDK_ROOT");
            if (string.IsNullOrEmpty(DeveloperRoot))
            {
                DeveloperRoot = GetConfiguredSdkLocation();

                if (string.IsNullOrEmpty(DeveloperRoot) && File.Exists("/usr/bin/xcode-select"))
                {
                    var startInfo = new ProcessStartInfo("/usr/bin/xcode-select", "--print-path");
                    startInfo.RedirectStandardOutput = true;
                    startInfo.UseShellExecute        = false;

                    var process = new Process();
                    var stdout  = string.Empty;

                    try {
                        process.StartInfo           = startInfo;
                        process.OutputDataReceived += (sender, e) => stdout += e.Data;
                        process.Start();
                        process.WaitForExit();
                    } catch (Win32Exception) {
                        stdout = string.Empty;
                    }

                    stdout = stdout.Trim();

                    if (!string.IsNullOrEmpty(stdout) && Directory.Exists(stdout))
                    {
                        if (stdout.EndsWith("/Contents/Developer", StringComparison.Ordinal))
                        {
                            stdout = stdout.Substring(0, stdout.Length - "/Contents/Developer".Length);
                        }

                        DeveloperRoot = stdout;
                    }
                }
            }

            if (string.IsNullOrEmpty(DeveloperRoot))
            {
                foreach (var v in DefaultRoots)
                {
                    if (ValidateSdkLocation(v, out xcode, out vplist, out devroot))
                    {
                        foundSdk = true;
                        break;
                    }

                    LoggingService.LogInfo("A valid Xcode installation was not found at '{0}'", v);
                }
            }
            else if (!ValidateSdkLocation(DeveloperRoot, out xcode, out vplist, out devroot))
            {
                LoggingService.LogError("A valid Xcode installation was not found at the configured location: '{0}'", DeveloperRoot);
                SetInvalid();
                return;
            }
            else
            {
                foundSdk = true;
            }

            if (foundSdk)
            {
                XcodePath                 = xcode;
                DeveloperRoot             = devroot;
                DeveloperRootVersionPlist = vplist;
                Environment.SetEnvironmentVariable("XCODE_DEVELOPER_DIR_PATH", DeveloperRoot);
            }
            else
            {
                SetInvalid();
                return;
            }

            try {
                var plist = Path.Combine(XcodePath, "Contents", "Info.plist");

                if (!File.Exists(plist))
                {
                    SetInvalid();
                    return;
                }

                lastWritten = File.GetLastWriteTime(plist);

                XcodeVersion  = new Version(3, 2, 6);
                XcodeRevision = "0";

                // DTXCode was introduced after xcode 3.2.6 so it may not exist
                var dict = PDictionary.FromFile(plist);

                PString value;
                if (dict.TryGetValue("DTXcode", out value))
                {
                    DTXcode = value.Value;
                }

                if (dict.TryGetValue("CFBundleShortVersionString", out value))
                {
                    XcodeVersion = Version.Parse(value.Value);
                }

                if (dict.TryGetValue("CFBundleVersion", out value))
                {
                    XcodeRevision = value.Value;
                }

                LoggingService.LogInfo("Found Xcode, version {0} ({1}).", XcodeVersion, XcodeRevision);
                AnalyticsService.ReportContextProperty("XS.Core.SDK.Xcode.Version", XcodeVersion.ToString());
                IsValid = true;
            } catch (Exception ex) {
                LoggingService.LogError("Error loading Xcode information for prefix '" + DeveloperRoot + "'", ex);
                SetInvalid();
            }
        }
        protected int Compile(ITaskItem[] items, string output, ITaskItem manifest)
        {
            var environment = new Dictionary <string, string> ();
            var args        = new CommandLineArgumentBuilder();

            if (!string.IsNullOrEmpty(SdkBinPath))
            {
                environment.Add("PATH", SdkBinPath);
            }

            if (!string.IsNullOrEmpty(SdkUsrPath))
            {
                environment.Add("XCODE_DEVELOPER_USR_PATH", SdkUsrPath);
            }

            if (!string.IsNullOrEmpty(SdkDevPath))
            {
                environment.Add("DEVELOPER_DIR", SdkDevPath);
            }

            // workaround for ibtool[d] bug / asserts if Intel version is loaded
            string tool;

            if (IsTranslated())
            {
                // we force the Intel (translated) msbuild process to launch ibtool as "Apple"
                tool = "arch";
                args.Add("-arch", "arm64e");
                args.Add("/usr/bin/xcrun");
            }
            else
            {
                tool = "/usr/bin/xcrun";
            }
            args.Add(ToolName);
            args.Add("--errors", "--warnings", "--notices");
            args.Add("--output-format", "xml1");

            AppendCommandLineArguments(environment, args, items);

            if (Link)
            {
                args.Add("--link");
            }
            else if (UseCompilationDirectory)
            {
                args.Add("--compilation-directory");
            }
            else
            {
                args.Add("--compile");
            }

            args.AddQuoted(Path.GetFullPath(output));

            foreach (var item in items)
            {
                args.AddQuoted(item.GetMetadata("FullPath"));
            }

            var arguments = args.ToList();
            var rv        = ExecuteAsync(tool, arguments, sdkDevPath, environment: environment, mergeOutput: false).Result;
            var exitCode  = rv.ExitCode;
            var messages  = rv.StandardOutput.ToString();

            File.WriteAllText(manifest.ItemSpec, messages);

            if (exitCode != 0)
            {
                // Note: ibtool or actool exited with an error. Dump everything we can to help the user
                // diagnose the issue and then delete the manifest log file so that rebuilding tries
                // again (in case of ibtool's infamous spurious errors).
                var errors = rv.StandardError.ToString();
                if (errors.Length > 0)
                {
                    Log.LogError(null, null, null, items[0].ItemSpec, 0, 0, 0, 0, "{0}", errors);
                }

                Log.LogError(MSBStrings.E0117, ToolName, exitCode);

                // Note: If the log file exists and is parseable, log those warnings/errors as well...
                if (File.Exists(manifest.ItemSpec))
                {
                    try {
                        var plist = PDictionary.FromFile(manifest.ItemSpec);

                        LogWarningsAndErrors(plist, items[0]);
                    } catch (Exception ex) {
                        Log.LogError(MSBStrings.E0094, ToolName, manifest.ItemSpec, ex.Message);
                    }

                    File.Delete(manifest.ItemSpec);
                }
            }

            return(exitCode);
        }
Exemple #45
0
        protected virtual PDictionary GetCompiledEntitlements(MobileProvision profile, PDictionary template)
        {
            var entitlements = new PDictionary();

            if (profile != null && MergeProfileEntitlements)
            {
                // start off with the settings from the provisioning profile
                foreach (var item in profile.Entitlements)
                {
                    if (!AllowedProvisioningKeys.Contains(item.Key))
                    {
                        continue;
                    }

                    var value = item.Value;

                    if (item.Key == "com.apple.developer.icloud-container-environment")
                    {
                        value = new PString("Development");
                    }
                    else if (value is PDictionary)
                    {
                        value = MergeEntitlementDictionary((PDictionary)value, profile);
                    }
                    else if (value is PString)
                    {
                        value = MergeEntitlementString((PString)value, profile, item.Key == ApplicationIdentifierKey);
                    }
                    else if (value is PArray)
                    {
                        value = MergeEntitlementArray((PArray)value, profile);
                    }
                    else
                    {
                        value = value.Clone();
                    }

                    if (value != null)
                    {
                        entitlements.Add(item.Key, value);
                    }
                }
            }

            // merge in the user's values
            foreach (var item in template)
            {
                var value = item.Value;

                if (item.Key == "com.apple.developer.ubiquity-container-identifiers" ||
                    item.Key == "com.apple.developer.icloud-container-identifiers" ||
                    item.Key == "com.apple.developer.icloud-container-environment" ||
                    item.Key == "com.apple.developer.icloud-services")
                {
                    if (profile == null)
                    {
                        Log.LogWarning(null, null, null, Entitlements, 0, 0, 0, 0, "iCloud entitlements such as '" + item.Key + "' require a Provisioning Profile.");
                    }
                    else if (!profile.Entitlements.ContainsKey(item.Key))
                    {
                        Log.LogWarning(null, null, null, Entitlements, 0, 0, 0, 0, "The iCloud entitlement '" + item.Key + "' is not supported by the Provisioning Profile.");
                    }
                }
                else if (item.Key == ApplicationIdentifierKey)
                {
                    var str = value as PString;

                    // Ignore ONLY if it is empty, otherwise take the user's value
                    if (str == null || string.IsNullOrEmpty(str.Value))
                    {
                        continue;
                    }
                }

                if (value is PDictionary)
                {
                    value = MergeEntitlementDictionary((PDictionary)value, profile);
                }
                else if (value is PString)
                {
                    value = MergeEntitlementString((PString)value, profile, item.Key == ApplicationIdentifierKey);
                }
                else if (value is PArray)
                {
                    value = MergeEntitlementArray((PArray)value, profile);
                }
                else
                {
                    value = value.Clone();
                }

                if (value != null)
                {
                    entitlements[item.Key] = value;
                }
            }

            return(entitlements);
        }
        protected void LogWarningsAndErrors(PDictionary plist, ITaskItem file)
        {
            PDictionary dictionary;
            PString     message;
            PArray      array;

            if (plist.TryGetValue(string.Format("com.apple.{0}.document.notices", ToolName), out array))
            {
                foreach (var item in array.OfType <PDictionary> ())
                {
                    if (item.TryGetValue("message", out message))
                    {
                        Log.LogMessage(MessageImportance.Low, "{0} notice : {1}", ToolName, message.Value);
                    }
                }
            }

            if (plist.TryGetValue(string.Format("com.apple.{0}.document.warnings", ToolName), out array))
            {
                foreach (var item in array.OfType <PDictionary> ())
                {
                    if (item.TryGetValue("message", out message))
                    {
                        Log.LogWarning(ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                    }
                }
            }

            if (plist.TryGetValue(string.Format("com.apple.{0}.document.errors", ToolName), out array))
            {
                foreach (var item in array.OfType <PDictionary> ())
                {
                    if (item.TryGetValue("message", out message))
                    {
                        Log.LogError(ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                    }
                }
            }

            //Trying to parse document warnings and erros using a PDictionary first since it's what ibtool is returning when building a storyboard.
            if (plist.TryGetValue(string.Format("com.apple.{0}.document.notices", ToolName), out dictionary))
            {
                foreach (var valuePair in dictionary)
                {
                    array = valuePair.Value as PArray;
                    foreach (var item in array.OfType <PDictionary> ())
                    {
                        if (item.TryGetValue("message", out message))
                        {
                            Log.LogMessage(MessageImportance.Low, "{0} notice : {1}", ToolName, message.Value);
                        }
                    }
                }
            }

            if (plist.TryGetValue(string.Format("com.apple.{0}.document.warnings", ToolName), out dictionary))
            {
                foreach (var valuePair in dictionary)
                {
                    array = valuePair.Value as PArray;
                    foreach (var item in array.OfType <PDictionary> ())
                    {
                        if (item.TryGetValue("message", out message))
                        {
                            Log.LogWarning(ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                        }
                    }
                }
            }

            if (plist.TryGetValue(string.Format("com.apple.{0}.document.errors", ToolName), out dictionary))
            {
                foreach (var valuePair in dictionary)
                {
                    array = valuePair.Value as PArray;
                    foreach (var item in array.OfType <PDictionary> ())
                    {
                        if (item.TryGetValue("message", out message))
                        {
                            Log.LogError(ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                        }
                    }
                }
            }

            if (plist.TryGetValue(string.Format("com.apple.{0}.errors", ToolName), out array))
            {
                foreach (var item in array.OfType <PDictionary> ())
                {
                    if (item.TryGetValue("description", out message))
                    {
                        Log.LogError(ToolName, null, null, file.ItemSpec, 0, 0, 0, 0, "{0}", message.Value);
                    }
                }
            }

            if (plist.TryGetValue(string.Format("com.apple.{0}.notices", ToolName), out array))
            {
                foreach (var item in array.OfType <PDictionary> ())
                {
                    if (item.TryGetValue("description", out message))
                    {
                        Log.LogMessage(MessageImportance.Low, "{0} notice : {1}", ToolName, message.Value);
                    }
                }
            }
        }
Exemple #47
0
        public override bool Execute()
        {
            MobileProvisionPlatform platform;
            MobileProvision         profile;
            PDictionary             template;
            PDictionary             compiled;
            PDictionary             archived;
            string path;
            bool   save;

            switch (SdkPlatform)
            {
            case "AppleTVSimulator":
            case "AppleTVOS":
                platform = MobileProvisionPlatform.tvOS;
                break;

            case "iPhoneSimulator":
            case "WatchSimulator":
            case "iPhoneOS":
            case "WatchOS":
                platform = MobileProvisionPlatform.iOS;
                break;

            case "MacOSX":
                platform = MobileProvisionPlatform.MacOS;
                break;

            default:
                Log.LogError("Unknown SDK platform: {0}", SdkPlatform);
                return(false);
            }

            if (!string.IsNullOrEmpty(ProvisioningProfile))
            {
                if ((profile = GetMobileProvision(platform, ProvisioningProfile)) == null)
                {
                    Log.LogError("Could not locate the provisioning profile with a Name or UUID of {0}.", ProvisioningProfile);
                    return(false);
                }
            }
            else
            {
                profile = null;
            }

            if (!string.IsNullOrEmpty(Entitlements))
            {
                if (!File.Exists(Entitlements))
                {
                    Log.LogError("Entitlements.plist template '{0}' not found.", Entitlements);
                    return(false);
                }

                path = Entitlements;
            }
            else
            {
                path = DefaultEntitlementsPath;
            }

            try {
                template = PDictionary.FromFile(path);
            } catch (Exception ex) {
                Log.LogError("Error loading Entitlements.plist template '{0}': {1}", path, ex.Message);
                return(false);
            }

            compiled = GetCompiledEntitlements(profile, template);
            archived = GetArchivedExpandedEntitlements(template, compiled);

            try {
                Directory.CreateDirectory(Path.GetDirectoryName(CompiledEntitlements.ItemSpec));
                WriteXcent(compiled, CompiledEntitlements.ItemSpec);
            } catch (Exception ex) {
                Log.LogError("Error writing xcent file '{0}': {1}", CompiledEntitlements, ex.Message);
                return(false);
            }

            path = Path.Combine(EntitlementBundlePath, "archived-expanded-entitlements.xcent");

            if (File.Exists(path))
            {
                var plist = PDictionary.FromFile(path);
                var src   = archived.ToXml();
                var dest  = plist.ToXml();

                save = src != dest;
            }
            else
            {
                save = true;
            }

            if (save)
            {
                try {
                    archived.Save(path, true);
                } catch (Exception ex) {
                    Log.LogError("Error writing archived-expanded-entitlements.xcent file: {0}", ex.Message);
                    return(false);
                }
            }

            return(!Log.HasLoggedErrors);
        }
Exemple #48
0
        void Init()
        {
            string currentLocation = IsInstalled ? Path.Combine(BinDir, "mtouch") : null;

            IsInstalled = false;
            versions    = null;

            if (string.IsNullOrEmpty(SdkDir))
            {
                foreach (var loc in DefaultLocations)
                {
                    if (IsInstalled = ValidateSdkLocation(loc, out hasUsrSubdir))
                    {
                        SdkDir = loc;
                        break;
                    }
                }
            }
            else
            {
                IsInstalled = ValidateSdkLocation(SdkDir, out hasUsrSubdir);
            }

            string mtouch = null;

            if (IsInstalled)
            {
                mtouch         = Path.Combine(BinDir, "mtouch");
                lastMTExeWrite = File.GetLastWriteTimeUtc(mtouch);
                Version        = ReadVersion();

                if (Version.CompareTo(requiredXI) >= 0)
                {
                    LoggingService.LogInfo("Found Xamarin.iOS, version {0}.", Version);

                    var path = Path.Combine(SdkDir, "Versions.plist");
                    if (File.Exists(path))
                    {
                        try {
                            versions = PDictionary.FromFile(path);
                        } catch {
                            LoggingService.LogWarning("Xamarin.iOS installation is corrupt: invalid Versions.plist at {0}.", path);
                        }
                    }

                    if (versions == null)
                    {
                        versions = CreateDefaultVersionsPlist();
                    }
                }
                else
                {
                    SdkNotInstalledReason = string.Format("Found unsupported Xamarin.iOS, version {0}.\nYou need Xamarin.iOS {1} or above.", Version, requiredXI.ToString());
                    LoggingService.LogWarning(SdkNotInstalledReason);
                    Version     = new IPhoneSdkVersion();
                    versions    = new PDictionary();
                    IsInstalled = false;
                }

                AnalyticsService.ReportSdkVersion("XS.Core.SDK.iOS.Version", Version.ToString());
            }
            else
            {
                lastMTExeWrite = DateTime.MinValue;
                Version        = new IPhoneSdkVersion();
                versions       = new PDictionary();

                SdkNotInstalledReason = string.Format("Xamarin.iOS not installed.\nCan't find mtouch or the Version file at {0}.", SdkDir);
                LoggingService.LogInfo(SdkNotInstalledReason);

                AnalyticsService.ReportSdkVersion("XS.Core.SDK.iOS.Version", string.Empty);
            }

            if (Changed != null && currentLocation != mtouch)
            {
                Changed(this, EventArgs.Empty);
            }
        }
Exemple #49
0
        public override bool Execute()
        {
            Log.LogTaskName ("Archive");
            Log.LogTaskProperty ("AppBundleDir", AppBundleDir);
            Log.LogTaskProperty ("AppExtensionReferences", AppExtensionReferences);
            Log.LogTaskProperty ("ITunesSourceFiles", ITunesSourceFiles);
            Log.LogTaskProperty ("OutputPath", OutputPath);
            Log.LogTaskProperty ("ProjectName", ProjectName);
            Log.LogTaskProperty ("SigningKey", SigningKey);
            Log.LogTaskProperty ("SolutionPath", SolutionPath);

            var archiveDir = CreateArchiveDirectory ();

            try {
                var plist = PDictionary.FromFile (Path.Combine (AppBundleDir.ItemSpec, "Info.plist"));
                var productsDir = Path.Combine (archiveDir, "Products");

                // Archive the OnDemandResources...
                var resourcesDestDir = Path.Combine (productsDir, "OnDemandResources");
                var resourcesSrcDir = Path.Combine (OutputPath, "OnDemandResources");

                if (Directory.Exists (resourcesSrcDir))
                    Ditto (resourcesSrcDir, resourcesDestDir);

                // Archive the Applications...
                var appDestDir = Path.Combine (productsDir, "Applications", Path.GetFileName (AppBundleDir.ItemSpec));
                Ditto (AppBundleDir.ItemSpec, appDestDir);

                // Archive the dSYMs...
                var dsymsDestDir = Path.Combine (archiveDir, "dSYMs", Path.GetFileName (DSYMDir));
                Ditto (DSYMDir, dsymsDestDir);

                // Archive the Bitcode symbol maps
                var bcSymbolMaps = Directory.GetFiles (Path.GetDirectoryName (DSYMDir), "*.bcsymbolmap");
                if (bcSymbolMaps.Length > 0) {
                    var bcSymbolMapsDir = Path.Combine (archiveDir, "BCSymbolMaps");

                    Directory.CreateDirectory (bcSymbolMapsDir);

                    for (int i = 0; i < bcSymbolMaps.Length; i++)
                        File.Copy (bcSymbolMaps[i], Path.Combine (bcSymbolMapsDir, Path.GetFileName (bcSymbolMaps[i])));
                }

                if (AppExtensionReferences != null) {
                    // Archive the dSYMs for each of the referenced App Extensions as well...
                    for (int i = 0; i < AppExtensionReferences.Length; i++)
                        ArchiveAppExtension (AppExtensionReferences[i], archiveDir);
                }

                if (ITunesSourceFiles != null) {
                    // Archive the iTunesMetadata.plist and iTunesArtwork files...
                    var iTunesMetadataDir = Path.Combine (archiveDir, "iTunesMetadata", Path.GetFileName (AppBundleDir.ItemSpec));
                    for (int i = 0; i < ITunesSourceFiles.Length; i++) {
                        var archivedMetaFile = Path.Combine (iTunesMetadataDir, Path.GetFileName (ITunesSourceFiles[i].ItemSpec));

                        Directory.CreateDirectory (iTunesMetadataDir);
                        File.Copy (ITunesSourceFiles[i].ItemSpec, archivedMetaFile, true);
                    }
                }

                // Generate an archive Info.plist
                var arInfo = new PDictionary ();
                // FIXME: figure out this value
                //arInfo.Add ("AppStoreFileSize", new PNumber (65535));

                var props = new PDictionary ();
                props.Add ("ApplicationPath", new PString (string.Format ("Applications/{0}", Path.GetFileName (AppBundleDir.ItemSpec))));
                props.Add ("CFBundleIdentifier", new PString (plist.GetCFBundleIdentifier ()));
                if (plist.GetCFBundleShortVersionString () != null)
                    props.Add ("CFBundleShortVersionString", new PString (plist.GetCFBundleShortVersionString ()));
                else if (plist.GetCFBundleVersion () != null)
                    props.Add ("CFBundleShortVersionString", new PString (plist.GetCFBundleVersion ()));

                var iconFiles = plist.GetCFBundleIconFiles ();
                var iconDict = plist.GetCFBundleIcons ();
                var icons = new PArray ();

                if (iconFiles != null)
                    AddIconPaths (icons, iconFiles, Path.Combine (archiveDir, "Products"));

                if (iconDict != null) {
                    var primary = iconDict.Get<PDictionary> (ManifestKeys.CFBundlePrimaryIcon);
                    if (primary != null && (iconFiles = primary.GetCFBundleIconFiles ()) != null)
                        AddIconPaths (icons, iconFiles, Path.Combine (archiveDir, "Products"));
                }

                if (icons.Count > 0)
                    props.Add ("IconPaths", icons);

                props.Add ("SigningIdentity", new PString (SigningKey));

                arInfo.Add ("ApplicationProperties", props);
                arInfo.Add ("ArchiveVersion", new PNumber (2));
                arInfo.Add ("CreationDate", new PDate (Now.ToUniversalTime ()));
                arInfo.Add ("Name", new PString (plist.GetCFBundleName () ?? plist.GetCFBundleDisplayName ()));
                arInfo.Add ("SchemeName", new PString (ProjectName));

                if (!string.IsNullOrEmpty (SolutionPath)) {
                    arInfo.Add ("SolutionName", new PString (Path.GetFileNameWithoutExtension (SolutionPath)));
                    arInfo.Add ("SolutionPath", new PString (SolutionPath));
                }

                arInfo.Save (Path.Combine (archiveDir, "Info.plist"));

                ArchiveDir = archiveDir;
            } catch (Exception ex) {
                Log.LogErrorFromException (ex);
                Directory.Delete (archiveDir, true);
            }

            return !Log.HasLoggedErrors;
        }
Exemple #50
0
        public void CreateIpa()
        {
            if (Platform == "iPhoneSimulator")
            {
                return;                 // this is a device-only test.
            }
            const string hostAppName = "MyWatchApp";
//			string extensionName = "MyWatchKitExtension";
            const string configuration = "AppStore";

            var mtouchPaths = SetupProjectPaths(hostAppName, "../", true, Platform, configuration);
            var proj        = SetupProject(Engine, mtouchPaths.ProjectCSProjPath);

            AppBundlePath = mtouchPaths.AppBundlePath;

            Engine.GlobalProperties.SetProperty("Platform", Platform);
            Engine.GlobalProperties.SetProperty("BuildIpa", "true");
            Engine.GlobalProperties.SetProperty("IpaIncludeArtwork", "true");
            Engine.GlobalProperties.SetProperty("CodesignProvision", "Automatic");              // Provisioning profile
            Engine.GlobalProperties.SetProperty("CodesignKey", "iPhone Developer");
            Engine.GlobalProperties.SetProperty("Configuration", configuration);

            RunTarget(proj, "Clean");
            Assert.IsFalse(Directory.Exists(AppBundlePath), "{1}: App bundle exists after cleanup: {0} ", AppBundlePath, Platform);

            proj = SetupProject(Engine, mtouchPaths.ProjectCSProjPath);
            RunTarget(proj, "Build");

            var plist = PDictionary.FromFile(Path.Combine(AppBundlePath, "Info.plist"));

            Assert.IsTrue(plist.ContainsKey("CFBundleExecutable"));
            Assert.IsTrue(plist.ContainsKey("CFBundleVersion"));
            Assert.IsNotEmpty(((PString)plist["CFBundleExecutable"]).Value);
            Assert.IsNotEmpty(((PString)plist["CFBundleVersion"]).Value);

            var ipaOutputDir        = Directory.EnumerateDirectories(mtouchPaths.ProjectBinPath, hostAppName + " *").FirstOrDefault();
            var ipaPath             = Path.Combine(ipaOutputDir, hostAppName + ".ipa");
            var payloadPath         = "Payload/";
            var watchkitSupportPath = "WatchKitSupport/";

            Assert.IsTrue(File.Exists(ipaPath));

            var startInfo = new ProcessStartInfo("/usr/bin/zipinfo", "-1 \"" + ipaPath + "\"");

            startInfo.RedirectStandardOutput = true;
            startInfo.UseShellExecute        = false;
            var process = new Process();

            process.StartInfo = startInfo;
            process.Start();
            var output = process.StandardOutput.ReadToEnd();

            process.WaitForExit();

            var lines = output.Split(new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

            Assert.Contains(payloadPath, lines, payloadPath + " does not exist");
            Assert.Contains(watchkitSupportPath, lines, watchkitSupportPath + " does not exist");

            string wkPath = "WatchKitSupport/WK";

            Assert.Contains(wkPath, lines, wkPath + " does not exist");

            var ipaIncludeArtwork = proj.GetEvaluatedProperty("IpaIncludeArtwork");

            Assert.IsTrue(output.Contains("iTunesMetadata.plist"), string.Format("The ipa should contain at least one iTunesMetadata.plist file if we are using an AppStore config and IpaIncludeArtwork is true. IpaIncludeArtwork: {0}", ipaIncludeArtwork));
        }
Exemple #51
0
 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;
     }
 }
        public override bool Execute()
        {
            var type     = MobileProvisionDistributionType.Any;
            var identity = new CodeSignIdentity();
            MobileProvisionPlatform  platform;
            IList <MobileProvision>  profiles;
            IList <X509Certificate2> certs;
            PDictionary plist;

            switch (SdkPlatform)
            {
            case "AppleTVSimulator":
            case "AppleTVOS":
                platform = MobileProvisionPlatform.tvOS;
                break;

            case "iPhoneSimulator":
            case "WatchSimulator":
            case "iPhoneOS":
            case "WatchOS":
                platform = MobileProvisionPlatform.iOS;
                break;

            case "MacOSX":
                platform = MobileProvisionPlatform.MacOS;
                break;

            default:
                Log.LogError("Unknown SDK platform: {0}", SdkPlatform);
                return(false);
            }

            if (ProvisioningProfile == AutomaticAppStoreProvision)
            {
                type = MobileProvisionDistributionType.AppStore;
            }
            else if (ProvisioningProfile == AutomaticInHouseProvision)
            {
                type = MobileProvisionDistributionType.InHouse;
            }
            else if (ProvisioningProfile == AutomaticAdHocProvision)
            {
                type = MobileProvisionDistributionType.AdHoc;
            }

            try {
                plist = PDictionary.FromFile(AppManifest);
            } catch (Exception ex) {
                Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Error loading '{0}': {1}", AppManifest, ex.Message);
                return(false);
            }

            DetectedCodesignAllocate = Path.Combine(DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate");
            DetectedBundleVersion    = plist.GetCFBundleVersion();
            DetectedDistributionType = type.ToString();

            identity.BundleId = plist.GetCFBundleIdentifier();
            if (string.IsNullOrEmpty(identity.BundleId))
            {
                Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "{0} does not define CFBundleIdentifier", AppManifest);
                return(false);
            }

            if (Framework == PlatformFramework.MacOS && !RequireCodeSigning)
            {
                DetectedBundleId = identity.BundleId;
                DetectedAppId    = DetectedBundleId;

                ReportDetectedCodesignInfo();

                return(!Log.HasLoggedErrors);
            }

            if (!RequireProvisioningProfile)
            {
                if (SdkIsSimulator && AppleSdkSettings.XcodeVersion.Major >= 8)
                {
                    // Note: Starting with Xcode 8.0, we need to codesign iOS Simulator builds in order for them to run.
                    // The "-" key is a special value allowed by the codesign utility that allows us to get away with
                    // not having an actual codesign key. As far as we know, this only works with Xcode >= 8.
                    DetectedCodeSigningKey = "-";
                }
                else
                {
                    // Try and get a valid codesigning certificate...
                    if (!TryGetSigningCertificates(out certs, SdkIsSimulator))
                    {
                        return(false);
                    }

                    if (certs.Count > 0)
                    {
                        if (certs.Count > 1)
                        {
                            if (!string.IsNullOrEmpty(SigningKey))
                            {
                                Log.LogMessage(MessageImportance.Normal, "Multiple signing identities match '{0}'; using the first match.", SigningKey);
                            }
                            else
                            {
                                Log.LogMessage(MessageImportance.Normal, "Multiple signing identities found; using the first identity.");
                            }

                            for (int i = 0; i < certs.Count; i++)
                            {
                                Log.LogMessage(MessageImportance.Normal, "{0,3}. Signing Identity: {1} ({2})", i + 1,
                                               SecKeychain.GetCertificateCommonName(certs[i]), certs[i].Thumbprint);
                            }
                        }

                        codesignCommonName     = SecKeychain.GetCertificateCommonName(certs[0]);
                        DetectedCodeSigningKey = certs[0].Thumbprint;
                    }
                    else
                    {
                        // Note: We don't have to codesign for iOS Simulator builds meant to run on Xcode iOS Simulators
                        // older than 8.0, so it's non-fatal if we don't find any...
                    }
                }

                DetectedBundleId = identity.BundleId;
                DetectedAppId    = DetectedBundleId;

                ReportDetectedCodesignInfo();

                return(!Log.HasLoggedErrors);
            }

            // Note: if we make it this far, we absolutely need a codesigning certificate
            if (!TryGetSigningCertificates(out certs, false))
            {
                return(false);
            }

            if (certs.Count > 0)
            {
                Log.LogMessage(MessageImportance.Low, "Available certificates:");
                foreach (var cert in certs)
                {
                    Log.LogMessage(MessageImportance.Low, "    {0}", Xamarin.MacDev.Keychain.GetCertificateCommonName(cert));
                }
            }

            if (!IsAutoCodeSignProfile(ProvisioningProfile))
            {
                identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile);

                if (identity.Profile == null)
                {
                    Log.LogError("The specified " + PlatformName + " provisioning profile '{0}' could not be found", ProvisioningProfile);
                    return(false);
                }

                var profile = identity.Profile;                 // capture ref for lambda

                if (certs.Count > 0)
                {
                    identity.SigningKey = certs.FirstOrDefault(c => profile.DeveloperCertificates.Any(p => p.Thumbprint == c.Thumbprint));
                    if (identity.SigningKey == null)
                    {
                        Log.LogError("No " + PlatformName + " signing identities match the specified provisioning profile '{0}'.", ProvisioningProfile);
                        return(false);
                    }
                }

                identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId);
                if (identity.AppId == null)
                {
                    Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, "Project bundle identifier '{0}' does not match specified provisioning profile '{1}'", identity.BundleId, ProvisioningProfile);
                    return(false);
                }

                if (identity.SigningKey != null)
                {
                    codesignCommonName     = SecKeychain.GetCertificateCommonName(identity.SigningKey);
                    DetectedCodeSigningKey = identity.SigningKey.Thumbprint;
                }

                provisioningProfileName = identity.Profile.Name;

                DetectedProvisioningProfile = identity.Profile.Uuid;
                DetectedDistributionType    = identity.Profile.DistributionType.ToString();
                DetectedBundleId            = identity.BundleId;
                DetectedAppId = identity.AppId;

                ReportDetectedCodesignInfo();

                return(!Log.HasLoggedErrors);
            }

            List <string> failures = new List <string> ();

            if (identity.BundleId != null)
            {
                if (certs.Count > 0)
                {
                    profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, certs, unique: true, failures: failures);
                }
                else
                {
                    profiles = MobileProvisionIndex.GetMobileProvisions(platform, identity.BundleId, type, unique: true, failures: failures);
                }
            }
            else if (certs.Count > 0)
            {
                profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, certs, unique: true, failures: failures);
            }
            else
            {
                profiles = MobileProvisionIndex.GetMobileProvisions(platform, type, unique: true, failures: failures);
            }

            if (profiles.Count == 0)
            {
                foreach (var f in failures)
                {
                    Log.LogMessage(MessageImportance.Low, "{0}", f);
                }
                Log.LogError($"Could not find any available provisioning profiles for {PlatformName}.");
                return(false);
            }
            else
            {
                Log.LogMessage(MessageImportance.Low, "Available profiles:");
                foreach (var p in profiles)
                {
                    Log.LogMessage(MessageImportance.Low, "    {0}", p.Name);
                }
            }

            List <CodeSignIdentity> pairs;

            if (certs.Count > 0)
            {
                pairs = (from p in profiles
                         from c in certs
                         where p.DeveloperCertificates.Any(d => {
                    var rv = d.Thumbprint == c.Thumbprint;
                    if (!rv)
                    {
                        Log.LogMessage(MessageImportance.Low, "'{0}' doesn't match '{1}'.", d.Thumbprint, c.Thumbprint);
                    }
                    return(rv);
                })
                         select new CodeSignIdentity {
                    SigningKey = c, Profile = p
                }).ToList();

                if (pairs.Count == 0)
                {
                    Log.LogError("No installed provisioning profiles match the installed " + PlatformName + " signing identities.");
                    return(false);
                }
            }
            else
            {
                pairs = (from p in profiles select new CodeSignIdentity {
                    Profile = p
                }).ToList();
            }

            var matches         = new List <CodeSignIdentity> ();
            int bestMatchLength = 0;
            int matchLength;

            // find matching provisioning profiles with compatible appid, keeping only those with the longest matching (wildcard) ids
            Log.LogMessage(MessageImportance.Low, "Finding matching provisioning profiles with compatible AppID, keeping only those with the longest matching (wildcard) IDs.");
            foreach (var pair in pairs)
            {
                var appid = ConstructValidAppId(pair.Profile, identity.BundleId, out matchLength);
                if (appid != null)
                {
                    if (matchLength >= bestMatchLength)
                    {
                        if (matchLength > bestMatchLength)
                        {
                            bestMatchLength = matchLength;
                            foreach (var previousMatch in matches)
                            {
                                Log.LogMessage(MessageImportance.Low, "AppID: {0} was ruled out because we found a better match: {1}.", previousMatch.AppId, appid);
                            }
                            matches.Clear();
                        }

                        var match = identity.Clone();
                        match.SigningKey = pair.SigningKey;
                        match.Profile    = pair.Profile;
                        match.AppId      = appid;

                        matches.Add(match);
                    }
                    else
                    {
                        string currentMatches = "";
                        foreach (var match in matches)
                        {
                            currentMatches += $"{match}; ";
                        }
                        Log.LogMessage(MessageImportance.Low, "AppID: {0} was ruled out because we already found better matches: ", appid, currentMatches);
                    }
                }
            }

            if (matches.Count == 0)
            {
                Log.LogWarning(null, null, null, AppManifest, 0, 0, 0, 0, "No installed provisioning profiles match the bundle identifier.");
            }
            else
            {
                if (matches.Count > 1)
                {
                    var spaces = new string (' ', 3);

                    Log.LogMessage(MessageImportance.Normal, "Multiple provisioning profiles match the bundle identifier; using the first match.");

                    matches.Sort(new SigningIdentityComparer());

                    for (int i = 0; i < matches.Count; i++)
                    {
                        Log.LogMessage(MessageImportance.Normal, "{0,3}. Provisioning Profile: \"{1}\" ({2})", i + 1, matches[i].Profile.Name, matches[i].Profile.Uuid);

                        if (matches[i].SigningKey != null)
                        {
                            Log.LogMessage(MessageImportance.Normal, "{0}  Signing Identity: \"{1}\"", spaces, SecKeychain.GetCertificateCommonName(matches[i].SigningKey));
                        }
                    }
                }

                identity = matches[0];
            }

            if (identity.Profile != null && identity.AppId != null)
            {
                codesignCommonName = identity.SigningKey != null?SecKeychain.GetCertificateCommonName(identity.SigningKey) : null;

                provisioningProfileName = identity.Profile.Name;

                DetectedCodeSigningKey      = identity.SigningKey?.Thumbprint;
                DetectedProvisioningProfile = identity.Profile.Uuid;
                DetectedBundleId            = identity.BundleId;
                DetectedAppId = identity.AppId;

                ReportDetectedCodesignInfo();
            }
            else
            {
                if (identity.SigningKey != null)
                {
                    Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile for selected signing identity '{0}'.", identity.BundleId, identity.SigningKey);
                }
                else
                {
                    Log.LogError("Bundle identifier '{0}' does not match any installed provisioning profile.", identity.BundleId);
                }
            }

            return(!Log.HasLoggedErrors);
        }
Exemple #53
0
        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");
                    }
                }
            }
        }
        public override bool Execute()
        {
            var type     = MobileProvisionDistributionType.Any;
            var identity = new CodeSignIdentity();
            MobileProvisionPlatform  platform;
            IList <MobileProvision>  profiles;
            IList <X509Certificate2> certs;
            List <CodeSignIdentity>  pairs;
            PDictionary plist;

            switch (SdkPlatform)
            {
            case "AppleTVSimulator":
            case "AppleTVOS":
                platform = MobileProvisionPlatform.tvOS;
                break;

            case "iPhoneSimulator":
            case "WatchSimulator":
            case "iPhoneOS":
            case "WatchOS":
                platform = MobileProvisionPlatform.iOS;
                break;

            case "MacOSX":
                platform = MobileProvisionPlatform.MacOS;
                break;

            default:
                Log.LogError("Unknown SDK platform: {0}", SdkPlatform);
                return(false);
            }

            if (ProvisioningProfile == AutomaticAppStoreProvision)
            {
                type = MobileProvisionDistributionType.AppStore;
            }
            else if (ProvisioningProfile == AutomaticInHouseProvision)
            {
                type = MobileProvisionDistributionType.InHouse;
            }
            else if (ProvisioningProfile == AutomaticAdHocProvision)
            {
                type = MobileProvisionDistributionType.AdHoc;
            }

            try {
                plist = PDictionary.FromFile(AppManifest);
            } catch (Exception ex) {
                Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, MSBStrings.E0010, AppManifest, ex.Message);
                return(false);
            }

            DetectedCodesignAllocate = Path.Combine(DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate");
            DetectedBundleVersion    = plist.GetCFBundleVersion();
            DetectedDistributionType = type.ToString();

            identity.BundleId = plist.GetCFBundleIdentifier();
            if (string.IsNullOrEmpty(identity.BundleId))
            {
                Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, MSBStrings.E0139, AppManifest);
                return(false);
            }

            if (Platform == ApplePlatform.MacOSX)
            {
                if (!RequireCodeSigning)
                {
                    DetectedBundleId = identity.BundleId;
                    DetectedAppId    = DetectedBundleId;

                    ReportDetectedCodesignInfo();

                    return(!Log.HasLoggedErrors);
                }
            }
            else
            {
                // Framework is either iOS, tvOS or watchOS
                if (SdkIsSimulator)
                {
                    if (AppleSdkSettings.XcodeVersion.Major >= 8 && RequireProvisioningProfile)
                    {
                        // Note: Starting with Xcode 8.0, we need to codesign iOS Simulator builds that enable Entitlements
                        // in order for them to run. The "-" key is a special value allowed by the codesign utility that
                        // allows us to get away with not having an actual codesign key.
                        DetectedCodeSigningKey = "-";

                        if (!IsAutoCodeSignProfile(ProvisioningProfile))
                        {
                            identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile);

                            if (identity.Profile == null)
                            {
                                Log.LogError(MSBStrings.E0140, PlatformName, ProvisioningProfile);
                                return(false);
                            }

                            identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId);
                            if (identity.AppId == null)
                            {
                                Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, MSBStrings.E0141, identity.BundleId, ProvisioningProfile);
                                return(false);
                            }

                            provisioningProfileName = identity.Profile.Name;

                            DetectedProvisioningProfile = identity.Profile.Uuid;
                            DetectedDistributionType    = identity.Profile.DistributionType.ToString();
                            DetectedBundleId            = identity.BundleId;
                            DetectedAppId = DetectedBundleId;
                        }
                        else
                        {
                            certs = new X509Certificate2[0];

                            if ((profiles = GetProvisioningProfiles(platform, type, identity, certs)) == null)
                            {
                                return(false);
                            }

                            if ((pairs = GetCodeSignIdentityPairs(profiles, certs)) == null)
                            {
                                return(false);
                            }

                            var match = GetBestMatch(pairs, identity);
                            identity.Profile = match.Profile;
                            identity.AppId   = match.AppId;

                            if (identity.Profile != null)
                            {
                                DetectedDistributionType    = identity.Profile.DistributionType.ToString();
                                DetectedProvisioningProfile = identity.Profile.Uuid;
                                provisioningProfileName     = identity.Profile.Name;
                            }

                            DetectedBundleId = identity.BundleId;
                            DetectedAppId    = identity.AppId;
                        }
                    }
                    else
                    {
                        // Note: Do not codesign. Codesigning seems to break the iOS Simulator in older versions of Xcode.
                        DetectedCodeSigningKey = null;

                        DetectedBundleId = identity.BundleId;
                        DetectedAppId    = DetectedBundleId;
                    }

                    ReportDetectedCodesignInfo();

                    return(!Log.HasLoggedErrors);
                }
            }

            // Note: if we make it this far, we absolutely need a codesigning certificate
            if (!TryGetSigningCertificates(out certs, false))
            {
                return(false);
            }

            Log.LogMessage(MessageImportance.Low, "Available certificates:");
            foreach (var cert in certs)
            {
                Log.LogMessage(MessageImportance.Low, "    {0}", SecKeychain.GetCertificateCommonName(cert));
            }

            if (!RequireProvisioningProfile)
            {
                if (certs.Count > 1)
                {
                    if (!string.IsNullOrEmpty(SigningKey))
                    {
                        Log.LogMessage(MessageImportance.Normal, MSBStrings.M0142, SigningKey);
                    }
                    else
                    {
                        Log.LogMessage(MessageImportance.Normal, MSBStrings.M0143);
                    }

                    for (int i = 0; i < certs.Count; i++)
                    {
                        Log.LogMessage(MessageImportance.Normal, "{0,3}. Signing Identity: {1} ({2})", i + 1,
                                       SecKeychain.GetCertificateCommonName(certs[i]), certs[i].Thumbprint);
                    }
                }

                codesignCommonName     = SecKeychain.GetCertificateCommonName(certs[0]);
                DetectedCodeSigningKey = certs[0].Thumbprint;
                DetectedBundleId       = identity.BundleId;
                DetectedAppId          = DetectedBundleId;

                ReportDetectedCodesignInfo();

                return(!Log.HasLoggedErrors);
            }

            if (!IsAutoCodeSignProfile(ProvisioningProfile))
            {
                identity.Profile = MobileProvisionIndex.GetMobileProvision(platform, ProvisioningProfile);

                if (identity.Profile == null)
                {
                    Log.LogError(MSBStrings.E0144, PlatformName, ProvisioningProfile);
                    return(false);
                }

                var profile = identity.Profile;                 // capture ref for lambda

                if (certs.Count > 0)
                {
                    identity.SigningKey = certs.FirstOrDefault(c => profile.DeveloperCertificates.Any(p => p.Thumbprint == c.Thumbprint));
                    if (identity.SigningKey == null)
                    {
                        Log.LogError(MSBStrings.E0145, PlatformName, ProvisioningProfile);
                        return(false);
                    }
                }

                identity.AppId = ConstructValidAppId(identity.Profile, identity.BundleId);
                if (identity.AppId == null)
                {
                    Log.LogError(null, null, null, AppManifest, 0, 0, 0, 0, MSBStrings.E0141, identity.BundleId, ProvisioningProfile);
                    return(false);
                }

                if (identity.SigningKey != null)
                {
                    codesignCommonName     = SecKeychain.GetCertificateCommonName(identity.SigningKey);
                    DetectedCodeSigningKey = identity.SigningKey.Thumbprint;
                }

                provisioningProfileName = identity.Profile.Name;

                DetectedProvisioningProfile = identity.Profile.Uuid;
                DetectedDistributionType    = identity.Profile.DistributionType.ToString();
                DetectedBundleId            = identity.BundleId;
                DetectedAppId = identity.AppId;

                ReportDetectedCodesignInfo();

                return(!Log.HasLoggedErrors);
            }

            if ((profiles = GetProvisioningProfiles(platform, type, identity, certs)) == null)
            {
                return(false);
            }

            if ((pairs = GetCodeSignIdentityPairs(profiles, certs)) == null)
            {
                return(false);
            }

            identity = GetBestMatch(pairs, identity);

            if (identity.Profile != null && identity.AppId != null)
            {
                codesignCommonName = identity.SigningKey != null?SecKeychain.GetCertificateCommonName(identity.SigningKey) : null;

                provisioningProfileName = identity.Profile.Name;

                DetectedCodeSigningKey      = identity.SigningKey?.Thumbprint;
                DetectedProvisioningProfile = identity.Profile.Uuid;
                DetectedBundleId            = identity.BundleId;
                DetectedAppId = identity.AppId;

                ReportDetectedCodesignInfo();
            }
            else
            {
                if (identity.SigningKey != null)
                {
                    Log.LogError(MSBStrings.E0146, identity.BundleId, identity.SigningKey);
                }
                else
                {
                    Log.LogError(MSBStrings.E0148, identity.BundleId);
                }
            }

            return(!Log.HasLoggedErrors);
        }
Exemple #55
0
        public virtual void ConfigureTask()
        {
            Task = CreateTask<CompileAppManifest> ();

            Task.AppBundleName = appBundleName;
            Task.AppBundleDir = "AppBundlePath";
            Task.AssemblyName = assemblyName;
            Task.AppManifest = CreateTempFile ("foo.plist");
            Task.BundleIdentifier = bundleIdentifier;
            Task.SdkPlatform = "iPhoneSimulator";

            Plist = new PDictionary ();
            Plist ["CFBundleDisplayName"] = displayName;
            Plist ["CFBundleIdentifier"] = identifier;
            Plist.Save (Task.AppManifest);
        }
        public override bool Execute()
        {
            var archiveDir = CreateArchiveDirectory();

            try {
                var plist       = PDictionary.FromFile(Path.Combine(AppBundleDir.ItemSpec, "Contents", "Info.plist"));
                var productsDir = Path.Combine(archiveDir, "Products");

                // Archive the Applications...
                var appDestDir = Path.Combine(productsDir, "Applications", Path.GetFileName(AppBundleDir.ItemSpec));
                Ditto(AppBundleDir.ItemSpec, appDestDir);

                // Archive the dSYMs...
                if (Directory.Exists(DSYMDir))
                {
                    var destDir = Path.Combine(archiveDir, "dSYMs", Path.GetFileName(DSYMDir));
                    Ditto(DSYMDir, destDir);
                }

                // Generate an archive Info.plist
                var arInfo = new PDictionary();
                var props  = new PDictionary();
                props.Add("ApplicationPath", new PString(string.Format("Applications/{0}", Path.GetFileName(AppBundleDir.ItemSpec))));
                props.Add("CFBundleIdentifier", new PString(plist.GetCFBundleIdentifier()));

                var version = plist.GetCFBundleShortVersionString();
                var build   = plist.GetCFBundleVersion();
                props.Add("CFBundleShortVersionString", new PString(version ?? (build ?? "1.0")));
                props.Add("CFBundleVersion", new PString(build ?? "1.0"));
                props.Add("SigningIdentity", SigningKey);

                arInfo.Add("ApplicationProperties", props);
                arInfo.Add("ArchiveVersion", new PNumber(2));
                arInfo.Add("CreationDate", new PDate(Now.ToUniversalTime()));
                arInfo.Add("Name", new PString(plist.GetCFBundleName() ?? plist.GetCFBundleDisplayName()));

                if (!string.IsNullOrEmpty(ProjectGuid))
                {
                    arInfo.Add("ProjectGuid", new PString(ProjectGuid));
                }

                if (!string.IsNullOrEmpty(ProjectTypeGuids))
                {
                    arInfo.Add("ProjectTypeGuids", new PString(ProjectTypeGuids));
                }

                if (!string.IsNullOrEmpty(SolutionPath))
                {
                    arInfo.Add("SolutionName", new PString(Path.GetFileNameWithoutExtension(SolutionPath)));
                    arInfo.Add("SolutionPath", new PString(SolutionPath));
                }

                if (!string.IsNullOrEmpty(InsightsApiKey))
                {
                    arInfo.Add("InsightsApiKey", new PString(InsightsApiKey));
                }

                arInfo.Save(Path.Combine(archiveDir, "Info.plist"));
                ArchiveDir = archiveDir;
            } catch (Exception ex) {
                Log.LogErrorFromException(ex);
                Directory.Delete(archiveDir, true);
            }

            return(!Log.HasLoggedErrors);
        }
Exemple #57
0
        protected virtual PDictionary GetCompiledEntitlements(MobileProvision profile, PDictionary template)
        {
            var entitlements = new PDictionary ();

            if (profile != null && MergeProfileEntitlements) {
                // start off with the settings from the provisioning profile
                foreach (var item in profile.Entitlements) {
                    if (!AllowedProvisioningKeys.Contains (item.Key))
                        continue;

                    var value = item.Value;

                    if (item.Key == "com.apple.developer.icloud-container-environment")
                        value = new PString ("Development");
                    else if (value is PDictionary)
                        value = MergeEntitlementDictionary ((PDictionary) value, profile);
                    else if (value is PString)
                        value = MergeEntitlementString ((PString) value, profile);
                    else if (value is PArray)
                        value = MergeEntitlementArray ((PArray) value, profile);
                    else
                        value = value.Clone ();

                    if (value != null)
                        entitlements.Add (item.Key, value);
                }
            }

            // merge in the user's values
            foreach (var item in template) {
                var value = item.Value;

                if (item.Key == "com.apple.developer.ubiquity-container-identifiers" ||
                    item.Key == "com.apple.developer.icloud-container-identifiers" ||
                    item.Key == "com.apple.developer.icloud-container-environment" ||
                    item.Key == "com.apple.developer.icloud-services") {
                    if (profile == null)
                        Log.LogWarning (null, null, null, Entitlements, 0, 0, 0, 0, "iCloud entitlements such as '" + item.Key + "' require a Provisioning Profile.");
                    else if (!profile.Entitlements.ContainsKey (item.Key))
                        Log.LogWarning (null, null, null, Entitlements, 0, 0, 0, 0, "The iCloud entitlement '" + item.Key + "' is not supported by the Provisioning Profile.");
                } else if (item.Key == ApplicationIdentifierKey) {
                    var str = value as PString;

                    // Ignore ONLY if it is empty, otherwise take the user's value
                    if (str == null || string.IsNullOrEmpty (str.Value))
                        continue;
                }

                if (value is PDictionary)
                    value = MergeEntitlementDictionary ((PDictionary) value, profile);
                else if (value is PString)
                    value = MergeEntitlementString ((PString) value, profile);
                else if (value is PArray)
                    value = MergeEntitlementArray ((PArray) value, profile);
                else
                    value = value.Clone ();

                if (value != null)
                    entitlements[item.Key] = value;
            }

            return entitlements;
        }
Exemple #58
0
        IEnumerable<ITaskItem> GetCompiledBundleResources(PDictionary output, string intermediateBundleDir)
        {
            var pwd = PathUtils.ResolveSymbolicLink (Environment.CurrentDirectory);
            PDictionary dict;
            PArray array;

            if (output.TryGetValue (string.Format ("com.apple.{0}.compilation-results", ToolName), out dict) && dict.TryGetValue ("output-files", out array)) {
                foreach (var path in array.OfType<PString> ().Select (x => x.Value)) {
                    // don't include the generated plist files as BundleResources
                    if (path.EndsWith ("partial-info.plist", StringComparison.Ordinal))
                        continue;

                    var vpath = PathUtils.AbsoluteToRelative (pwd, PathUtils.ResolveSymbolicLink (path));
                    var item = new TaskItem (vpath);

                    // Note: the intermediate bundle dir functions as a top-level bundle dir
                    var logicalName = PathUtils.AbsoluteToRelative (intermediateBundleDir, path);

                    if (logicalName.StartsWith ("../OnDemandResources/", StringComparison.Ordinal)) {
                        logicalName = logicalName.Substring (3);

                        var outputPath = Path.Combine (OutputPath, logicalName);

                        item.SetMetadata ("OutputPath", outputPath);
                    }

                    item.SetMetadata ("LogicalName", logicalName);
                    item.SetMetadata ("Optimize", "false");

                    yield return item;
                }
            }

            yield break;
        }
Exemple #59
0
        PDictionary MergeEntitlementDictionary(PDictionary dict, MobileProvision profile)
        {
            var result = new PDictionary ();

            foreach (var item in dict) {
                PObject value = item.Value;

                if (value is PDictionary)
                    value = MergeEntitlementDictionary ((PDictionary) value, profile);
                else if (value is PString)
                    value = MergeEntitlementString ((PString) value, profile);
                else if (value is PArray)
                    value = MergeEntitlementArray ((PArray) value, profile);
                else
                    value = value.Clone ();

                if (value != null)
                    result.Add (item.Key, value);
            }

            return result;
        }
        protected override bool Compile(PDictionary plist)
        {
            var currentSDK = IPhoneSdks.GetSdk(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 = 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");

            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);
                    }
                }
            }
        }
    }