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.
Related
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
I have a project that uses the non-experimental version of the Android Gradle plugin (com.android.tools.build:gradle:2.1.3). I have some native code that I build into a shared library libnative.so.
The problem is that now I want to link libnative.so against a prebuilt library. Let's call this file libfoo.so. If I set the jniLibs.srcDir to the folder containing libfoo.so for the different ABIs I see that it gets bundled into my APK.
However I don't understand how I am supposed to link against it successfully. If I add "foo" to ldLibs I get a linker error saying that it can't find the library. This is probably because the folder containing libfoo.so is not included as a search path to the linker.
How am I supposed to do this? Is it simply not possible without switching to the experimental gradle plugin?
This is my gradle file. I stripped away the part that probably is irrelevant for this problem:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.foo.bar"
minSdkVersion 15
targetSdkVersion 23
versionCode 11
versionName "0.0.11"
def foodir = "${project.buildDir}/../../foo"
ndk {
moduleName "native"
ldLibs "foo"
stl "gnustl_static"
}
sourceSets {
main {
jniLibs.srcDirs = ["${foodir}"]
}
}
}
}
I have several c++ projects which I currently build using Android.mk files and ndk-build. Since this is not really great to debug I want to include this c++ projects as modules inside my android studio project. This android studio project is currently an android java library which uses the .so from the ndk-build.
I got debugging to work by creating a new android library module and importing the c++ code, setting header and library paths. This module looks like this:
apply plugin: 'com.android.model.library'
model {
android {
compileSdkVersion = 23
buildToolsVersion = '23.0.2'
defaultConfig {
minSdkVersion.apiLevel = 4
targetSdkVersion.apiLevel = 23
}
}
android.ndk {
moduleName = 'module_name'
toolchain = 'gcc'
stl "gnustl_static"
ldFlags.addAll(["-L/LIB_PATH"])
ldLibs.addAll(["android", "log", "whatever_lib"])
cppFlags.addAll(['-std=c++11',
"-I" + "/SEARCH_PATHS"])
}
android.productFlavors {
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
}
android.sources {
main {
java.source.srcDirs += []
res.source.srcDirs += []
assets.source.srcDirs += []
jniLibs.source.srcDirs += []
jni.source{
srcDirs += [
NATIVE_PROJECT_PATH + "include/",
NATIVE_PROJECT_PATH + "src/",
]
}
}
}
}
This works fine but i get the .so in module/build/output/aar/libname_release.aar/lib/abi/lib.so which is not a good spot since i would need the .so directly without unzipping the aar.
Is there any possible way to let this module only create the .so at a given path and have another module build and use it?
Of course I find a way shortly after asking.
http://tools.android.com/tech-docs/new-build-system/gradle-experimental#TOC-NDK-Dependencies
Instead of "apply plugin: 'com.android.model.library'" you can use "apply plugin: 'com.android.model.native'" and in the module having the dependency you can use:
sources {
main {
jni {
dependencies {
project ":dependency_module"
}
}
}
}
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 built some test c and c++ programs using gradle following these examples
I was also able to setup android studio with the experimental features to build a android project calling native functions with the help of this answer
I know that I can build this project using the android.useDeprecatedNdk=true
and provide my android.mk file for android studio to compile and build the app.
Is it possible with the experimental feature to build this same program? This project is built with CMAKE and there are some compilation steps that output files that needs to link. ndk-build creates these files but I can't find a way to do it with with android experimental features.
I am attempting for testing purposes and to build a non trivial example of building a more complex project. I decided to try to build the zlib library.
Here is my build.gradle
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
defaultConfig.with {
applicationId = "me.test.testnative_exp"
minSdkVersion.apiLevel = 10
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
buildConfigFields.with {
create() {
type = "int"
name = "VALUE"
value = "1"
}
}
}
}
compileOptions.with {
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
android.ndk {
moduleName = "hello-jni"
cppFlags += "-I${file("src/main/jni/zlib")}".toString()
stl = "stlport_static"
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.pro')
}
}
android.sources {
main {
java {
source {
srcDir 'src'
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
}
my project structure is
app/
build/
libs/
src/
src/main/testActivity.java
jni/zlib <- the zlib folder is the one that I downloaded from the zlib website.
jni/hello-jni.c
After syncing the build.gradle I get a link error on the header in file:
infbak9.c cannot find #include "zutil.h"
but both files are in the zlib directory under jni.
Is it possible to use the android studio experimental ndk build to compile this project?
there is good project in github that i use its structure in mine, it is nice example for start on "how use experimental(v_0.4.0) plugin in complex project?" :
https://github.com/frogermcs/FlatBuffs
*there are zlib in android NDK, just add appropriate cflag and ldLibs.add("z") in gradle. and in your native code include <zlib.h>
and a good experimental gradle config from google :
https://github.com/googlesamples/android-ndk/blob/229cbe86238d401bb06166b8dfadec8198532589/native-codec/app/build.gradle
you might check this repo for a group of samples:
https://github.com/googlesamples/android-ndk
your issue might be able to fixed by adding something as[from Teapot sample there]:
cppFlags.addAll(['-I' + "${ndkDir}/sources/android/cpufeatures",'-I' + file('src/main/jni/ndk_helper')])
just replace the directory with your own path "zutil.h" etc. you may also use the latest gradle-experimental version to simplify your script -- like removing ".with" for defaultConfig.with, delete java 7 version section( the latest android studio could handle java 8 ), those ".toString()" thing is also wordy so the samples have changed style to use "+" [those is not problem for your build error though]