public static string GetStoredCertificateName(IPhoneProject project, bool distribution) { var keys = project.UserProperties.GetValue <SigningKeyInformation> ("IPhoneSigningKeys"); if (keys != null) { string key = distribution? keys.Distribution : keys.Developer; if (!String.IsNullOrEmpty(key)) { return(key); } } return(null); }
public static BuildResult UpdateXibCodebehind (CodeBehindWriter writer, IPhoneProject project, IEnumerable<ProjectFile> allFiles, bool forceRegen) { BuildResult result = null; var projWrite = File.GetLastWriteTime (project.FileName); foreach (var xibFile in allFiles.Where (x => x.FilePath.Extension == ".xib" && x.BuildAction == BuildAction.Page)) { var designerFile = GetDesignerFile (xibFile); if (designerFile == null) continue; try { var designerWrite = File.GetLastWriteTime (designerFile.FilePath); if (forceRegen || designerWrite < projWrite || designerWrite < File.GetLastWriteTime (xibFile.FilePath)) { GenerateDesignerCode (writer, xibFile, designerFile); } } catch (Exception ex) { result = result ?? new BuildResult (); result.AddError (xibFile.FilePath, 0, 0, null, ex.Message); LoggingService.LogError (String.Format ("Error generating code for xib file '{0}'", xibFile.FilePath), ex); } } return result; }
static bool AddIconRelativeIfNotEmpty (IPhoneProject proj, PlistArray arr, FilePath iconFullPath, string name) { var icon = iconFullPath.ToRelative (proj.BaseDirectory).ToString (); if (string.IsNullOrEmpty (icon) || icon == ".") return false; arr.Add (null ?? icon); return true; }
static bool AddIconRelativeIfNotEmpty (IPhoneProject proj, PlistArray arr, FilePath iconFullPath) { return AddIconRelativeIfNotEmpty (proj, arr, iconFullPath, null); }
public IPhoneCodeBehind (IPhoneProject project) : base (project) { }
void GenerateXCodeProject(IPhoneProject proj, IPhoneProjectConfiguration conf, ConfigurationSelector slnConf) { string mtouchPath = IPhoneUtility.GetMtouchPath(proj.TargetRuntime, proj.TargetFramework); var xcodeDir = conf.OutputDirectory.Combine("XcodeProject"); if (!Directory.Exists(xcodeDir)) { try { Directory.CreateDirectory(xcodeDir); } catch (IOException ex) { MessageService.ShowException(ex, "Failed to create directory '" + xcodeDir + "' for Xcode project"); return; } } var args = new System.Text.StringBuilder(); args.AppendFormat("-xcode=\"{0}\" -v", xcodeDir); foreach (ProjectFile pf in proj.Files) { if (pf.BuildAction == BuildAction.Content) { var rel = pf.ProjectVirtualPath; args.AppendFormat(" -res=\"{0}\",\"{1}\"", pf.FilePath, rel); //hack around mtouch 1.0 bug. create resource directories string subdir = rel.ParentDirectory; if (string.IsNullOrEmpty(subdir)) { continue; } subdir = xcodeDir.Combine(subdir); try { if (!Directory.Exists(subdir)) { Directory.CreateDirectory(subdir); } } catch (IOException ex) { MessageService.ShowException(ex, "Failed to create directory '" + subdir + "' for Xcode project"); return; } } else if (pf.BuildAction == BuildAction.Page) { args.AppendFormat(" -res=\"{0}\"", pf.FilePath); } } args.AppendFormat(" -res=\"{0}\",\"Info.plist\"", conf.AppDirectory.Combine("Info.plist")); foreach (string asm in proj.GetReferencedAssemblies(slnConf).Distinct()) { args.AppendFormat(" -r=\"{0}\"", asm); } IPhoneBuildExtension.AppendExtrasMtouchArgs(args, proj, conf); args.AppendFormat(" \"{0}\"", conf.CompiledOutputName); string argStr = args.ToString(); var console = (IConsole)IdeApp.Workbench.ProgressMonitors.GetOutputProgressMonitor( GettextCatalog.GetString("Generate Xcode project"), MonoDevelop.Ide.Gui.Stock.RunProgramIcon, true, true); console.Log.WriteLine(mtouchPath + " " + argStr); Runtime.ProcessService.StartConsoleProcess(mtouchPath, argStr, conf.OutputDirectory, console, null); }
static BuildResult GetIdentity (IProgressMonitor monitor, IPhoneProject proj, IPhoneProjectConfiguration conf, out IPhoneAppIdentity identity) { var result = new BuildResult (); identity = new IPhoneAppIdentity (); bool defaultID = string.IsNullOrEmpty (proj.BundleIdentifier); if (!defaultID) identity.BundleID = proj.BundleIdentifier; //treat empty as "developer automatic" if (string.IsNullOrEmpty (conf.CodesignKey)) { conf.CodesignKey = IPhoneProject.DEV_CERT_PREFIX; } IList<X509Certificate2> certs = null; if (conf.CodesignKey == IPhoneProject.DEV_CERT_PREFIX || conf.CodesignKey == IPhoneProject.DIST_CERT_PREFIX) { certs = Keychain.FindNamedSigningCertificates (x => x.StartsWith (conf.CodesignKey)).ToList (); if (certs.Count == 0) { result.AddError ("No valid iPhone code signing keys found in keychain."); return result; } } else { identity.SigningKey = Keychain.FindNamedSigningCertificates (x => x == conf.CodesignKey).FirstOrDefault (); if (identity.SigningKey == null) { result.AddError (string.Format ("iPhone code signing key '{0}' not found in keychain.", conf.CodesignKey)); return result; } certs = new X509Certificate2[] { identity.SigningKey }; } if (!string.IsNullOrEmpty (conf.CodesignProvision)) { //if the profile was installed by Xcode, we can determine the filename directly from the UUID //but if it was installed by iTunes, we need to search all profiles for the UUID. var file = MobileProvision.ProfileDirectory.Combine (conf.CodesignProvision).ChangeExtension (".mobileprovision"); if (File.Exists (file)) { try { identity.Profile = MobileProvision.LoadFromFile (file); } catch (Exception ex) { string msg = "Could not read provisioning profile '" + file + "'."; monitor.ReportError (msg, ex); result.AddError (msg); return result; } } else { identity.Profile = MobileProvision.GetAllInstalledProvisions () .Where (p => p.Uuid == conf.CodesignProvision).FirstOrDefault (); } if (identity.Profile == null) { result.AddError (string.Format ("The specified provisioning profile '{0}' could not be found", conf.CodesignProvision)); return result; } var prof = identity.Profile; //capture ref for lambda identity.SigningKey = certs.Where (c => prof.DeveloperCertificates .Any (p => p.Thumbprint == c.Thumbprint)).FirstOrDefault (); if (identity.SigningKey == null) { result.AddError (string.Format ("No iPhone code signing key matches specified provisioning profile '{0}'.", conf.CodesignProvision)); return result; } if (defaultID) { identity.BundleID = GetDefaultBundleID (proj, GetProfileBundleID (identity.Profile)); result.AddWarning (string.Format ("Project does not have bundle identifier specified. Generated '{0}' to match provisioning profile.", identity.BundleID)); } bool exact; identity.AppID = ConstructValidAppId (identity.Profile, identity.BundleID, out exact); if (identity.AppID == null) { result.AddError (string.Format ( "Project bundle ID '{0}' does not match specified provisioning profile '{1}'", identity.BundleID, conf.CodesignProvision)); return result; } return result; } var pairs = (from p in MobileProvision.GetAllInstalledProvisions () from c in certs where p.DeveloperCertificates.Any (d => d.Thumbprint == c.Thumbprint) select new { Cert = c, Profile = p }).ToList (); if (pairs.Count == 0) { result.AddError ("No installed provisioning profiles match the installed iPhone code signing keys."); return result; } if (!defaultID) { //find a provisioning profile with compatible appid, preferring exact match foreach (var p in pairs) { bool exact; var id = ConstructValidAppId (p.Profile, identity.BundleID, out exact); if (id != null) { if (exact || identity.AppID == null) { identity.Profile = p.Profile; identity.SigningKey = p.Cert; identity.AppID = id; } if (exact) break; } } } else { //pick provisioning profile to provide appid and better default bundle ID, preferring star bundle IDs foreach (var p in pairs) { var suggestion = GetProfileBundleID (p.Profile); bool star = (suggestion != null) && suggestion.EndsWith ("*"); if (star || identity.Profile == null) { identity.Profile = p.Profile; identity.SigningKey = p.Cert; identity.BundleID = GetDefaultBundleID (proj, suggestion); bool exact; identity.AppID = ConstructValidAppId (p.Profile, identity.BundleID, out exact); } if (star) break; } result.AddWarning (string.Format ("Project does not have bundle identifier specified. Generated '{0}' to match an installed provisioning profile.", identity.BundleID)); } if (identity.Profile != null && identity.SigningKey != null && identity.AppID != null) return result; if (identity.SigningKey != null) { result.AddError (string.Format ( "Bundle identifier '{0}' does not match any installed provisioning profile for selected signing identity '{0}'.", identity.BundleID, identity.SigningKey)); } else { result.AddError (string.Format ( "Bundle identifier '{0}' does not match any installed provisioning profile.", identity.BundleID)); } return result; }
static IEnumerable<FilePair> GetIconContentFiles (IPhoneSdkVersion sdkVersion, IPhoneProject proj, IPhoneProjectConfiguration conf) { bool v3_2_orNewer = sdkVersion >= IPhoneSdkVersion.V3_2; bool v4_0_orNewer = sdkVersion >= IPhoneSdkVersion.V4_0; bool supportsIPhone = (proj.SupportedDevices & TargetDevice.IPhone) != 0; bool supportsIPad = (proj.SupportedDevices & TargetDevice.IPad) != 0; var appDir = conf.AppDirectory; if (supportsIPhone && !proj.BundleIcon.IsNullOrEmpty) yield return new FilePair (proj.BundleIcon, appDir.Combine ("Icon.png")); if (!proj.BundleIconSpotlight.IsNullOrEmpty) yield return new FilePair (proj.BundleIconSpotlight, appDir.Combine ("Icon-Small.png")); if (v3_2_orNewer && supportsIPad) { if (!proj.BundleIconIPad.IsNullOrEmpty) yield return new FilePair (proj.BundleIconIPad, appDir.Combine ("Icon-72.png")); if (!proj.BundleIconIPadSpotlight.IsNullOrEmpty) yield return new FilePair (proj.BundleIconIPadSpotlight, appDir.Combine ("Icon-Small-50.png")); } if (supportsIPhone && v4_0_orNewer) { if (!proj.BundleIconHigh.IsNullOrEmpty) yield return new FilePair (proj.BundleIconHigh, appDir.Combine ("*****@*****.**")); if (!proj.BundleIconSpotlightHigh.IsNullOrEmpty) yield return new FilePair (proj.BundleIconSpotlightHigh, appDir.Combine ("*****@*****.**")); } }
static string GetFilteredProjectName (IPhoneProject project) { var sb = new StringBuilder (); foreach (char c in project.Name) if (char.IsLetterOrDigit (c)) sb.Append (c); return sb.Length > 0? sb.ToString ().ToLowerInvariant () : "application"; }
static string GetDefaultBundleID (IPhoneProject project, string suggestion) { if (string.IsNullOrEmpty (suggestion)) { return "com.yourcompany." + GetFilteredProjectName (project); } else if (suggestion.EndsWith ("*")) { return suggestion.Substring (0, suggestion.Length - 1) + GetFilteredProjectName (project); } else { return suggestion; } }
static internal void AppendExtrasMtouchArgs (ProcessArgumentBuilder args, IPhoneSdkVersion sdkVersion, IPhoneProject proj, IPhoneProjectConfiguration conf) { if (conf.MtouchDebug) args.Add ("-debug"); switch (conf.MtouchLink) { case MtouchLinkMode.SdkOnly: args.Add ("-linksdkonly"); break; case MtouchLinkMode.None: args.Add ("-nolink"); break; case MtouchLinkMode.Full: default: break; } if (!string.IsNullOrEmpty (conf.MtouchI18n)) { args.AddQuotedFormat ("-i18n={0}", conf.MtouchI18n); } if (!sdkVersion.Equals (IPhoneSdkVersion.V3_0)) args.AddQuotedFormat ("-sdk={0}", sdkVersion); if (conf.MtouchMinimumOSVersion != "3.0") args.AddQuotedFormat ("-targetver={0}", conf.MtouchMinimumOSVersion); AddExtraArgs (args, conf.MtouchExtraArgs, proj, conf); }
internal ProcessStartInfo GetTool (string tool, IPhoneProject project, IProgressMonitor monitor, out BuildResult error) { var toolPath = project.TargetRuntime.GetToolPath (project.TargetFramework, tool); if (String.IsNullOrEmpty (toolPath)) { var err = GettextCatalog.GetString ("Error: Unable to find '" + tool + "' tool."); monitor.ReportError (err, null); error = new BuildResult (); error.AddError (null, 0, 0, null, err); return null; } error = null; return new ProcessStartInfo (toolPath) { UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, }; }
BuildResult UpdateInfoPlist (IProgressMonitor monitor, IPhoneProject proj, IPhoneProjectConfiguration conf, IPhoneAppIdentity identity, ProjectFile template, string plistOut) { return CreateMergedPlist (monitor, conf, template, plistOut, (IPhoneProjectConfiguration config, PlistDocument doc) => { var result = new BuildResult (); var dict = doc.Root as PlistDictionary; if (dict == null) doc.Root = dict = new PropertyList.PlistDictionary (); bool sim = conf.Platform != IPhoneProject.PLAT_IPHONE; SetIfNotPresent (dict, "CFBundleDevelopmentRegion", String.IsNullOrEmpty (proj.BundleDevelopmentRegion)? "English" : proj.BundleDevelopmentRegion); SetIfNotPresent (dict, "CFBundleDisplayName", proj.BundleDisplayName ?? proj.Name); SetIfNotPresent (dict, "CFBundleExecutable", conf.NativeExe.FileName); //iphone icons if ((proj.SupportedDevices & TargetDevice.IPhone) != 0) { if (!dict.ContainsKey ("CFBundleIconFile")) { var icon = proj.BundleIcon.ToRelative (proj.BaseDirectory); if (icon.IsNullOrEmpty || icon.ToString () == ".") result.AddWarning ("Application bundle icon has not been set"); else dict ["CFBundleIconFile"] = icon.FileName; } } //ipad and universal icons if ((proj.SupportedDevices & TargetDevice.IPad) != 0 && !dict.ContainsKey ("CFBundleIconFiles")) { var arr = new PlistArray (); dict["CFBundleIconFiles"] = arr; //universal only if ((proj.SupportedDevices & TargetDevice.IPhone) != 0) AddRelativeIfNotEmpty (proj, arr, proj.BundleIcon); //ipad and universal AddRelativeIfNotEmpty (proj, arr, proj.BundleIconSpotlight); AddRelativeIfNotEmpty (proj, arr, proj.BundleIconIPadSpotlight); if (!AddRelativeIfNotEmpty (proj, arr, proj.BundleIconIPad)) result.AddWarning ("iPad bundle icon has not been set"); } SetIfNotPresent (dict, "CFBundleIdentifier", identity.BundleID); SetIfNotPresent (dict, "CFBundleInfoDictionaryVersion", "6.0"); SetIfNotPresent (dict, "CFBundleName", proj.Name); SetIfNotPresent (dict, "CFBundlePackageType", "APPL"); if (!sim) dict["CFBundleResourceSpecification"] = "ResourceRules.plist"; SetIfNotPresent (dict, "CFBundleSignature", "????"); SetIfNotPresent (dict, "CFBundleSupportedPlatforms", new PropertyList.PlistArray () { sim? "iPhoneSimulator" : "iPhoneOS" }); SetIfNotPresent (dict, "CFBundleVersion", proj.BundleVersion ?? "1.0"); SetIfNotPresent (dict, "DTPlatformName", sim? "iphonesimulator" : "iphoneos"); SetIfNotPresent (dict, "DTSDKName", (sim? "iphonesimulator" : "iphoneos") + conf.MtouchSdkVersion); SetIfNotPresent (dict, "LSRequiresIPhoneOS", true); if (proj.SupportedDevices != TargetDevice.IPhone) SetIfNotPresent (dict, "UIDeviceFamily", GetSupportedDevices (proj.SupportedDevices)); SetIfNotPresent (dict, "DTPlatformVersion", conf.MtouchSdkVersion); SetIfNotPresent (dict, "MinimumOSVersion", conf.MtouchMinimumOSVersion); SetNibProperty (dict, proj, proj.MainNibFile, "NSMainNibFile"); if (proj.SupportedDevices == TargetDevice.IPhoneAndIPad) SetNibProperty (dict, proj, proj.MainNibFileIPad, "NSMainNibFile~ipad"); return result; }); }
static internal void AppendExtrasMtouchArgs (StringBuilder args, IPhoneProject proj, IPhoneProjectConfiguration conf) { if (conf.MtouchDebug) args.Append (" -debug"); switch (conf.MtouchLink) { case MtouchLinkMode.SdkOnly: args.Append (" -linksdkonly"); break; case MtouchLinkMode.None: args.Append (" -nolink"); break; case MtouchLinkMode.Full: default: break; } if (!string.IsNullOrEmpty (conf.MtouchI18n)) { args.Append (" -i18n="); args.Append (conf.MtouchI18n); } if (conf.MtouchSdkVersion != "3.0") args.AppendFormat (" -sdk=\"{0}\"", conf.MtouchSdkVersion); if (conf.MtouchMinimumOSVersion != "3.0") args.AppendFormat (" -targetver=\"{0}\"", conf.MtouchMinimumOSVersion); AppendExtraArgs (args, conf.MtouchExtraArgs, proj, conf); }
static bool SetNibProperty (PlistDictionary dict, IPhoneProject proj, FilePath mainNibProp, string propName) { if (!dict.ContainsKey (propName)) { if (mainNibProp.IsNullOrEmpty) { return false; } else { string mainNib = mainNibProp.ToRelative (proj.BaseDirectory); if (mainNib.EndsWith (".nib") || mainNib.EndsWith (".xib")) mainNib = mainNib.Substring (0, mainNib.Length - 4).Replace ('\\', '/'); dict[propName] = mainNib; } } return true; }
static BuildResult GenXcent (IProgressMonitor monitor, IPhoneSdkVersion sdkVersion, IPhoneProject proj, IPhoneProjectConfiguration conf, IPhoneAppIdentity identity, out string xcentName) { xcentName = conf.CompiledOutputName.ChangeExtension (".xcent"); monitor.BeginTask (GettextCatalog.GetString ("Processing entitlements file"), 0); string srcFile; if (!string.IsNullOrEmpty (conf.CodesignEntitlements)) { if (!File.Exists (conf.CodesignEntitlements)) return BuildError ("Entitlements file \"" + conf.CodesignEntitlements + "\" not found."); srcFile = conf.CodesignEntitlements; } else { srcFile = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" + sdkVersion.ToString () + ".sdk/Entitlements.plist"; } var doc = new PlistDocument (); try { doc.LoadFromXmlFile (srcFile); } catch (Exception ex) { monitor.Log.WriteLine (ex.ToString ()); return BuildError ("Error loading entitlements source file '" + srcFile +"'."); } //insert the app ID into the plist at the beginning var oldDict = doc.Root as PlistDictionary; var newDict = new PlistDictionary (); doc.Root = newDict; newDict["application-identifier"] = identity.AppID; var keychainGroups = new PlistArray (new [] { identity.AppID } ); newDict["keychain-access-groups"] = keychainGroups; //merge in the user's values foreach (var item in oldDict) { //FIXME: we currently ignore these items, and write our own, but maybe we should do substitutes //i.e. $(AppIdentifierPrefix)$(CFBundleIdentifier) if (item.Key == "application-identifier") { var str = item.Value as PlistString; if (str == null || string.IsNullOrEmpty (str.Value) || str.Value.Contains ('$')) continue; } else if (item.Key == "keychain-access-groups") { //special handling, merge into the array var keyArr = item.Value as PlistArray; foreach (var key in keyArr) { var str = key as PlistString; if (str != null && !string.IsNullOrEmpty (str.Value) && !str.Value.Contains ('$')) { keychainGroups.Add (str.Value); } } continue; } newDict[item.Key] = item.Value; } //merge in the settings from the provisioning profile, skipping some foreach (var item in identity.Profile.Entitlements) if (item.Key != "application-identifier" && item.Key != "keychain-access-groups") newDict[item.Key] = item.Value; try { WriteXcent (doc, xcentName); } catch (Exception ex) { monitor.Log.WriteLine (ex.ToString ()); return BuildError ("Error writing entitlements file '" + xcentName +"'."); } monitor.EndTask (); return null; }
internal ProcessStartInfo GetMTouch (IPhoneProject project, IProgressMonitor monitor, out BuildResult error) { return MacBuildUtilities.GetTool ("mtouch", project, monitor, out error); }
static BuildResult SignAppBundle (IProgressMonitor monitor, IPhoneProject proj, IPhoneProjectConfiguration conf, X509Certificate2 key, string resRules, string xcent) { monitor.BeginTask (GettextCatalog.GetString ("Signing application"), 0); var args = new ProcessArgumentBuilder (); args.Add ("-v", "-f", "-s"); args.AddQuoted (Keychain.GetCertificateCommonName (key)); args.AddQuotedFormat ("--resource-rules={0}", resRules); args.Add ("--entitlements"); args.AddQuoted (xcent); args.AddQuoted (conf.AppDirectory); AddExtraArgs (args, conf.CodesignExtraArgs, proj, conf); int signResultCode; var psi = new ProcessStartInfo ("codesign") { UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, Arguments = args.ToString (), }; monitor.Log.WriteLine ("codesign " + psi.Arguments); psi.EnvironmentVariables.Add ("CODESIGN_ALLOCATE", "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate"); string output; if ((signResultCode = MacBuildUtilities.ExecuteCommand (monitor, psi, out output)) != 0) { monitor.Log.WriteLine (output); return BuildError (string.Format ("Code signing failed with error code {0}. See output for details.", signResultCode)); } monitor.EndTask (); return null; }
static BuildResult ProcessPackaging (IProgressMonitor monitor, IPhoneSdkVersion sdkVersion, IPhoneProject proj, IPhoneProjectConfiguration conf, IPhoneAppIdentity identity) { //don't bother signing in the sim bool isDevice = conf.Platform == IPhoneProject.PLAT_IPHONE; if (!isDevice) return null; BuildResult result = new BuildResult (); var pkgInfo = conf.AppDirectory.Combine ("PkgInfo"); if (!File.Exists (pkgInfo)) using (var f = File.OpenWrite (pkgInfo)) f.Write (new byte [] { 0X41, 0X50, 0X50, 0X4C, 0x3f, 0x3f, 0x3f, 0x3f}, 0, 8); if (result.Append (CompressResources (monitor, conf)).ErrorCount > 0) return result; if (result.Append (EmbedProvisioningProfile (monitor, conf, identity.Profile)).ErrorCount > 0) return result; string xcent; if (result.Append (GenXcent (monitor, sdkVersion, proj, conf, identity, out xcent)).ErrorCount > 0) return result; string resRules; if (result.Append (PrepareResourceRules (monitor, sdkVersion, conf, out resRules)).ErrorCount > 0) return result; if (result.Append (SignAppBundle (monitor, proj, conf, identity.SigningKey, resRules, xcent)).ErrorCount > 0) return result; return result; }
static internal void AppendExtrasMtouchArgs (ProcessArgumentBuilder args, IPhoneSdkVersion sdkVersion, IPhoneProject proj, IPhoneProjectConfiguration conf) { if (conf.MtouchDebug) args.Add ("-debug"); switch (conf.MtouchLink) { case MtouchLinkMode.SdkOnly: args.Add ("-linksdkonly"); break; case MtouchLinkMode.None: args.Add ("-nolink"); break; case MtouchLinkMode.Full: default: break; } if (!string.IsNullOrEmpty (conf.MtouchI18n)) { args.AddQuotedFormat ("-i18n={0}", conf.MtouchI18n); } if (!sdkVersion.Equals (IPhoneSdkVersion.V3_0)) args.AddQuotedFormat ("-sdk={0}", sdkVersion); if (conf.MtouchMinimumOSVersion != "3.0") args.AddQuotedFormat ("-targetver={0}", conf.MtouchMinimumOSVersion); if (IPhoneFramework.MonoTouchVersion >= new IPhoneSdkVersion (3, 99)) { if (conf.MtouchUseSGen) args.Add ("--sgen"); if (conf.MtouchUseLlvm) { args.Add ("--llvm"); switch (conf.MtouchArch) { case MtouchArch.ARMv6_ARMv7: args.Add ("--fat"); break; case MtouchArch.ARMv7: args.Add ("--armv7"); break; } if (conf.MtouchArch != MtouchArch.ARMv6 && conf.MtouchUseThumb) args.Add ("--thumb"); } } AddExtraArgs (args, conf.MtouchExtraArgs, proj, conf); }
public static string GetStoredCertificateName (IPhoneProject project, bool distribution) { var keys = project.UserProperties.GetValue<SigningKeyInformation> ("IPhoneSigningKeys"); if (keys != null) { string key = distribution? keys.Distribution : keys.Developer; if (!String.IsNullOrEmpty (key)) return key; } return null; }
static void AddExtraArgs (ProcessArgumentBuilder args, string extraArgs, IPhoneProject proj, IPhoneProjectConfiguration conf) { if (!string.IsNullOrEmpty (extraArgs)) { var customTags = new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase) { { "projectdir", proj.BaseDirectory }, { "solutiondir", proj.ParentSolution.BaseDirectory }, { "appbundledir", conf.AppDirectory }, { "targetpath", conf.CompiledOutputName }, { "targetdir", conf.CompiledOutputName.ParentDirectory }, { "targetname", conf.CompiledOutputName.FileName }, { "targetext", conf.CompiledOutputName.Extension }, }; args.Add (StringParserService.Parse (extraArgs, customTags)); } }
void GenerateXCodeProject (IPhoneProject proj, IPhoneProjectConfiguration conf, ConfigurationSelector slnConf) { string mtouchPath = IPhoneUtility.GetMtouchPath (proj.TargetRuntime, proj.TargetFramework); var xcodeDir = conf.OutputDirectory.Combine ("XcodeProject"); if (!Directory.Exists (xcodeDir)) { try { Directory.CreateDirectory (xcodeDir); } catch (IOException ex) { MessageService.ShowException (ex, "Failed to create directory '" + xcodeDir +"' for Xcode project"); return; } } var args = new ProcessArgumentBuilder (); args.AddQuotedFormat ("-xcode={0}", xcodeDir); args.Add ("-v"); foreach (ProjectFile pf in proj.Files) { if (pf.BuildAction == BuildAction.Content) { var rel = pf.ProjectVirtualPath; args.AddQuotedFormat ("-res={0},{1}", pf.FilePath, rel); //hack around mtouch 1.0 bug. create resource directories string subdir = rel.ParentDirectory; if (string.IsNullOrEmpty (subdir)) continue; subdir = xcodeDir.Combine (subdir); try { if (!Directory.Exists (subdir)) Directory.CreateDirectory (subdir); } catch (IOException ex) { MessageService.ShowException (ex, "Failed to create directory '" + subdir +"' for Xcode project"); return; } } else if (pf.BuildAction == BuildAction.Page) { args.AddQuotedFormat ("-res={0}", pf.FilePath); } } args.AddQuotedFormat ("-res={0},Info.plist", conf.AppDirectory.Combine ("Info.plist")); foreach (string asm in proj.GetReferencedAssemblies (slnConf).Distinct ()) args.AddQuotedFormat ("-r={0}", asm); var sdkVersion = conf.MtouchSdkVersion.ResolveIfDefault (); if (!IPhoneFramework.SdkIsInstalled (sdkVersion)) sdkVersion = IPhoneFramework.GetClosestInstalledSdk (sdkVersion); IPhoneBuildExtension.AppendExtrasMtouchArgs (args, sdkVersion, proj, conf); args.AddQuoted (conf.CompiledOutputName); string argStr = args.ToString (); var console = (IConsole) IdeApp.Workbench.ProgressMonitors.GetOutputProgressMonitor ( GettextCatalog.GetString ("Generate Xcode project"), MonoDevelop.Ide.Gui.Stock.RunProgramIcon, true, true); console.Log.WriteLine (mtouchPath + " " + argStr); Runtime.ProcessService.StartConsoleProcess (mtouchPath, argStr, conf.OutputDirectory, console, null); }
BuildResult UpdateInfoPlist (IProgressMonitor monitor, IPhoneSdkVersion sdkVersion, IPhoneProject proj, IPhoneProjectConfiguration conf, IPhoneAppIdentity identity, ProjectFile template, string plistOut) { return MacBuildUtilities.CreateMergedPlist (monitor, template, plistOut, (PlistDocument doc) => { var result = new BuildResult (); var dict = doc.Root as PlistDictionary; if (dict == null) doc.Root = dict = new PlistDictionary (); bool sim = conf.Platform != IPhoneProject.PLAT_IPHONE; bool v3_2_orNewer = sdkVersion >= IPhoneSdkVersion.V3_2; bool v3_1_orNewer = sdkVersion >= IPhoneSdkVersion.V3_1; bool v4_0_orNewer = sdkVersion >= IPhoneSdkVersion.V4_0; bool supportsIPhone = (proj.SupportedDevices & TargetDevice.IPhone) != 0; bool supportsIPad = (proj.SupportedDevices & TargetDevice.IPad) != 0; var sdkSettings = IPhoneFramework.GetSdkSettings (sdkVersion); var dtSettings = IPhoneFramework.GetDTSettings (); SetIfNotPresent (dict, "BuildMachineOSBuild", dtSettings.BuildMachineOSBuild); SetIfNotPresent (dict, "CFBundleDevelopmentRegion", String.IsNullOrEmpty (proj.BundleDevelopmentRegion)? "en" : proj.BundleDevelopmentRegion); SetIfNotPresent (dict, "CFBundleDisplayName", proj.BundleDisplayName ?? proj.Name); SetIfNotPresent (dict, "CFBundleExecutable", conf.NativeExe.FileName); // < 3.2 icon if (supportsIPhone) { if (!dict.ContainsKey ("CFBundleIconFile")) { var icon = proj.BundleIcon.ToRelative (proj.BaseDirectory); if (icon.IsNullOrEmpty || icon.ToString () == ".") result.AddWarning ("Application bundle icon has not been set (iPhone Application options panel)"); else dict ["CFBundleIconFile"] = icon.FileName; } } //newer icons - see http://developer.apple.com/library/ios/#qa/qa2010/qa1686.html if (v3_2_orNewer && !dict.ContainsKey ("CFBundleIconFiles")) { var arr = new PlistArray (); dict["CFBundleIconFiles"] = arr; if (supportsIPhone) AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIcon, "Icon.png"); if (v4_0_orNewer && supportsIPhone) if (!AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconHigh, "*****@*****.**")) result.AddWarning ("iPhone high res bundle icon has not been set (iPhone Application options panel)"); if (supportsIPad) if (!AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconIPad, "Icon-72.png")) result.AddWarning ("iPad bundle icon has not been set (iPhone Application options panel)"); AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconSpotlight, "Icon-Small.png"); if (supportsIPad) AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconIPadSpotlight, "Icon-Small-50.png"); if (v4_0_orNewer && supportsIPhone) AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconSpotlightHigh, "*****@*****.**"); } SetIfNotPresent (dict, "CFBundleIdentifier", identity.BundleID); SetIfNotPresent (dict, "CFBundleInfoDictionaryVersion", "6.0"); SetIfNotPresent (dict, "CFBundleName", proj.Name); SetIfNotPresent (dict, "CFBundlePackageType", "APPL"); if (!sim) dict["CFBundleResourceSpecification"] = "ResourceRules.plist"; SetIfNotPresent (dict, "CFBundleSignature", "????"); SetIfNotPresent (dict, "CFBundleSupportedPlatforms", new PlistArray () { sim? "iPhoneSimulator" : "iPhoneOS" }); SetIfNotPresent (dict, "CFBundleVersion", proj.BundleVersion ?? "1.0"); if (!sim) { SetIfNotPresent (dict, "DTCompiler", sdkSettings.DTCompiler); SetIfNotPresent (dict, "DTPlatformBuild", dtSettings.DTPlatformBuild); SetIfNotPresent (dict, "DTSDKBuild", sdkSettings.DTSDKBuild); } SetIfNotPresent (dict, "DTPlatformName", sim? "iphonesimulator" : "iphoneos"); if (!sim) { SetIfNotPresent (dict, "DTPlatformVersion", dtSettings.DTPlatformVersion); } SetIfNotPresent (dict, "DTSDKName", sim? sdkSettings.AlternateSDK : sdkSettings.CanonicalName); if (!sim) { SetIfNotPresent (dict, "DTXcode", dtSettings.DTXcode); SetIfNotPresent (dict, "DTXcodeBuild", dtSettings.DTXcodeBuild); } SetIfNotPresent (dict, "LSRequiresIPhoneOS", true); if (v3_2_orNewer) SetIfNotPresent (dict, "UIDeviceFamily", GetSupportedDevices (proj.SupportedDevices)); if (v3_1_orNewer) { if (conf.MtouchArch != MtouchArch.ARMv6_ARMv7) { var val = conf.MtouchArch == MtouchArch.ARMv6? "armv6" : "armv7"; var key = "UIRequiredDeviceCapabilities"; var caps = dict.TryGetValue (key) ?? (dict[key] = new PlistArray ()); var a = caps as PlistArray; if (a != null) { a.Add (val); } else { var d = (PlistDictionary) caps; d[val] = new PlistBoolean (true); } } } SetIfNotPresent (dict, "MinimumOSVersion", conf.MtouchMinimumOSVersion); SetNibProperty (dict, proj, proj.MainNibFile, "NSMainNibFile"); if (proj.SupportedDevices == TargetDevice.IPhoneAndIPad) SetNibProperty (dict, proj, proj.MainNibFileIPad, "NSMainNibFile~ipad"); if (v3_2_orNewer) { if (!dict.ContainsKey (OrientationUtil.KEY)) { result.AddWarning ("Supported orientations have not been set (iPhone Application options panel)"); } else { var val = OrientationUtil.Parse ((PlistArray)dict[OrientationUtil.KEY]); if (!OrientationUtil.IsValidPair (val)) result.AddWarning ("Supported orientations are not matched pairs (Info.plist)"); if (dict.ContainsKey (OrientationUtil.KEY_IPAD)) { var pad = OrientationUtil.Parse ((PlistArray)dict[OrientationUtil.KEY_IPAD]); if (pad != Orientation.None && !OrientationUtil.IsValidPair (pad)) result.AddWarning ("iPad orientations are not matched pairs (Info.plist)"); } } } return result; }); }
public IPhoneCodeBehind(IPhoneProject project) : base(project) { }
BuildResult UpdateInfoPlist (IProgressMonitor monitor, IPhoneProject proj, IPhoneProjectConfiguration conf, IPhoneAppIdentity identity, ProjectFile template, string plistOut) { return MacBuildUtilities.CreateMergedPlist (monitor, template, plistOut, (PlistDocument doc) => { var result = new BuildResult (); var dict = doc.Root as PlistDictionary; if (dict == null) doc.Root = dict = new PlistDictionary (); bool sim = conf.Platform != IPhoneProject.PLAT_IPHONE; var sdkversion = IPhoneSdkVersion.Parse (conf.MtouchSdkVersion); bool v3_2_orNewer = sdkversion.CompareTo (IPhoneSdkVersion.V3_2) >= 0; bool v4_0_orNewer = sdkversion.CompareTo (IPhoneSdkVersion.V4_0) >= 0; bool supportsIPhone = (proj.SupportedDevices & TargetDevice.IPhone) != 0; bool supportsIPad = (proj.SupportedDevices & TargetDevice.IPad) != 0; SetIfNotPresent (dict, "CFBundleDevelopmentRegion", String.IsNullOrEmpty (proj.BundleDevelopmentRegion)? "English" : proj.BundleDevelopmentRegion); SetIfNotPresent (dict, "CFBundleDisplayName", proj.BundleDisplayName ?? proj.Name); SetIfNotPresent (dict, "CFBundleExecutable", conf.NativeExe.FileName); // < 3.2 icon if (supportsIPhone) { if (!dict.ContainsKey ("CFBundleIconFile")) { var icon = proj.BundleIcon.ToRelative (proj.BaseDirectory); if (icon.IsNullOrEmpty || icon.ToString () == ".") result.AddWarning ("Application bundle icon has not been set (iPhone Application options panel)"); else dict ["CFBundleIconFile"] = icon.FileName; } } //newer icons if (v3_2_orNewer && !dict.ContainsKey ("CFBundleIconFiles")) { var arr = new PlistArray (); dict["CFBundleIconFiles"] = arr; if (supportsIPhone) AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIcon); AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconSpotlight, "Icon-Small.png"); if (supportsIPad) { AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconIPadSpotlight, "Icon-Small-50.png"); if (!AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconIPad)) result.AddWarning ("iPad bundle icon has not been set (iPhone Application options panel)"); } if (v4_0_orNewer) { if (supportsIPhone) { if (!AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconHigh)) result.AddWarning ("iPhone high res bundle icon has not been set (iPhone Application options panel)"); AddIconRelativeIfNotEmpty (proj, arr, proj.BundleIconSpotlightHigh, "*****@*****.**"); } } } SetIfNotPresent (dict, "CFBundleIdentifier", identity.BundleID); SetIfNotPresent (dict, "CFBundleInfoDictionaryVersion", "6.0"); SetIfNotPresent (dict, "CFBundleName", proj.Name); SetIfNotPresent (dict, "CFBundlePackageType", "APPL"); if (!sim) dict["CFBundleResourceSpecification"] = "ResourceRules.plist"; SetIfNotPresent (dict, "CFBundleSignature", "????"); SetIfNotPresent (dict, "CFBundleSupportedPlatforms", new PlistArray () { sim? "iPhoneSimulator" : "iPhoneOS" }); SetIfNotPresent (dict, "CFBundleVersion", proj.BundleVersion ?? "1.0"); SetIfNotPresent (dict, "DTPlatformName", sim? "iphonesimulator" : "iphoneos"); SetIfNotPresent (dict, "DTSDKName", IPhoneFramework.GetDTSdkName (sdkversion, sim)); SetIfNotPresent (dict, "LSRequiresIPhoneOS", true); if (v3_2_orNewer) SetIfNotPresent (dict, "UIDeviceFamily", GetSupportedDevices (proj.SupportedDevices)); SetIfNotPresent (dict, "DTPlatformVersion", IPhoneFramework.DTPlatformVersion); SetIfNotPresent (dict, "MinimumOSVersion", conf.MtouchMinimumOSVersion); SetNibProperty (dict, proj, proj.MainNibFile, "NSMainNibFile"); if (proj.SupportedDevices == TargetDevice.IPhoneAndIPad) SetNibProperty (dict, proj, proj.MainNibFileIPad, "NSMainNibFile~ipad"); if (v3_2_orNewer) { if (!dict.ContainsKey (OrientationUtil.KEY)) { result.AddWarning ("Supported orientations have not been set (iPhone Application options panel)"); } else { var val = OrientationUtil.Parse ((PlistArray)dict[OrientationUtil.KEY]); if (!OrientationUtil.IsValidPair (val)) result.AddWarning ("Supported orientations are not matched pairs (Info.plist)"); if (dict.ContainsKey (OrientationUtil.KEY_IPAD)) { var pad = OrientationUtil.Parse ((PlistArray)dict[OrientationUtil.KEY_IPAD]); if (pad != Orientation.None && !OrientationUtil.IsValidPair (pad)) result.AddWarning ("iPad orientations are not matched pairs (Info.plist)"); } } } return result; }); }