Search Unity

Build date or version from code

Discussion in 'Scripting' started by BS-er, Sep 1, 2010.

  1. BS-er

    BS-er

    Joined:
    May 24, 2009
    Posts:
    115
    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.
     
  2. laurie

    laurie

    Joined:
    Aug 31, 2009
    Posts:
    638
    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.
     
  3. BS-er

    BS-er

    Joined:
    May 24, 2009
    Posts:
    115
    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.
     
  4. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    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.
     
  5. ulisesyo

    ulisesyo

    Joined:
    Aug 11, 2010
    Posts:
    24
    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)
     
  6. steinbitglis

    steinbitglis

    Joined:
    Sep 22, 2011
    Posts:
    254
    You can use a compile-time language to create a string. At least I know that Boo has this.

    Code (csharp):
    1. import UnityEngine
    2.  
    3. macro build_buildtime_info():
    4.     dateString = System.DateTime.Now.ToString()
    5.     yield [|
    6.         class BuildtimeInfo:
    7.             static def DateTimeString() as string:
    8.                 return "${$(dateString)}"
    9.     |]
    10.  
    11. build_buildtime_info
    12.  
    13. # # Now you can do this:
    14. # Debug.Log( BuildtimeInfo.DateTimeString() )
     
  7. notagame

    notagame

    Joined:
    Sep 17, 2017
    Posts:
    17
    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.
     
    vedram likes this.
  8. tmurraysdca

    tmurraysdca

    Joined:
    May 3, 2018
    Posts:
    1
    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"?
     
  9. dmkmwagner

    dmkmwagner

    Joined:
    Mar 23, 2018
    Posts:
    5
    a bit late, but try somthing like this:

    Code (CSharp):
    1. public class BuildInfo
    2. {
    3.     public System.DateTime BuildTime()
    4.     {
    5. #if UNITY_EDITOR
    6.         BuildTime = System.DateTime.Now;
    7. #else
    8.         BuildTime = System.DateTime.Parse(BuildtimeInfo.DateTimeString());
    9. #endif
    10.     }
    11. }
    Then call:
    Code (CSharp):
    1.  
    2. UnityEngine.Debug.Log("BuildTime: " + BuildInfo.BuildTime());
    3.  
     
    MikeWise and MaxPirat like this.
  10. Krstn

    Krstn

    Joined:
    Dec 30, 2012
    Posts:
    27
    @dmkmwagner what is BuildtimeInfo? The code you provided doesn't look valid.
     
  11. dmkmwagner

    dmkmwagner

    Joined:
    Mar 23, 2018
    Posts:
    5
    @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.
     
  12. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    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
     
  13. dmkmwagner

    dmkmwagner

    Joined:
    Mar 23, 2018
    Posts:
    5
    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):
    1. namespace MyAwesomeProject.Build
    2. {
    3.     using System;
    4.     using System.IO;
    5.     using UnityEngine;
    6.  
    7.     public class Info
    8.     {
    9.         private static Info _instance;
    10.         public static Info Instance
    11.         {
    12.             get
    13.             {
    14.                 if (_instance == null) {
    15.                     _instance = new Info();
    16.                 }
    17.  
    18.                 return _instance;
    19.             }
    20.         }
    21.  
    22.         public DateTime BuildTime { get; private set; }
    23.  
    24.         protected Info()
    25.         {
    26.             byte[] ByteInfo = this.ReadStreamingAsset("BuildInfo");
    27.  
    28.             // file does not exists. set defaults!
    29.             if (ByteInfo.Length == 0)
    30.             {
    31.                 BuildTime = DateTime.UtcNow;
    32.  
    33.                 return;
    34.             }
    35.             // else, read the infos from file
    36.  
    37.             using (BinaryReader Reader = new BinaryReader(new MemoryStream(ByteInfo, false))) {
    38.                 BuildTime = DateTime.FromBinary(Reader.ReadInt64());
    39.             }
    40.         }
    41.  
    42.         public byte[] ReadStreamingAsset(string path)
    43.         {
    44.             string filePath = Path.Combine(Application.streamingAssetsPath, path);
    45.  
    46.             // add file prefix
    47.             if (Application.platform != RuntimePlatform.Android)
    48.             {
    49.                 filePath = "file://" + filePath;
    50.             }
    51.  
    52.             WWW fileContent = new WWW(filePath);
    53.  
    54.             // wait for file was loaded!
    55.             while (!fileContent.isDone && string.IsNullOrEmpty(fileContent.error)) { }
    56.  
    57.             return fileContent.bytes;
    58.         }
    59.     }
    60.  
    61. #if UNITY_EDITOR
    62.     public class AndroidBuildPrepartion : UnityEditor.Build.IPreprocessBuildWithReport
    63.     {
    64.         public int callbackOrder { get { return 0; } }
    65.  
    66.         public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
    67.         {
    68.             using (BinaryWriter Writer = new BinaryWriter(File.Open("Assets/StreamingAssets/BuildInfo", FileMode.Create)))
    69.             {
    70.                 Writer.Write(DateTime.UtcNow.ToBinary());
    71.             }
    72.         }
    73.     }
    74. #endif
    75. }
    Now you cat read the build time like this:
    Code (CSharp):
    1. MyAwesomeProject.Build.Info.Instance.BuildTime
     
  14. 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):
    1. public static class BuildInfo{public static string BUILD_TIME = "Foobar";}
    2.  
    Assets/Editor/BuildInfoProcessor.cs
    Code (CSharp):
    1. using System;
    2. using System.IO;
    3. using System.Text;
    4. using UnityEditor.Build;
    5. using UnityEditor.Build.Reporting;
    6.  
    7. public class BuildInfoProcessor : IPreprocessBuildWithReport
    8. {
    9.     public int callbackOrder { get { return 0; } }
    10.     public void OnPreprocessBuild(BuildReport report)
    11.     {
    12.         StringBuilder sb = new StringBuilder();
    13.         sb.Append("public static class BuildInfo");
    14.         sb.Append("{");
    15.         sb.Append("public static string BUILD_TIME = \"");
    16.         sb.Append(DateTime.UtcNow.ToString());
    17.         sb.Append("\";");
    18.         sb.Append("}");
    19.         using(System.IO.StreamWriter file =
    20.             new System.IO.StreamWriter(@"Assets/BuildInfo.cs"))
    21.         {
    22.             file.WriteLine(sb.ToString());
    23.         }
    24.     }
    25. }
    26.  
    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.
     
    cficara, grobonom and Dance_M like this.
  15. dmkmwagner

    dmkmwagner

    Joined:
    Mar 23, 2018
    Posts:
    5
    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.
     
    Last edited: Jan 11, 2019
    grobonom likes this.
  16. Deleted User

    Deleted User

    Guest

    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):
    1.  
    2.     public class Info
    3.     {
    4.         private static Info _instance;
    5.         public static Info Instance
    6.         {
    7.             get
    8.             {
    9.                 if (_instance == null)
    10.                 {
    11.                     _instance = new Info();
    12.                 }
    13.                 return _instance;
    14.             }
    15.         }
    16.  
    17.         public DateTime BuildTime { get; private set; }
    18.         public String BuildDate { get; private set; }
    19.  
    20.         protected Info()
    21.         {
    22.             var txt = (UnityEngine.Resources.Load("BuildDate") as TextAsset);
    23.             BuildDate = Loader.sAppVersion = txt.text.Trim();
    24.         }
    25.  
    26.     }
    27.  
    28. #if UNITY_EDITOR
    29.     public class AndroidBuildPrepartion : UnityEditor.Build.IPreprocessBuildWithReport
    30.     {
    31.         public int callbackOrder { get { return 0; } }
    32.  
    33.         public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
    34.         {
    35.             using (BinaryWriter Writer = new BinaryWriter(File.Open("Assets/Resources/BuildDate.txt", FileMode.OpenOrCreate| FileMode.Truncate)))
    36.             {
    37.                 Writer.Write(DateTime.Now.ToString("dd/MM/yyyy"));
    38.             }
    39.         }
    40.     }
    41. #endif
     
    Last edited by a moderator: Jun 3, 2019
    ryan-challinor likes this.
  17. dmkmwagner

    dmkmwagner

    Joined:
    Mar 23, 2018
    Posts:
    5
    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
     
  18. chviff

    chviff

    Joined:
    Aug 2, 2018
    Posts:
    1
    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):
    1. #if UNITY_EDITOR
    2.     public class AndroidBuildPrepartion : UnityEditor.Build.IPreprocessBuildWithReport
    3.     {
    4.         public int callbackOrder { get { return 0; } }
    5.         public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
    6.         {
    7.             using (BinaryWriter Writer = new BinaryWriter(File.Open("Assets/Resources/BuildDate.txt", FileMode.OpenOrCreate| FileMode.Truncate)))
    8.             {
    9.                 Writer.Write(DateTime.Now.ToString("dd/MM/yyyy"));
    10.             }
    11.  
    12.         AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
    13.  
    14.         }
    15.     }
    16. #endif
     
    andrew_pearce likes this.
  19. andrew_pearce

    andrew_pearce

    Joined:
    Aug 5, 2019
    Posts:
    9
    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):
    1.   public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) {
    2.     File.WriteAllText("Assets/Resources/app_build_time.txt", DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"));
    3.     AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
    4.   }
     
    Last edited: Oct 21, 2019
  20. grobonom

    grobonom

    Joined:
    Jun 23, 2018
    Posts:
    335
    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 :p

    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 ?
     
    Last edited: Jun 1, 2020
  21. grobonom

    grobonom

    Joined:
    Jun 23, 2018
    Posts:
    335

    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 ?
     
  22. Did you create the BuildInfo.cs first with the default content above?
     
    grobonom likes this.
  23. grobonom

    grobonom

    Joined:
    Jun 23, 2018
    Posts:
    335
    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 :D

    Thanks for your workaround @Lurking-Ninja :)

    Happy unitying !
     
  24. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,327
    berry nice!
    and to load this, use Resource.Load<TextAsset>("filename that is inside the Resource folder").text
     
    munkiki7 likes this.
  25. jamespaterson

    jamespaterson

    Joined:
    Jun 19, 2018
    Posts:
    398
    hi all - thanks for a very helpful thread.
     
    nxtboyIII and grobonom like this.