Looking for a way to access the build date (of my own code) as a string in code, if possible. Barring that, some other unique and changing string would be nice.
How would you define the build date of your code, given that each script is re-compiled each time it's edited? The build date for the player itself would be a more reasonable thing to look for, but what value would that have when running in the editor? What do you need the value for? What are you trying to achieve? There may be a way that makes more sense than using an ill-defined build date.
A build date is an excellent way to tell you when the thing was released to your testers, and is hardly a stretch of a concept. When a bug is identified, a date or code stamp can be helpful. It looks like I'll have to adjust a number myself, no biggie, but I like to avoid human error/forgetfulness where possible.
The only way I can think of to automate this is to create your own editor script that builds the player using the BuildPipeline.BuildPlayer function. The script could set a public variable in an object somewhere with the current time just before starting the build process.
What we did in the last company I worked was get the build number from subversion to a file, and read that file at the beginning of the program. I think you could make something like this using PostBuild scripts to create a file and read it from your scripts (I have not test it, but it appears possible)
You can use a compile-time language to create a string. At least I know that Boo has this. Code (csharp): import UnityEngine macro build_buildtime_info(): dateString = System.DateTime.Now.ToString() yield [| class BuildtimeInfo: static def DateTimeString() as string: return "${$(dateString)}" |] build_buildtime_info # # Now you can do this: # Debug.Log( BuildtimeInfo.DateTimeString() )
You are a life-saver, even 4 years later . I would never have thought about Boo and what it can do. This still works in the current Unity Engine. Just put a "BuildtimeInfo.boo" file with the above content into "Assets/Plugins". You need to do this manually in the OS file explorer, since Unity wont show BOO files anymore. Then you can use this build time-stamp in C# via: BuildtimeInfo.DateTimeString() Pretty sleak. This works because everything in "Assets/Plugins" is compiled BEFORE all other stuff so you can access this dynamic class later in the build process. I like it. Although it is yet another shortcoming of Unity that we have to resort to such hacks to do obvious things. I use it to create a watermark over debug builds to be sure that the device/WebGL really is using the version I want to test.
I just tried adding this boo script, and it works with no errors in Unity, but VisualStudio complains that "The name 'BuildtimeInfo' does not exist in the current context." I have not worked with Boo files before -- is there any way to get rid of this "error"?
a bit late, but try somthing like this: Code (CSharp): public class BuildInfo { public System.DateTime BuildTime() { #if UNITY_EDITOR BuildTime = System.DateTime.Now; #else BuildTime = System.DateTime.Parse(BuildtimeInfo.DateTimeString()); #endif } } Then call: Code (CSharp): UnityEngine.Debug.Log("BuildTime: " + BuildInfo.BuildTime());
@Krstn `BuildtimeInfo` was created by the Boo script from steinbitglis from above at build time. But after Upgrade Unity to the latest 2018.3 the BuildtimeInfo is not created anymore. Any ideas? Unity seems to stop using the boo script.
One of the changes for 2018.3 was the final removal of the compiler used for UnityScript and Boo. https://docs.unity3d.com/Manual/UpgradeGuide20183.html
Thank your for the fast reply. I have removed the boo script and implement the BuildInfo by another way with C#. For those who are interested, here are my current solution: During the pre build procress of unity i create a file with the build time in the StreamingAssets folder. So the build time can be read from the file later. There can be stored some other information there too. example implementation code: Code (CSharp): namespace MyAwesomeProject.Build { using System; using System.IO; using UnityEngine; public class Info { private static Info _instance; public static Info Instance { get { if (_instance == null) { _instance = new Info(); } return _instance; } } public DateTime BuildTime { get; private set; } protected Info() { byte[] ByteInfo = this.ReadStreamingAsset("BuildInfo"); // file does not exists. set defaults! if (ByteInfo.Length == 0) { BuildTime = DateTime.UtcNow; return; } // else, read the infos from file using (BinaryReader Reader = new BinaryReader(new MemoryStream(ByteInfo, false))) { BuildTime = DateTime.FromBinary(Reader.ReadInt64()); } } public byte[] ReadStreamingAsset(string path) { string filePath = Path.Combine(Application.streamingAssetsPath, path); // add file prefix if (Application.platform != RuntimePlatform.Android) { filePath = "file://" + filePath; } WWW fileContent = new WWW(filePath); // wait for file was loaded! while (!fileContent.isDone && string.IsNullOrEmpty(fileContent.error)) { } return fileContent.bytes; } } #if UNITY_EDITOR public class AndroidBuildPrepartion : UnityEditor.Build.IPreprocessBuildWithReport { public int callbackOrder { get { return 0; } } public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) { using (BinaryWriter Writer = new BinaryWriter(File.Open("Assets/StreamingAssets/BuildInfo", FileMode.Create))) { Writer.Write(DateTime.UtcNow.ToBinary()); } } } #endif } Now you cat read the build time like this: Code (CSharp): MyAwesomeProject.Build.Info.Instance.BuildTime
Cool thing and thanks for sharing. Although if you don't need the file itself only for reading by the game maybe it would be better if you just generate a BuildInfo static class and use that. Something like this: Assets/BuildInfo.cs Code (CSharp): public static class BuildInfo{public static string BUILD_TIME = "Foobar";} Assets/Editor/BuildInfoProcessor.cs Code (CSharp): using System; using System.IO; using System.Text; using UnityEditor.Build; using UnityEditor.Build.Reporting; public class BuildInfoProcessor : IPreprocessBuildWithReport { public int callbackOrder { get { return 0; } } public void OnPreprocessBuild(BuildReport report) { StringBuilder sb = new StringBuilder(); sb.Append("public static class BuildInfo"); sb.Append("{"); sb.Append("public static string BUILD_TIME = \""); sb.Append(DateTime.UtcNow.ToString()); sb.Append("\";"); sb.Append("}"); using(System.IO.StreamWriter file = new System.IO.StreamWriter(@"Assets/BuildInfo.cs")) { file.WriteLine(sb.ToString()); } } } So basically you can refer to this whole thing like BuildInfo.BUILD_TIME; in your code. The drawback is that every build will overwrite this BuildInfocs file, so the editor runs will be affected by the builds too.
That is a interesting approach @Lurking-Ninja. I'll take a look at this later, thank you! Edit: After a short commemorative break, i think the file is the better solution for me, instead of a dynamical code creation on build time.
Thanks for the solution @dmkmwagner, Awesome work. I just did not really like the idea of using www to access the file so I made a small modification. Change it, use it, hate it, burn it, whatever, but maybe another lazy dev comes across it and prefers it as well. Code (CSharp): public class Info { private static Info _instance; public static Info Instance { get { if (_instance == null) { _instance = new Info(); } return _instance; } } public DateTime BuildTime { get; private set; } public String BuildDate { get; private set; } protected Info() { var txt = (UnityEngine.Resources.Load("BuildDate") as TextAsset); BuildDate = Loader.sAppVersion = txt.text.Trim(); } } #if UNITY_EDITOR public class AndroidBuildPrepartion : UnityEditor.Build.IPreprocessBuildWithReport { public int callbackOrder { get { return 0; } } public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) { using (BinaryWriter Writer = new BinaryWriter(File.Open("Assets/Resources/BuildDate.txt", FileMode.OpenOrCreate| FileMode.Truncate))) { Writer.Write(DateTime.Now.ToString("dd/MM/yyyy")); } } } #endif
Hi @ScienceJ, thanks for your reply. My code is a reduced version. I write some information more in the buildinfo than the time. Thats why there is a binary reader. I like the idea how you load the information. I'll check this later and give your idea a try. Best regards
In my case, I need to put asset refresh code to update changed build date. What I thought is 1. OnPreprocessBuild() called 2. Create BuildTime file 3. Build <In this phase, builder still point last BuildTime file> 4. Update BuildTime file So I put some update codes and solve problem in my case. Code (CSharp): #if UNITY_EDITOR public class AndroidBuildPrepartion : UnityEditor.Build.IPreprocessBuildWithReport { public int callbackOrder { get { return 0; } } public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) { using (BinaryWriter Writer = new BinaryWriter(File.Open("Assets/Resources/BuildDate.txt", FileMode.OpenOrCreate| FileMode.Truncate))) { Writer.Write(DateTime.Now.ToString("dd/MM/yyyy")); } AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); } } #endif
Since FileMode.OpenOrCreate| FileMode.Truncate did not work for me and was producing error in Unity 2018.4, I replaced it with single line code: Code (CSharp): public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) { File.WriteAllText("Assets/Resources/app_build_time.txt", DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss")); AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); }
Isn't there a simple way of doing this ? Seems so simple that it's impossible in U3D ! Text myUItext; myUItext.text = "version: "+#BUILD_DATE; there seem to be legions of ways with onprebuild, onpostbuild, onwaiticookthepizza, onamnotsureofwhattodo, etc.... most (all) are obsolete and there's no way to find how do versionning ( indeed it's not versionning, i only need the build date ) for built apps..... PLEASE light my candle ! I cannot believe this cannot be done simply in unity regards ! EDIT: People use tu compile gazillion of versions a day..... it's well known ^^ For my own part..... 1 version a day is okay ! therefore the DAY/MONTH/YEAR version string is okay for me...... Then this thought comes to me: WHY IS THIS SO IMPOSSIBLE ????? Is it too simple ?
Sorry.... i'm probably kinda dumb.... When i do: string my_version_date = "Kleioscope "+BuildInfo.BUILD_TIME; i got the error: error CS0103: The name 'BuildInfo' does not exist in the current context what's wrong ?
I just did and it works fine ! Anyway i keep beeing surprised that such simple things need this kind of 'hack' Centuries ago, i remember C++ compilers ( gcc or µsoft ones ) allowed to use a __DATE__ preprocessor macro for getting the build date in code..... But i guess this was too simple and efficient Thanks for your workaround @Lurking-Ninja Happy unitying !
berry nice! and to load this, use Resource.Load<TextAsset>("filename that is inside the Resource folder").text