1

I have some pre-build *.so files for different build flavors like

arm64-v8a, armeabi-v7a, x86, x86_64,
and these files are of android third party library. When I run the project all these *.so files are packaging in apk. But here my question is that how to package different *.SO files in different apks? can you please give build.gradle script for this. any help will be appreciated? Thank you. Sorry for my poor english.

my library.gradle is

apply plugin: 'com.android.library'

import com.android.builder.core.DefaultManifestParser

android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion

sourceSets {
    main {
        jni.srcDirs = []
        // Prevent gradle from building native code with ndk; we have our own Makefile for it.
        jniLibs.srcDirs = ['jni/libs', 'jni/loader/libs', 'private_libs/libs']
        // Where generated .so files are placed.
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        resources.srcDirs = ['src']
        aidl.srcDirs = ['src']
        renderscript.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
    }
}

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

// Make per-variant version code
libraryVariants.all { variant ->
    def manifestParser = new DefaultManifestParser(android.sourceSets.main.manifest.srcFile)
    // get the version code of each flavor
    def version = manifestParser.getVersionName()
    //Custom APK name
    variant.outputs.all { output ->
        if (outputFileName != null && outputFileName.endsWith('.aar')) {
            outputFileName = "lib-${version}.aar"
        }
    }
}
}

class BuildNative extends Exec {}

tasks.withType(BuildNative) {
/*
Properties set for Android Studio own shell.
when you run gradlew from cli, OS shell env variables will be used

To be able to build from Android Studio, you have to set ndk.dir & sdk.dir
properties in local.properties in the root folder, like this (for example):
sdk.dir=/home/<username>/SDK/android-sdk-linux
ndk.dir=/home/<username>/SDK/android-ndk-r10b
 */
if (System.getenv('ANDROID_SDK') == null || System.getenv('ANDROID_NDK') == null) {
    Properties properties = new Properties()
    properties.load(project.rootProject.file('local.properties').newDataInputStream())
    environment 'ANDROID_NDK', properties.getProperty('ndk.dir')
    environment 'ANDROID_SDK', properties.getProperty('sdk.dir')
}
workingDir '..'
commandLine './compile-libvlc.sh'
}

task buildDebugARMv7(type: BuildNative) {
args('-a', "armeabi-v7a")
}
task buildDebugARM64(type: BuildNative) {
args('-a', "arm64-v8a")
}
task buildDebugx86(type: BuildNative) {
args('-a', "x86")
}
task buildDebugx86_64(type: BuildNative) {
args('-a', "x86_64")
}
task buildDebugMIPS(type: BuildNative) {
args('-a', "mips")
}
task buildDebugMIPS64(type: BuildNative) {
args('-a', "mips64")
}

task generateSources(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}

clean {
// delete 'build', /*'jni/libs',*/ 'jni/obj'
}

dependencies {
api "com.android.support:support-annotations:$rootProject.ext.appCompatVersion"
api "com.android.support:support-v4:$rootProject.ext.appCompatVersion"
}

and my app.gradle is:

apply plugin: 'com.android.application'

android {

packagingOptions {

}

dexOptions {
    maxProcessCount 8
    javaMaxHeapSize "2g"
    preDexLibraries true
    keepRuntimeAnnotatedClasses false
}

compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion

flavorDimensions "target", "abi"

defaultConfig {
    applicationId "com.example"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    versionCode rootProject.ext.versionCode
    versionName rootProject.ext.versionName
    vectorDrawables.useSupportLibrary true
    multiDexEnabled true
}

signingConfigs {
    release {
        storeFile file("D:\\Keystore\\aaaaaaaa.jks")
        storePassword "aaaaaaa"
        keyAlias "avbbaaaaaa"
        keyPassword "ababababa"
    }
}

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

lintOptions {
    checkReleaseBuilds false
    // Or, if you prefer, you can continue to check for errors in release builds,
    // but continue the build even when errors are found:
    abortOnError false
}

dataBinding {
    enabled = true
}

productFlavors {
    vanilla {
        dimension "target"
        versionCode = 1
    }
    chrome {
        minSdkVersion 19
        dimension "target"
        versionCode = 2
    }
    ARMv7 {
        dimension "abi"
        versionCode = 4
    }
    x86 {
        dimension "abi"
        versionCode = 5
    }
    MIPS {
        dimension "abi"
        versionCode = 6
    }
    ARMv8 {
        dimension "abi"
        versionCode = 7
    }
    x86_64 {
        dimension "abi"
        versionCode = 8
    }
    MIPS64 {
        dimension "abi"
        versionCode = 9
    }
}
}
Jitendra Singh
  • 200
  • 4
  • 17

