Accessing Bundle Version in Unity iOS Runtime (3)

top feature image

Accessing Bundle Version in Unity iOS Runtime (3)

In part (1) and part (2) I discussed the concept and some implementation details for BundleVersionChecker a set of editor classes to provide access to Unity’s PlayerSettings.bundleVersion (and bundleIdentifier) at runtime and an enhanced way of managing the history of versions to provide migration steps as necessary – at least since you have installed it. Now I show you how to use it in your project.

Installation – The First Contact

BundleVersionChecker is hosted at GitHub under MIT license so it’s free to use even in a commercial environment.

The following steps are needed:

  • Ensure that you have a bundle version defined in Unity’s Player Settings: In Unity go to menu Edit / Project Settings / Player. In Inspector choose “Settings for iOS” under “Per-Platform Settings” and look in section other settings
  • Download BundleVersionChecker from GitHub
  • Put it in a new directory BundleVersionChecker under Assets/Editor; The code within the project has no sub-directories so it’s easy to create a submodule if you are using git as version control system
  • Bring Unity to the foreground (or start it if you haven’t it running)
  • In console you should see 2 messages after a few seconds:
    • Very first call, class file “TrackedBundleVersion”.cs will be generated for the first tracked version 0.8.5 (or whatever version)
    • Successfully copied template for class TrackedBundleVersionInfo to Assets/Scripts/Config/Generated/TrackedBundleVersionInfo.cs

Now you find 2 new classes in a new directory under Assets/Scripts/Config/Generated TrackedBundleVersion.cs and TrackedBundleVersionInfo.cs.


Getting The Current Bundle Version at Runtime

TrackedBundleVersion contains the bundle identifier, the current bundle version and a growing list of previously found versions. At the moment there is only one entry for the current version, we will look at that in a minute. Assume your current version is 0.8.5 then it looks like:

public class TrackedBundleVersion
    public static readonly string bundleIdentifier = "com.mycompany.myapp ";
    public ArrayList history = new ArrayList ();

    public TrackedBundleVersionInfo current = new TrackedBundleVersionInfo ("0.8.5", 0);

    public TrackedBundleVersion()
        history.Add (current);

