Fork us on GitHub

TIP: Cross Platform Update Available Strategy

Don't let your old versions weigh you down
Post Image

TIP: Cross Platform Update Available Strategy

One of the nice things in mobile development vs. desktop is the fact that updates are seamless. We supposedly don’t need to worry about them and most newer OS’s turn them on by default. This keeps are users with the latest version which is important, e.g. if we fixed a crucial bug or added a new monetization option…​

However, the reality rarely fits into this nice image. In practice an update can be delayed because of permission changes user settings and many other problems. As a result old and even discontinued apps can still exist on user devices and give you a hard time with user complaints.

We still get notifications from apps that haven’t been listed in the stores for over 2 years!

Over the years we developed a policy of update management that handles all potential edge cases:

  • Update recommended - we have a new update out and we want you to switch to it but it isn’t crucial

  • Update required - if you don’t update now we’d rather the app stops working

  • Switch App recommended - This app was discontinued, we suggest you switch to a new app. This can happen when a product line changes or even if you lose your certificate an can no longer update the app

  • Switch App required - This app was discontinued but we have this alternative app you can migrate to, the app will stop working and activating it will launch that URL after an error message

  • App was discontinued but you can keep using for now

  • App was discontinued and will no longer work

Those are all potential outcomes that we can forsee but there are a lot of things we can’t forsee so we need to make this process as generic as possible.

The Solution

We store properties files in our servers as plain text, this is easy and requires almost no configuration. These properties files use the following naming convention: AppName-OS-Status.properties.

Inside the properties file we have the following settings:

  • deprecatedVersion - the version number we no longer support but still run

  • derprecatedMessage - a message to show users of the deprecated version

  • derprecatedAltURL - URL to send users of the deprecated version to

  • unsupportedVersion - the version we no longer support

  • unsupportedMessage - a message we show to users of the unsupported version

  • unsupportedAltURL - URL to send users of the unsupported version

We can leave most properties blank if they aren’t applicable and might not even have a file.

Host these files in your own domain under your control. A dropbox URL might change and might be blocked in some cases and the same is true for github

The Code

Notice that this code needs to execute after the first form was shown and not in the init(Object) method. It will fail gracefully and the app will keep working if there is no Internet connection.

String url = "https://myurl.com/mydir/" + Display.getInstance().getProperty("AppName", "MyApp") +
        "-" + Display.getInstance().getPlatformName() + "-Status.properties";
Log.p("Checking update URL: " + url);
ConnectionRequest c = new ConnectionRequest(url, false) {
    private Properties props;
    @Override
    protected void readResponse(InputStream input) throws IOException {
        props = new Properties();
        props.load(input);
    }

    @Override
    protected void postResponse() {
        if(props != null) {
            float version = Float.parseFloat(Display.getInstance().getProperty("AppVersion", "1.0"));
            float unsupportedVersion = Float.parseFloat(props.getProperty("unsupportedVersion", "-1"));
            if(version <= unsupportedVersion) {
                String message = props.getProperty("unsupportedMessage", "The current application version is no longer supported");
                String url = props.getProperty("unsupportedAltURL", null);
                if(url == null) {
                    Dialog.show("Unsupported Version", message, "OK", null);
                    Display.getInstance().exitApplication();
                } else {
                    if(!Dialog.show("Unsupported Version", message, "OK", "Exit")) {
                        Display.getInstance().exitApplication();
                    }
                    Display.getInstance().execute(url);
                    Display.getInstance().exitApplication();
                }
            }
            float deprecatedVersion = Float.parseFloat(props.getProperty("deprecatedVersion", "-1"));
            if(version <= deprecatedVersion) {
                String message = props.getProperty("derprecatedMessage", "A new version of the app is available, please update");
                String url = props.getProperty("derprecatedAltURL", null);
                if(url == null) {
                    Dialog.show("New Version", message, "OK", null);
                } else {
                    if(Dialog.show("New Version", message, "Download", "OK")) {
                        Display.getInstance().execute(url);
                    }
                }
            }
        }
    }

};
c.setFailSilently(true);
NetworkManager.getInstance().addToQueue(c);

Now you will need properties files matching these URL’s, notice that the name is OS specific to allow you to have different version deprecation policies for different OS’s (e.g. for the case of losing the Android certificate).

Share this Post:

Posted by Shai Almog

Shai is the co-founder of Codename One. He's been a professional programmer for over 25 years. During that time he has worked with dozens of companies including Sun Microsystems.
For more follow Shai on Twitter & github.