3 Answers3

3

Finally I found out how to do this, I got this solution from https://developer.android.com/studio/projects/gradle-external-native-builds. Hope you also get from something here.

android {
  ...
  defaultConfig {
    ...
    // This block is different from the one you use to link Gradle
    // to your CMake or ndk-build script.
    externalNativeBuild {

      // For ndk-build, instead use the ndkBuild block.
      cmake {

        // Passes optional arguments to CMake.
        arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"

        // Sets a flag to enable format macro constants for the C compiler.
        cFlags "-D__STDC_FORMAT_MACROS"

        // Sets optional flags for the C++ compiler.
        cppFlags "-fexceptions", "-frtti"
      }
    }
  }

  buildTypes {...}

  productFlavors {
    ...
    demo {
      ...
      externalNativeBuild {
        cmake {
          ...
          // Specifies which native libraries or executables to build and package
          // for this product flavor. The following tells Gradle to build only the
          // "native-lib-demo" and "my-executible-demo" outputs from the linked
          // CMake project. If you don't configure this property, Gradle builds all
          // executables and shared object libraries that you define in your CMake
          // (or ndk-build) project. However, by default, Gradle packages only the
          // shared libraries in your APK.
          targets "native-lib-demo",
                  // You need to specify this executable and its sources in your CMakeLists.txt
                  // using the add_executable() command. However, building executables from your
                  // native sources is optional, and building native libraries to package into
                  // your APK satisfies most project requirements.
                  "my-executible-demo"
        }
      }
    }

    paid {
      ...
      externalNativeBuild {
        cmake {
          ...
          targets "native-lib-paid",
                  "my-executible-paid"
        }
      }
    }
  }

  // Use this block to link Gradle to your CMake or ndk-build script.
  externalNativeBuild {
    cmake {...}
    // or ndkBuild {...}
  }
}

Include prebuilt native libraries

If you want Gradle to package prebuilt native libraries with your APK, modify the default source set configuration to include the directory of your prebuilt .so files, as shown below. Keep in mind, you don't need to do this to include artifacts of CMake build scripts that you link to Gradle.

android {
    ...
    sourceSets {
        main {
            jniLibs.srcDirs 'imported-lib/src/', 'more-imported-libs/src/'
        }
    }
}

Specify ABIs

By default, Gradle builds your native library into separate .so files for the ABIs the NDK supports and packages them all into your APK. If you want Gradle to build and package only certain ABI configurations of your native libraries, you can specify them with the ndk.abiFilters flag in your module-level build.gradle file, as shown below:

android {
  ...
  defaultConfig {
    ...
    externalNativeBuild {
      cmake {...}
      // or ndkBuild {...}
    }

    // Similar to other properties in the defaultConfig block,
    // you can configure the ndk block for each product flavor
    // in your build configuration.
    ndk {
      // Specifies the ABI configurations of your native
      // libraries Gradle should build and package with your APK.
      abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
                   'arm64-v8a'
    }
  }
  buildTypes {...}
  externalNativeBuild {...}
}
Mayur Patel
  • 2,300
  • 11
  • 30
0

By adding this script in app.gradle it works like a charm

ndk {
  // Specifies the ABI configurations of your native
  // libraries Gradle should build and package with your APK.
  abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a','arm64-v8a'
}
Jitendra Singh
  • 200
  • 4
  • 17
0

Another solution would be to specify the jniLibs.srcDirs based on your flavor requirements, like this:

android {
...
   sourceSets {
      def flavor = getCurrentFlavor()
      if (flavor == ‘device’ || flavor == ‘production’) {
         jniLibs.srcDirs = ['libs']//or whatever path you have
      }
   ...

Where getCurrentFlavor() gets your build flavor name. You can find how to do it here:

How to get current flavor in gradle

Ultimo_m
  • 4,724
  • 4
  • 38
  • 60