I am using the android gradle experimental plugin to build an app module with some native code. This native code uses a library with pre-built .so files, which I am bundling into a .aar file via an android library module. The .aar file builds fine, but how do I link the native code module in the app module to the pre-built .so files in the .aar module? The gradle experimental documentation doesn't mention this scenario.
Also, I'd like to package up include files in the .aar file if possible (although they shouldn't be packaged with the final application).
In /prebuiltlib:
build.gradle
-src/
--main/
---jniLibs/
----libfoo.so
Here are the gradle files:
/prebuiltlib/build.gradle
apply plugin: "com.android.model.library"
model {
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
minSdkVersion.apiLevel = 21
targetSdkVersion.apiLevel = 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file("proguard-rules.pro"))
}
}
}
}
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:25.3.1"
}
Here is /app/build.gradle, note the ??? where I'm not sure what to put:
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.model.application'
model {
repositories {
libs(PrebuiltLibraries) {
// ??? is this right, and does this go into app/build.gradle or mylib/build.gradle?
foo {
binaries.withType(SharedLibraryBinary) {
sharedLibraryFile = file('???/libfoo.so')
}
}
}
}
android {
compileSdkVersion = 25
buildToolsVersion = '25.0.3'
defaultConfig {
applicationId = 'com.jeremy.stackoverflow.sample'
minSdkVersion.apiLevel = 21
targetSdkVersion.apiLevel = 21
versionCode = 1
versionName = '1.0'
}
ndk {
platformVersion = 21
moduleName = 'native-activity'
toolchain = 'gcc'
toolchainVersion = '4.9'
stl = 'gnustl_shared'
abiFilters.add('armeabi-v7a')
ldLibs.addAll(['log',
'android',
'EGL',
'GLESv2'
])
// ??? How do I add include paths from the .aar module?
cppFlags.add('-I' + file('???/include'))
cppFlags.addAll(['-std=c++11', '-fexceptions'])
}
sources {
main {
jni {
dependencies {
// ??? Is this right?
library 'foo' linkage 'shared'
}
}
jniLibs {
source {
// ??? Do I need one of these for the libs in the .aar?
srcDir file('???/jniLibs')
}
dependencies {
// ??? Is this right?
library 'foo'
}
}
}
}
buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.pro'))
}
}
}
}
dependencies {
println rootProject.getName()
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.3.1'
compile project(':prebuiltlib')
}
Starting with Android Gradle Plugin 4.0, C/C++ dependencies can be imported from AARs linked in your build.gradle file. Gradle will automatically make these available to the native build system, but your build system must be configured to make use of the imported libraries and headers.
In gradle 4.0: add the following to your project's gradle.properties file:
android.enablePrefab=true
In gradle 4.1: add the following to the android block of your module's build.gradle file:
buildFeatures {
prefab true
}
, if your application defines libapp.so and it uses cURL, your CMakeLists.txt should include the following:
add_library(app SHARED app.cpp)
# Add these two lines.
find_package(curl REQUIRED CONFIG)
target_link_libraries(app curl::curl)
app.cpp is now able to #include "curl/curl.h", libapp.so will be automatically linked against libcurl.so when building, and libcurl.so will be included in the APK.
Source: https://developer.android.com/studio/build/native-dependencies
Related
I have an Android Library project which has a part in C/C++ via Android NDK.
The project started half of a year ago so we chose to use Experimental Plugin because of better NDK support.
I'm using gradle-experimental:0.8.2right now. I have a com.android.model.native module and i would like to migrate it to gradle:2.2.0. The only option i see in Gradle Android Plugin DSL is:
AppExtension: android extension for com.android.application projects.
LibraryExtension: android extension for com.android.library projects.
TestExtension: android extension for com.android.test projects.
So the question is how to make a pure native module in gradle with stable gradle plugin?
Here is my current native module:
apply plugin: 'com.android.model.native'
apply from: "../config.gradle"
def config = ext.configuration
model {
android {
compileSdkVersion = config.compileSdkVersion
buildToolsVersion = config.buildToolsVersion
defaultConfig {
minSdkVersion.apiLevel = config.minimumSdkVersion
targetSdkVersion.apiLevel = config.targetSdkVersion
versionCode = 1
versionName = '1.0'
}
ndk {
moduleName = 'apicore'
platformVersion = config.minimumSdkVersion
cppFlags.add("-std=c++11")
cppFlags.add("-pthread")
cppFlags.add("-fexceptions")
cppFlags.add("-frtti")
stl = "gnustl_static"
abiFilters.addAll(config.targetPlatforms)
ldLibs.addAll(['android', 'log'])
}
sources {
main {
jni {
source {
//include "someFile.txt"
// This is ignored.
exclude "main.cpp"
exclude "misc/APITest.cpp"
exclude "misc/APITest.h"
}
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
}
}
You will need to create CMakeLists.txt or Android.mk to build your "libapicore.so", if you want to move to stable gradle plugin.
I think you should do next steps:
For easy migration move your .h, .c, .cpp to the
root_folder_of_project\app\src\main\cpp
Also add there CMakeLists.txt. It should look like:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
add_library(apicore SHARED
#here add your cpp sources
mysource1.cpp
mysource2.cpp
#do not include main.cpp misc/APITest.cpp misc/APITest.h
)
#include libraries needed for apicore lib
target_link_libraries(apicore
android
log
)
Now rewrite your app's build.gradle and point it to CMakeLists.txt:
apply plugin: 'com.android.application'
android {
compileSdkVersion = 25
buildToolsVersion = '25.0.2'
defaultConfig {
applicationId = 'com.your.app'
minSdkVersion 16
targetSdkVersion 25
ndk {
abifilters 'armeabi-v7a' /*,'armeabi', etc.*/
}
externalNativeBuild {
cmake {
arguments '-DANDROID_PLATFORM=android-19',
'-DANDROID_TOOLCHAIN=clang', /*or gcc*/
'-DANDROID_CPP_FEATURES=rtti',
'-DANDROID_CPP_FEATURES=exceptions',
'-DANDROID_STL=gnustl_static' /*CMake uses by default*/
}
}
}
buildTypes {...}
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
}
dependencies {...}
With this you will build your android application with your native "libapicore.so" inside.
I just migrated my project from Gradle Experimental Plugin to Gradle plugin for Android. The current Gradle plugin for Android still not provide something what com.android.model.native extension provided from the experimental plugin which is an ability to create a pure native module. I have to realise that i don't even need that. What i did to replace the com.android.model.native module is i made a library module where i handle the native code and building of my native libraries and i just copy the native libraries where i need them. Of course the module generate the .aar but thats not a problem i just don't use it.
I'm trying to import a little C++ Open GL ES framework I wrote for an iOS application into an Android application.
I want to use Android NDK to import this framework.
As the framework will be shared between iOS and Android, I placed it outside the jni folder. I specified the path to the source dir of this framework in my grade file as follow (http://tools.android.com/tech-docs/new-build-system/gradle-experimental#TOC-Source-Set):
In this framework I used the GLM library for math operation, but as you could see again from the above screenshot, when I try to compile the project I receive the error:
/Users/chicio/Desktop/SpectralBRDFExplorer/SpectralBRDFExplorer/glm/detail/glm.cpp:4:10: fatal error: 'glm/glm.hpp' file not found
What am I doing wrong?
I found a solution to the problem by myself.
As stated before, it was a problem in the setup of the include directories.
I made the app compile by specifying in the gradle file the include directories suing the C++ flag -I
Here you can find the complete gradle file:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 24
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "it.chicio.android.spectralbrdfexplorer"
minSdkVersion.apiLevel 22
targetSdkVersion.apiLevel 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
ndk {
moduleName "LibOpenGLJNI"
toolchain = 'clang'
stl = 'gnustl_static'
CFlags.addAll(['-Wall'])
cppFlags.addAll(['-std=c++11','-Wall',
'-I' + file('src/main/jni'),
'-I' + file('../../SpectralBRDFExplorer'),
'-I' + file('../../SpectralBRDFExplorer/lodepng')])
ldLibs.addAll(['android', 'log', 'GLESv3'])
}
sources {
main {
jni {
source {
srcDir "../../SpectralBRDFExplorer"
}
}
}
}
sources {
main {
assets {
source {
srcDir "../../Assets"
}
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:design:24.2.0'
}
I am trying to make use of the "Multiple NDK Projects" feature of the experimental gradle plugin. I am using Android Studio 2.1 and gradle plugin 0.7.0 stable. The blog seems to say that the header files specified in the exportedHeaders section of the native library will be included during compilation
exportedHeaders {
srcDir "src"
}
This does not seem to work for me. Say for example I have the following folder structure, I would expect Addition.h to be available in native.cpp, ie I should be able to say
#include <Addition.h>
but only
#include "../../../../../../../Framework/Addition/src/Addition.h"
works. Adding cppFlags to include the headers makes no difference.
Here's how some relevant files look for an example project. The example project module "app" depends on a native library module "addition" to add 2 numbers. The native library uses the new native plugin.
settings.gradle
include ':app'
include ':Addition'
project (":Addition").projectDir = new File("../../../Framework/Addition")
gradle-wrapper.properties
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
build.gradle (:app)
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
ndk {
moduleName = 'native'
platformVersion = 17
toolchain "clang"
cppFlags.addAll(['-I' + file('src/main/jni'),
'-I' + file('../../../Framework/Addition')])
}
sources {
main {
jni {
dependencies {
project ':Addition' linkage 'static'
}
}
}
}
defaultConfig {
applicationId "com.harkish.nativepluginexample"
minSdkVersion.apiLevel 21
targetSdkVersion.apiLevel 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
}
build.gradle (:Addition)
apply plugin: 'com.android.model.native'
model {
android {
compileSdkVersion = 23
buildToolsVersion = '23.0.2'
defaultConfig {
minSdkVersion.apiLevel = 21
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = '1.0'
}
ndk {
moduleName = 'addition'
}
sources {
main {
jni {
source {
srcDir "src"
}
exportedHeaders {
srcDir "src"
}
}
}
}
}
}
Anyone solved this problem? ideas?
I've inherited a really messy android project with a lot of NDK dependencies and having a lot of problems with getting gradle to correctly link and include all .so and .a files into the resulting apk.
The project consists of some java code that sets up some activities and call into a big NDK library, built from C++ which in turn links with a dosens of 3rd party library (prebuilt or built from source).
I have managed to make it build with the latest gradle experimental plugin, but for some reason, my module isn't included in the apk while my 3rd party .so files are even though I can see that gradle have built my module into a .so file which it have placed in the build directory.
My build.gradle looks like this:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "22.0.1"
defaultConfig.with {
applicationId = "<removed>"
minSdkVersion.apiLevel = 7
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
}
ndk {
moduleName = "XM"
CFlags.add("-I${file("src/main/jni")}".toString())
cppFlags.addAll(["-I${file("../../3rd_part/android/osg")}".toString()])
cppFlags.addAll(["-I${file("../../3rd_part/android/opus")}".toString()])
ldFlags.add("-L${file("src/main/jniLibs/armeabi-v7a")}".toString())
ldLibs.addAll(["osgdb_jpeg", "osgdb_freetype", "jpeg","argsub_es", "jnigraphics", "android", "log"])
stl = "gnustl_shared"
abiFilters.add("armeabi-v7a")
}
sources {
main {
jni {
source {
srcDir "../../core"
srcDir "src/main/jni"
}
}
}
}
lintOptions.abortOnError = false
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-v4:23.0.0'
compile 'com.android.support:appcompat-v7:23.0.0'
compile 'com.android.support:design:23.0.0'
compile 'com.wunderlist:sliding-layer:1.1.1'
}
So to sum up my question: why does gradle build my module (libXM.so), place it into build/libs/xM/shared/armeabi-v7a/debug, but not include it into my final apk file?
I didn't get several things: if you want to build a shared library with gradle, then you have to use apply plugin: 'com.android.model.library' and not application
If you want to build an application and use prebuilt library, then you have to write something like this:
sources {
main {
jni {
source {
srcDir "../../core"
srcDir "src/main/jni"
}
dependencies{
library "XM" linkage "shared"
}
And, of course, to set ldFlags previously.
I'm using Android Studio and building Android library project, so I distribute aar file. And to be more specific I just distribute the jar inside (yes- customers still using Eclipse so I combine manually the jar with manifest, res etc well known procedure).
This is my Gradle build script (regular default...):
apply plugin: 'com.android.library'
android {
compileSdkVersion 22
buildToolsVersion "23.0.0"
lintOptions {
abortOnError false
}
defaultConfig {
// Ain't applicationIdNot
minSdkVersion 11
targetSdkVersion 22
versionCode 1
versionName "1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/../lib'
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile '...'
}
The problem is that: Under one java package alongside regular java classes I have ttf font files. This is due to historical reasons and now the project complexity not allowing to make changes and move them to where they actually need to be.
Well - The jar missing these files. How to implement the build process such the jar inside the arr will include these files - Because after all - It's regular archive and those file are in the file tree already compressed into the jar.
Thanks,
Just specify to include the files in your sourceSets closure
// if you want to include the files in your aar
android {
...
sourceSets {
main {
resources.includes = [ '**/mySweetFont.ttf' ]
}
}
}
// to include in your jar
sourceSets {
main {
resources.includes = [ '**/mySweetFont.ttf' ]
}
}
This will place the files at the root of the artifact produced. For the jar you may need to specify the sourceSets closure twice once inside android closure and again after the android closure