15

I just found that PackageInfo.versionCode is deprecated in Android Pie. They point you to use PackageInfo.getLongVersionCode() instead. The JavaDoc of this new method is:

Return versionCode and versionCodeMajor combined together as a single long value. The versionCodeMajor is placed in the upper 32 bits.

But what is versionCodeMajor? How must I use it? What's the difference between versionCodeMajor and the old versionCode?

The documentation of it say nearlly nothing:

Internal major version code. This is essentially additional high bits for the base version code; it has no other meaning than that higher numbers are more recent. This is not a version number generally shown to the user, that is usually supplied with R.attr.versionName.

Brais Gabin
  • 5,827
  • 6
  • 57
  • 92
  • 2
    I thought it was pretty self-explanatory. They've expanded the version code from an `int` to a `long`. The way to do that, in a backwards-compatible fashion, is to pack two `int`s into that `long`, where the low `int` is the old version code and the high `int` defaults to zero. I don't expect most people to need any of this, but clearly some product team at Google was unwise in their versioning practices and is running out of numbers. – j__m Dec 31 '18 at 23:59
  • Maybe they learned from the old mis-optimism that 640 KB will be "plenty" of RAM and decided to play it safe and not assume that 4 billion versions will always be enough. :-) – Edward Brey Jun 21 '20 at 20:59

2 Answers2

15

Up to now, the only way I've found to set versionCodeMajor with Android Studio 3.2.1 is through AndroidManifest.xml and disabling InstantRun.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:versionCodeMajor="8" [...]

'cause setting it in build.gradle file you get

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.xxx.myapplicationp"
        minSdkVersion 'P'
        targetSdkVersion 'P'
        versionCode 127
        //versionCodeMajor 8
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

Could not find method versionCodeMajor() for arguments

So, having set your chosen major version code number in AndroidManifest.xml and having disable InstantRun then you could get it in this way:

static long getAppVersionCode(Context context) throws PackageManager.NameNotFoundException {
        PackageInfo pinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        long returnValue = Long.MAX_VALUE;
        //if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P
                && !"P".equals(Build.VERSION.CODENAME) /* This 'cause the dev preview */) {
            returnValue = pinfo.versionCode;
        } else {
            returnValue = pinfo.getLongVersionCode();
            Log.d("AAA", "Full long value: " + returnValue);
            Log.d("AAA", "Major Version Code (your chosen one) " + (returnValue >> 32)); // 8 in this scenario
            Log.d("AAA", "Version Code (your chosen one) " + (int)(returnValue & 0x00000000ffffffff)); // 127 in this scenario
        }
        return returnValue;
    }

or you could use PackageInfoCompat like that:

static long getAppVersionCode(Context context) throws PackageManager.NameNotFoundException {
        PackageInfo pinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        long returnValue = Long.MAX_VALUE;
        returnValue = PackageInfoCompat.getLongVersionCode(pinfo);
        if (BuildConfig.DEBUG) {
            int majorCode = (int)(returnValue >> 32);
            int versionCode = (int)(returnValue & 0x00000000ffffffff); // or simply returnValue

            Log.d("AAA", "Full long value: " + returnValue);
            Log.d("AAA", "Major Version Code (your chosen one) " + majorCode); // 8 in this scenario
            Log.d("AAA", "Version Code (your chosen one) " + versionCode); // 127 in this scenario
        }
        return returnValue;
    }

And this should answer how to use it or a way to.

For when and why using it... I guess it's up to you... as, as you pointed out, the documentation tells you nothing on why you should use it. What doc says it’s you should present to your users only the well known versionNumber.

I guess they add some more bits to versionCode ‘cause they needed a greater number for their versioning ^^’

That said, if you dind’t set the versionCodeMajor either in AndroidManifest.xml or in the build.gradle file (when it will handle it) or you set it to 0 then this value is identical to the old versionNumber deprecated field.

Edward Brey
  • 40,302
  • 20
  • 199
  • 253
shadowsheep
  • 14,048
  • 3
  • 67
  • 77
0

Another way to get version name and version code is by BuildConfig

BuildConfig.VERSION_CODE
BuildConfig.VERSION_NAME