Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle: change NDK build target independent from the SDK build target

In the past I used eclipse for NDK projects, the Android.mk file was perfectly suited for compiling the NDK with API level 9 while letting the app (SDK) compile on API level 22. But it seems that this is not possible when using the experimental Gradle build system (2.5) with Android Studio 1.3 RC1.

What can I do to compile ONLY the NDK on API level 9?

My typical Android.mk file looks like this:

APP_PLATFORM := android-9
APP_STL := stlport_static
APP_ABI := all

# Enable c++11 extentions in source code
APP_CPPFLAGS += -std=c++11

#Enable optimalization in release mode
APP_OPTIM := release

My new gradle file looks like this:

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 22
        buildToolsVersion = "23.0.0 rc3"

        defaultConfig.with {
            applicationId = "com.example"
            minSdkVersion.apiLevel = 9
            targetSdkVersion.apiLevel = 22
            versionCode = 1
            versionName = "1.0"
        }
    }

    android.ndk {
        moduleName = "NativeLibrary"
        cppFlags   += "-I${file("src/main/jni/some_folder")}".toString()
        cppFlags   += "-std=c++11"

        //What should be added here to compile the NDK on API 9???

        CFlags += "-DNDEBUG"
        CFlags += "-fvisibility=hidden"
        cppFlags += "-fvisibility=hidden"

        ldLibs     += ["log"]
        stl         = "stlport_static"
    }

    android.buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles += file('D:/path/proguard-rules.pro')
        }
    }
}

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

I investigated the Gradle source and it seems that the NDK build target is hard-coded the same as the compileSdkVersion. Is there an method to avoid or alter this behavior?

NdkCompile.groovy (make file creation)

// target
IAndroidTarget target = getPlugin().loadedSdkParser.target
if (!target.isPlatform()) {
    target = target.parent
}
commands.add("APP_PLATFORM=" + target.hashString())

Sdk.groovy (target is fetched form the compileSdkVersion)

public SdkParser loadParser() {
    checkNotNull(extension, "Extension has not been set")

    // call getParser to ensure it's created.
    SdkParser theParser = getParser()

    if (!isSdkParserInitialized) {
        String target = extension.getCompileSdkVersion()
        if (target == null) {
            throw new IllegalArgumentException("android.compileSdkVersion is missing!")
        }

        FullRevision buildToolsRevision = extension.buildToolsRevision
        if (buildToolsRevision == null) {
            throw new IllegalArgumentException("android.buildToolsVersion is missing!")
        }

        theParser.initParser(target, buildToolsRevision, logger)

        isSdkParserInitialized = true
    }

    return theParser
}
like image 783
Rolf ツ Avatar asked Jul 14 '15 10:07

Rolf ツ


2 Answers

If you are using the experimental plugin version 0.4. you can set

android.ndk {
   platformVersion = "19"
}
like image 86
JE42 Avatar answered Nov 14 '22 22:11

JE42


Ok, this is a terrible hack, but it is very easy. Find the NDK, it should be in android-sdk/ndk-bundle. Go into the platforms folder. Rename android-21 to something else. Make a copy of android-19, and then copy the three 64-bit folders from android-21 into it, then rename it android-21. Gradle will THINK it's using android-21, and it will for 64-bit targets, but for 32-bit targets it will use android 19.

I'm not 100% sure this is safe, but I tested it on a few devices and I've got an app in Beta Test right now. I think it's cleaner than making gradle tasks for ndk-build. Whenever Google fixes experimental gradle, nothing needs to change other than to reinstall the ndk.

like image 35
Peter Sperl Avatar answered Nov 14 '22 22:11

Peter Sperl