override public BuildPlayerOptions PrepareBuild(BuildPlayerOptions options, OptionInclusion inclusion) { options.options |= Value; options.locationPathName = ExpandPath(GetChild <OptionBuildPath>().Value, options); var scenes = GetChild <OptionScenes>(); if (scenes.Value != null || scenes.Variants.Any()) { var paths = new List <string>(); if (scenes.Value != null) { paths.Add(AssetDatabase.GetAssetPath(scenes.Value)); } foreach (OptionScenes variant in scenes.Variants) { if (variant.Value != null) { paths.Add(AssetDatabase.GetAssetPath(variant.Value)); } } if (paths.Count > 0) { options.scenes = paths.ToArray(); } } return(base.PrepareBuild(options, inclusion)); }
public override void PreprocessBuild(BuildTarget target, string path, OptionInclusion inclusion) { base.PreprocessBuild(target, path, inclusion); originalValue = PlayerSettings.Android.targetDevice; PlayerSettings.Android.targetDevice = Value; }
override public void PostprocessBuild(BuildReport report, OptionInclusion inclusion) { base.PostprocessBuild(report, inclusion); if (inclusion == OptionInclusion.Remove || !Value) { return; } var projectPath = System.IO.Path.Combine(report.summary.outputPath, "Unity-iPhone.xcodeproj"); if (!Directory.Exists(projectPath)) { Debug.LogError("Could not find Unity-iPhone.xcodeproj at path: " + projectPath); return; } var basePath = System.IO.Path.Combine(projectPath, "xcshareddata/xcschemes"); var schemePath = System.IO.Path.Combine(basePath, "Unity-iPhone.xcscheme"); if (!File.Exists(schemePath)) { Debug.Log("No default Unity scheme at path, possibly already renamed: " + schemePath); return; } var newName = System.IO.Path.Combine(basePath, Application.productName + ".xcscheme"); File.Move(schemePath, newName); Debug.Log("Renamed Unity's default scheme to " + Application.productName); }
/// <summary> /// The scripting define symbols set by this Option. /// </summary> /// <remarks> /// By default, this method will define /// <pre><see cref="DEFINE_PREFIX"/> + <see cref="OPTION_PREFIX"/> + <see cref="Name"/></pre> /// if the Option is included and /// <pre><see cref="DEFINE_PREFIX"/> + <see cref="Name"/></pre> /// if the associated feature is included. /// /// Only the main Option will set these symbols but child and variant Options /// can set additional symbols. /// /// > [!NOTE] /// > This method is only available in the editor. /// </remarks> public virtual void GetScriptingDefineSymbols(OptionInclusion inclusion, HashSet <string> symbols) { // Only the root option has a toggle in the build profile if (Parent == null) { if (inclusion.HasFlag(OptionInclusion.Feature) && Capabilities.HasFlag(OptionCapabilities.HasAssociatedFeature)) { symbols.Add(DEFINE_PREFIX + Name); } if (inclusion.HasFlag(OptionInclusion.Option) && Capabilities.HasFlag(OptionCapabilities.CanIncludeOption)) { symbols.Add(DEFINE_PREFIX + OPTION_PREFIX + Name); } } if (variants != null) { foreach (var variant in variants) { variant.GetScriptingDefineSymbols(inclusion, symbols); } } if (children != null) { foreach (var child in children) { child.GetScriptingDefineSymbols(inclusion, symbols); } } }
override public void GetScriptingDefineSymbols(OptionInclusion inclusion, HashSet <string> symbols) { base.GetScriptingDefineSymbols(inclusion, symbols); if (inclusion.HasFlag(OptionInclusion.Option)) { symbols.Add("TRIMMER_SERVER"); } }
override public BuildPlayerOptions PrepareBuild(BuildPlayerOptions options, OptionInclusion inclusion) { options = base.PrepareBuild(options, inclusion); if (Value) { BuildAddressables(); } return(options); }
override public void PostprocessScene(Scene scene, OptionInclusion inclusion) { base.PostprocessScene(scene, inclusion); var script = OptionHelper.InjectFeature <VersionContainer>(scene, OptionInclusion.Feature); if (script != null) { script.version = Version.ProjectVersion; } }
override public void PreprocessBuild(BuildReport report, OptionInclusion inclusion) { base.PreprocessBuild(report, inclusion); if (inclusion == OptionInclusion.Remove) { return; } if (validation == Error.Unknonw) { validation = Validate(); } if (validation == Error.NoKeystore) { // Option not configured: only print a notice Debug.Log("OptionKeyStore: No keystore configured"); return; } else if (validation != Error.None) { var error = "Error in the active Build Profile Key Store Option:\n" + ErrorMessages[validation]; if (Application.isBatchMode) { // In batch mode: Log error Debug.LogError(error); return; } else if (EditorUtility.DisplayDialog("Android Keystore", error, "Cancel", "Ignore")) { // In editor: Show a warning dialog throw new Exception(error); } } var keystore = GetChild <OptionStorePath>().Value; var alias = GetChild <OptionAlias>().Value; PlayerSettings.Android.keystoreName = keystore; PlayerSettings.Android.keyaliasName = alias; if (GetChild <OptionUseKeychain>().Value&& Keychain.Main != null) { PlayerSettings.Android.keystorePass = Keychain.Main.GetPassword(KeychainService, keystore); PlayerSettings.Android.keyaliasPass = Keychain.Main.GetPassword(KeychainService, keystore + "#" + alias); } else { PlayerSettings.Android.keystorePass = GetChild <OptionStorePassword>().Value; PlayerSettings.Android.keyaliasPass = GetChild <OptionAliasPassword>().Value; } }
override public void PostprocessScene(Scene scene, OptionInclusion inclusion) { base.PostprocessScene(scene, inclusion); var host = OptionHelper.InjectFeature <TrimmerServerHost>(scene, inclusion); if (host != null) { host.enabled = Value; host.serverPort = GetChild <OptionServerPort>().Value; host.isDiscoverable = GetChild <OptionDiscoverable>().Value; } }
override public void PostprocessScene(Scene scene, OptionInclusion inclusion) { base.PostprocessScene(scene, inclusion); var prompt = OptionHelper.InjectFeature <Prompt>(scene, inclusion); if (prompt != null) { prompt.activationSequence = GetChild <OptionPromptActivation>().Value; prompt.fontSize = GetChild <OptionPromptFontSize>().Value; prompt.position = GetChild <OptionPromptPosition>().Value; } }
override public void PostprocessScene(Scene scene, OptionInclusion inclusion) { base.PostprocessScene(scene, inclusion); // Only include reference when Option is included, // we're building the first scene and a reference is set if ((inclusion & OptionInclusion.Option) != 0 && ProfileContainer.Instance != null && Value != null && !string.IsNullOrEmpty(GuidValue)) { ProfileContainer.Instance.AddReference(GuidValue, Value); } }
override public void PreprocessBuild(BuildReport report, OptionInclusion inclusion) { base.PreprocessBuild(report, inclusion); if (!inclusion.HasFlag(OptionInclusion.Feature)) { return; } Version.ProjectVersion = DetermineProjectVersion(report.summary.platform); if (GetChild <OptionIncrementBuildNumber>().Value) { Version.ProjectVersion = IncrementBuildNumber(Version.ProjectVersion, report.summary.platform); } }
override public void PreprocessBuild(BuildTarget target, string path, OptionInclusion inclusion) { base.PreprocessBuild(target, path, inclusion); if (!inclusion.HasFlag(OptionInclusion.Feature)) { return; } Version.ProjectVersion = DetermineProjectVersion(target); if (incrementBuildNumber) { Version.ProjectVersion = IncrementBuildNumber(Version.ProjectVersion, target); } }
/// <summary> /// Inject a singleton script in a build. /// Intended for use in Options' <see cref="Option.PostprocessScene"/> methods. /// </summary> /// <remarks> /// See <see cref="GetSingleton*"/> for a introductory explanation on how to /// implement the feature injection design pattern. /// /// InjectFeature is used in conjunction with GetSingleton. It's needed in case /// a build includes an Option's associated feature but not the Option itself. /// If the Option is included, it can take care of injecting the feature at /// runtime in the build. But if only the feature is included, it needs to be /// injected at build-time. /// /// This method should be used in an Option's <see cref="Option.PostprocessScene"/> /// to inject the feature into the build at build-time when required. /// /// Example for a typical implementation: /// ```cs /// protected bool Validate() /// { /// // Check if the Option is properly configured and/or enabled /// return Value && !string.IsNullOrEmpty(GetChild<OptionChild>().Value); /// } /// /// #if UNITY_EDITOR /// /// override public bool ShouldIncludeOnlyFeature() /// { /// // Removes the feature if it's improperly configured. /// // Otherwise the feature will always be included even if misconfigured/disabled. /// return Validate(); /// } /// /// override public void PostprocessScene(Scene scene, OptionInclusion inclusion) /// { /// base.PostprocessScene(scene, inclusion); /// /// var singleton = OptionHelper.InjectFeature<MyScript>(scene, inclusion); /// if (singleton != null) { /// singleton.option = false; /// singleton.otherOption = GetChild<OptionChild>().Value; /// } /// } /// /// #endif /// ``` /// /// Here overriding ShouldIncludeOnlyFeature takes care of checking if only /// the feature is included and removing it when it's not enabled/configured. /// InjectFeature then adds the singleton to the first scene so that it will /// be loaded in the build. /// </remarks> /// <param name="scene">Pass in the `scene` parameter from <see cref="Option.PostprocessScene"/></param> /// <param name="inclusion">Pass in the `inclusion` parameter from <see cref="Option.PostprocessScene"/></param> /// <returns>The script if it's injected or null</returns> public static T InjectFeature <T>(Scene scene, OptionInclusion inclusion) where T : Component { // We only inject when the feature is included but the Option is not if (!inclusion.HasFlag(OptionInclusion.Feature) || inclusion.HasFlag(OptionInclusion.Option)) { return(null); } // We only inject to the first scene, because DontDestroyOnLoad is set, // the script will persist through scene loads if (!IsFirstScene(scene)) { return(null); } return(GetSingleton <T>(true)); }
/// <summary> /// Callback invoked after the build completed. /// </summary> /// <remarks> /// This callback is invoked after the build has been completed, for /// both profile builds and regular Unity builds. /// /// > [!NOTE] /// > This method is only available in the editor. /// </remarks> /// <param name="report">Unity's build report</param> /// <param name="inclusion">Wether this option is included in the build</param> public virtual void PostprocessBuild(BuildReport report, OptionInclusion inclusion) { if (variants != null) { foreach (var variant in variants) { variant.PostprocessBuild(report, inclusion); } } if (children != null) { foreach (var child in children) { child.PostprocessBuild(report, inclusion); } } }
/// <summary> /// Callback invoked for every scene during build. /// </summary> /// <remarks> /// This callback gives Options a chance to modify scenes during the /// build process. This can be used to e.g. inject a script into the /// scene or remove some game objects. /// /// Unlike Unity's `OnProcessScene`, this method is not called when /// playing in the editor. Use <see cref="Apply"/> and Unity's /// `SceneManager` API instead. /// /// > [!NOTE] /// > This method is only available in the editor. /// </remarks> /// <param name="scene">The scene that is being processed.</param> /// <param name="inclusion">Wether the option is included in the build.</param> public virtual void PostprocessScene(Scene scene, OptionInclusion inclusion) { if (variants != null) { foreach (var variant in variants) { variant.PostprocessScene(scene, inclusion); } } if (children != null) { foreach (var child in children) { child.PostprocessScene(scene, inclusion); } } }
/// <summary> /// Callback invoked after the build completed. /// </summary> /// <remarks> /// This callback is invoked after the build has been completed, for /// both profile builds and regular Unity builds. /// /// > [!NOTE] /// > This method is only available in the editor. /// </remarks> /// <param name="target">Build target type</param> /// <param name="path">Path to the built project</param> /// <param name="inclusion">Wether this option is included in the build</param> public virtual void PostprocessBuild(BuildTarget target, string path, OptionInclusion inclusion) { if (variants != null) { foreach (var variant in variants) { variant.PostprocessBuild(target, path, inclusion); } } if (children != null) { foreach (var child in children) { child.PostprocessBuild(target, path, inclusion); } } }
override public void PostprocessBuild(BuildTarget target, string path, OptionInclusion inclusion) { base.PostprocessBuild(target, path, inclusion); if (!inclusion.HasFlag(OptionInclusion.Feature) || !Value) { return; } if (target == BuildTarget.StandaloneOSX) { UpdateVersionMac(path, Version.ProjectVersion); } else if (target == BuildTarget.StandaloneWindows || target == BuildTarget.StandaloneWindows64) { UpdateVersionWindows(path, Version.ProjectVersion); } }
override public void PostprocessBuild(BuildReport report, OptionInclusion inclusion) { base.PostprocessBuild(report, inclusion); if (inclusion == OptionInclusion.Remove || !Value) { return; } var plistPath = System.IO.Path.Combine(report.summary.outputPath, "Info.plist"); if (!File.Exists(plistPath)) { Debug.LogError("Could not find Info.plist at path: " + plistPath); return; } // Unity made the unfortunate decision to include UnityEditor.iOS.Xcode // as part of the iOS build support. This means users that don't have // it installed would get an error when we use it here. // // Using UNITY_IOS unfortunately doesn't work, as it is only set if iOS // is the active platform. With Trimmer, it's possible to make an iOS // build when iOS is not the active platform. Unity will switch the // active platform during the build but the editor code won't be recompiled, // meaning the code won't be executed. // // The only remaining options are to use reflection or to include the // Xcode DLL as part of Trimmer. We used reflection initially but // that is error-prone and unwieldy and switched to including the DLL. // With Asmdef's explicit assembly references, there hopefully won't // be any issues with duplicate DLLs. var info = new PlistDocument(); info.ReadFromFile(plistPath); info.root.SetBoolean("ITSAppUsesNonExemptEncryption", false); info.WriteToFile(plistPath); Debug.Log("Added Info.plist entry indicating the app only uses exempt encryption."); }
override public void PostprocessBuild(BuildReport report, OptionInclusion inclusion) { base.PostprocessBuild(report, inclusion); if (GetChild <OptionSaveBuildInfo>().Value) { if (BuildInfo.Current == null) { Debug.LogWarning("Save build info: BuildInfo.Current not set"); } else { var infoPath = OptionHelper.GetBuildBasePath(report.summary.outputPath); infoPath = System.IO.Path.Combine(infoPath, BuildInfo.DEFAULT_NAME); var json = BuildInfo.Current.ToJson(); File.WriteAllText(infoPath, json); } } }
/// <summary> /// Callback invoked before a profile build is started. /// </summary> /// <remarks> /// When a build is started on a <see cref="T:sttz.Trimmer.Editor.BuildProfile"/>, all options /// will receive this callback before the build is started. /// /// This callback allows Option to influence the build settings, including /// build options, output path and included scenes. /// /// By default, the build will include the scenes set in Unity's build /// player window and the options will be set to `BuildOptions.None`. /// If no Option sets the location path name, the user will be prompted /// to choose it. /// /// > [!WARNING] /// > This method will not be called for regular Unity builds, /// > started from the build player window or using the build menu item. /// /// > [!NOTE] /// > This method is only available in the editor. /// </remarks> /// <param name="options">The current options</param> /// <param name="inclusion">Wether the Option is included in the build.</param> /// <returns>The modified options.</returns> public virtual BuildPlayerOptions PrepareBuild(BuildPlayerOptions options, OptionInclusion inclusion) { if (variants != null) { foreach (var variant in variants) { options = variant.PrepareBuild(options, inclusion); } } if (children != null) { foreach (var child in children) { options = child.PrepareBuild(options, inclusion); } } return(options); }
override public void PostprocessBuild(BuildReport report, OptionInclusion inclusion) { base.PostprocessBuild(report, inclusion); if (!inclusion.HasFlag(OptionInclusion.Feature) || !Value) { return; } var platform = report.summary.platform; if (platform == BuildTarget.StandaloneOSX) { UpdateVersionMac(report.summary.outputPath, Version.ProjectVersion); } else if (platform == BuildTarget.StandaloneWindows || platform == BuildTarget.StandaloneWindows64) { UpdateVersionWindows(report.summary.outputPath, Version.ProjectVersion); } }
override public void PostprocessBuild(BuildReport report, OptionInclusion inclusion) { base.PostprocessBuild(report, inclusion); if (inclusion == OptionInclusion.Remove || !Value) { return; } var preprocessorPath = System.IO.Path.Combine(report.summary.outputPath, "Classes/Preprocessor.h"); if (!File.Exists(preprocessorPath)) { Debug.LogError("Could not find Preprocessor.h at path: " + preprocessorPath); return; } var contents = File.ReadAllText(preprocessorPath, Encoding.UTF8); if (!contents.Contains("#define UNITY_USES_REMOTE_NOTIFICATIONS ")) { Debug.LogError("Could not find UNITY_USES_REMOTE_NOTIFICATIONS define in Preprocessor.h"); return; } else if (!contents.Contains("#define UNITY_USES_REMOTE_NOTIFICATIONS 1")) { Debug.Log("Remote notifications already disabled, nothing to do."); return; } contents = contents.Replace( "#define UNITY_USES_REMOTE_NOTIFICATIONS 1", "#define UNITY_USES_REMOTE_NOTIFICATIONS 0" ); File.WriteAllText(preprocessorPath, contents); Debug.Log("Force disabled remote notifications."); }
public override BuildPlayerOptions PrepareBuild(BuildPlayerOptions options, OptionInclusion inclusion) { if (Value) { var canAppend = BuildPipeline.BuildCanBeAppended(options.target, options.locationPathName); if (canAppend == CanAppendBuild.Yes) { Debug.Log($"Trimmer: Appending build is possible, adding option AcceptExternalModificationsToPlayer"); options.options |= BuildOptions.AcceptExternalModificationsToPlayer; } else { Debug.Log($"Trimmer: Appending build is not possible ({canAppend})"); } } return(base.PrepareBuild(options, inclusion)); }