As the class resides in the runtime assemby you can now access it from your other code. Typical usage scenario:

  • Save your current version string in PlayerPrefs
  • In the startup phase of your iOS app you read the version string from PlayerPrefs and compare it with the current version:
    string lastSavedVersion = PlayerPrefs.GetString ("BundleVersion"); // assume this is 0.8.4
    TrackedBundleVersionInfo currentRunningVersion = new TrackedBundleVersion ().current; // assume this is 0.8.5
    if (currentRunningVersion  > lastSavedVersion) {
    // do migration stuff

As you see TrackedBundleVersionInfo objects can be compared directly with strings because all comparison operators are overloaded not only for TrackedBundleVersionInfo objects among themselves but for comparing strings with TrackedBundleVersionInfo as well.

At the moment your history has just one element, the current bundle version. If you leave BundleVersionChecker in your project a while and change the bundle version with every new release, you will see how …

History Is Growing

First off, I’d like to mention that changing the bundle identifier in player settings does not force Unity to refresh its assets database. So always a change of a script or other asset is needed to force BundleVersionChecker to get active.

Let’s assume the test scenario from above. For testing purposes go to class TrackedBundleVersion and change the current version from “0.8.5” to “0.8.4” i.e public TrackedBundleVersionInfo current = new TrackedBundleVersionInfo (“0.8.4”, 0); .  Save in MonoDevelop and switch back to Unity. Unity. The class will be ‘updated’ (= regenerated but considering old history information). Now we have:

public static readonly TrackedBundleVersionInfo Version_0_8_4 =  new TrackedBundleVersionInfo ("0.8.4", 0);
public ArrayList history = new ArrayList ();
public TrackedBundleVersionInfo current = new TrackedBundleVersionInfo ("0.8.5", 1);

public  TrackedBundleVersion() {
    history.Add (Version_0_8_4);
    history.Add (current);

As you see the editor classes from BundleVersionChecker detected that the version information has to be updated and saved version 0.8.4 which we have faked as a previous release. Even more it is now available as public member Version_0_8_4 to be used for comparison. If you have introduced some new PlayerPrefs in version 0.8.4 that need some migration logic, you can trigger it in your new fancy class MigrationManager at app start and write something like:

if (lastSavedVersion <= Version_0_8_4) {
// migrate to 0.8.4
if (lastSavedVersion <= Version_0_9) {
// the next major change migrate to 0.9

OK, there is no such member Version_0_9, but it should be clear what I mean. If you saved version IDs in your app already for example by manually setting them in code, you can proceed with … 

Tweaking The History

As mentioned above everything under Assets/Scripts/Config/Generated is generated code and we all know: Never change generated code. That’s still true but this one is slightly different:

During generation all version strings from the ArrayList history are considered in the order they appear within the list (not their version string). All the “public static readonly TrackedBundleVersionInfo …” entries are not considered for analysing history. They are regenerated based on the version string for convenient access in you runtime code. So assuming 0.8.5 is current and you have a list of previous version strings between 0.8.1 and 0.8.4 that should be integrated in TrackedBundleVersion’s history. The easiest way is:

  • Write anything as version in current so BundleVersionChecker detects that it has to update the class:
    public TrackedBundleVersionInfo current = new TrackedBundleVersionInfo (“what ever is different to 0.8.5”, 0);
  • In constructor put

    public TrackedBundleVersion() 
        history.Add (new TrackedBundleVersionInfo ("0.8.1", 0)); 
        history.Add (new TrackedBundleVersionInfo ("0.8.2", 0)); 
        history.Add (new TrackedBundleVersionInfo ("0.8.3", 0)); 
        history.Add (new TrackedBundleVersionInfo ("0.8.4", 0)); 

Will result in:

public static readonly TrackedBundleVersionInfo Version_0_8_2 =  new TrackedBundleVersionInfo ("0.8.1", 0);
public static readonly TrackedBundleVersionInfo Version_0_8_2 =  new TrackedBundleVersionInfo ("0.8.2", 1);
public static readonly TrackedBundleVersionInfo Version_0_8_3 =  new TrackedBundleVersionInfo ("0.8.3", 2);
public static readonly TrackedBundleVersionInfo Version_0_8_4 =  new TrackedBundleVersionInfo ("0.8.4", 3);

public TrackedBundleVersionInfo current = new TrackedBundleVersionInfo ("0.8.5", 4);

public  TrackedBundleVersion() {
    history.Add (Version_0_8_1);
    history.Add (Version_0_8_2);
    history.Add (Version_0_8_3);
    history.Add (Version_0_8_4);
    history.Add (current);

At the bottom line:

  • The order in history counts nothing else
  • changing current forces regeneration


Changing Output Directory

You don’t like Assets/Config/Generated as output directory for the generated classes? No problem, first of all make a backup if you have made changes like described in the last paragraph. Then go to directory Assets/Editor/BundleVersionChecker and edit the file ConfigBundleVersionChecker.cs. Change the path in line

public const string TargetDir = "Assets/Scripts/Config/Generated";

to fit your needs. There you can change the names of the generated classes too (OK, I never tested it …). If you need any changes to TrackedBundleVersionInfo.cs, you can do them in the generated class but should copy them to the template TrackedBundleVersionInfo.txt. This is used just once at the very first start, afterwards there is no need to recreate the class.


Troubleshooting FAQ

This section will grow when users provide feedback. So don’t hesitate to use the comment section below, it works without registration until spammers will detect it.

  • Q: I just changed the iOS bundle version in player settings. Why do I still see the old string in current?
    A: There is no chance to get notified when settings are changed, so changes will go into TrackedBundleVersion the next time Unity performs a refresh – usually after a change in assets like source code
  • Q: What is this trackedMode flag in ConfigBundleVersionChecker?
    A: I started with a very simple solution without history tracking and didn’t want to throw away the source. So if trackedMode = false a different class CurrentBundleVersion.cs is generated that contains just the current bundle version string
  • Q: Can I use it in commercial projects?
    Yes, see the Wikipedia article and go to your language for further information
  • Q: Where do I get more technical details?
    In part (1) I described the start (very simplecode  and in part (2) the concept and some implementation about the process how to get here. For further details: “Die Wahrheit steht im Code” (German), don’t know if there is an appropriate English equivalent saying, it means “The code will tell the truth”
  • Q: Can I extend the functionality?
    Get your git clone and start 🙂 Thanks for sending a pull request.


What Is Missing / Can Be Improved

Refactoring to use UnityEngine.Application.version. Note that BundleVersionChecker still can be useful as it is more than jsut reading the curren versionbut also allows history tracking.

Tests in Unity 2017 as I still run Unity 5.

At the moment configuration data is read from class ConfigBundleVersionChecker. But it contains local information individual for every user as well. So if several people have BundeVersionChecker configured as a git submodule and have code improvement to be sent as pull request, these config changes will be included.

A nice GUI showing the history. Maybe the possibility to add or delete old version keys.



This happens when the installation directory is outside /Assets/Editor. When I started develping this for private use this was for fine for me. Now with a couple of users out there it’s pretty bad practice.

I fixed this in the most recent release 0.8.6 so that you can install BundelVersionChecker at arbitrary locations under the Assets folder.

i’m having the same problem and got this log:

Code generation stopped, no code to write.
BundleVersionChecker:CreateNewBuildVersionClassFile(AbstractBundleVersionGenerator) (at Assets/Editor/BundleVersionChecker/BundleVersionChecker.cs:76)
BundleVersionChecker:.cctor() (at Assets/Editor/BundleVersionChecker/BundleVersionChecker.cs:62)

I am working with 4.6.2 and works as designed. Note that you have to put Unity into the background after a change so that it detects changes in the Assets folder.

Are there any errors or warnings in the console view?

using UnityEditor.VersionControl;

static void CreateNewBuildVersionClassFile (string bundleVersion) {

FileInfo fileInfo = new FileInfo(filename);
if (fileInfo.IsReadOnly)
Debug.Log(“Checking out ” + filename);
Task task = Provider.Checkout(filename, CheckoutMode.Asset);
Debug.Log(“Checkout done ” + filename);
if (!fileInfo.IsReadOnly)
using (StreamWriter writer = new StreamWriter (filename, false)) {

StreamWriter fails miserably if file is readonly as some version control system works, like Perforce.

Comments are closed.

Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu <a href="">Mehr</a><br/>By continuing to use the site, you agree to the use of cookies. More

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.