android-MNC project won’t run on devices prior to API level 'android-MNC'

1.8k views Asked by At

Shortly after the Google I/O keynote and the consecutive talks about Android M features, I started playing around with the new SDK functions, e.g., runtime permissions. For that it is necessary to set the compileSdkVersion as well as the targetSdkVersion to android-mnc. When running the project on a Nexus 5 with the Android M Developer Preview installed, Android Studio installs the application and it works fine on the device.

If I set the minSdkVersion to, e.g., 10 to test it on a 2.3.6 device or to 21 to test it on a 5.0 device, it still works on the M-Nexus5 but not on the aforementioned devices with lower-than-M API versions.

apply plugin: 'com.android.application'

android {
    buildToolsVersion "22.0.1"
    compileSdkVersion 'android-MNC'

    defaultConfig {
        applicationId "de.FOOBAR.permtestproject"
        minSdkVersion 10
        targetSdkVersion 21
        versionCode 23
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:design:22.2.0'
    compile 'com.android.support:appcompat-v7:22.2.0'
}

As you can see in the following screenshot, my level-21 device is shown as incompatible even though I set the minSdkVersion to 10 and not to the claimed level of 22.

Available devices dialogue in the foreground, gradle build file in the background

Lowering the targetSdkVersion to 21 doesn’t make a difference. Changing the compileSdkVersion is not an option as the permission request calls have not been available in pre-M(NC) SDKs.

Trying to run the application on a pre-M device always fails with the error INSTALL_FAILED_OLDER_SDK.

INSTALL_FAILED_OLDER_SDK

1

There are 1 answers

1
CommonsWare On BEST ANSWER

Quoting myself:

In the case of the M Developer Preview, the compileSdkVersion value of android-MNC causes the build process to put MNC in as the minSdkVersion and targetSdkVersion in the generated manifest.

Fortunately, manifests are text files.

So, here is an android closure that can build an app module that compiles against MNC but will run on API Level 15+ devices:

android {
    compileSdkVersion 'android-MNC'
    buildToolsVersion "23.0.0 rc1"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 15
    }

    // based on http://stackoverflow.com/a/27372806/115145

    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.processManifest.doLast {
                def manifestOutFile = output.processManifest.manifestOutputFile
                def newFileContents = manifestOutFile.getText('UTF-8').replace("MNC", "15")
                manifestOutFile.write(newFileContents, 'UTF-8')
            }
        }
    }
}

This takes a very “caveman” approach to the problem, reading in the generated manifest, replacing all occurrences of MNC with 15, and writing the adjusted manifest back out. This will fail on projects that have MNC somewhere else, like an activity’s class name. It also sets both minSdkVersion and targetSdkVersion to the same value. A more sophisticated script would replace those individual attributes — the proof of this is left as an exercise for the reader. Similarly, a more powerful script would read the desired values out of defaultConfig and apply them. And, a safety-conscious edition of this would only apply this for debuggable variants, thereby helping to reduce the impact of a drooling idiot trying to ship a release build that performs this override. This is merely a proof of concept, not implementing all possible bells and whistles.

Again, doing this and releasing the results to the Play Store or elsewhere is monumentally idiotic. Use this for testing only.