Enabling of renderscript makes app to ignore jniLibs - android

I want to use some jni libraries. So I put binaries like this:
project
-app
--jnilibs
---armeabi
----libqwerty.so
and in my build.gradle (app module):
sourceSets.main {
jniLibs.srcDirs = ['jniLibs']
}
it works as expected, however when I add renderscript to my project:
renderscriptTargetApi 22
renderscriptSupportModeEnabled true
application doesn't see my jniLibs directory anymore. And the content of getApplicationInfo().nativeLibraryDir is: [libRSSupport.so, librsjni.so]
UPDATE: ok, I was able to resolve this issue with just renaming directory armeabi to armeabi-v7a. However what if I want to support some other cpu-architectures?

See the answer by a Google developer: renderscript libraries are not supported for Arm v6 and they have no plans to port them back. As for x86, MIPS, and 64-bit versions, Gradle will automagically add appropriate RS binaries to your APK.

Related

RenderScript includes native binaries for all the platforms

Our Android project includes some native libraries and we support only arbeabi-v7. So the generate apk only includes native libraries for this architecture.
Lately we added RenderScript that causes the generated apk to include librsjni.so and libRSSuport.so native for all the supported platform i.e. x86, arbeabi-v7 etc.
The build.gradle files changes to add RenderScript are:
defaultConfig {
// Other configs
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
}
The generated apk libs folder looks like:
libs
- armeabi-v7
- librsjni.so
- libRSSuport.so
- Other native libs
- x86
- librsjni.so
- libRSSuport.so
- Other archs
- librsjni.so
- libRSSuport.so
This causes issues in phones where primary abi is non armeabi-v7 as the run time may think that non armeabi-v7 architecture are supported and tries to run it and app crashes.
As of now we have added the following to build.gradle :
ndk {
abiFilters "armeabi-v7a"
}
and in gradle.properties:
android.useDeprecatedNdk=true
Though this solves the issue, but it does seems like a hack or non standard solution.
Is there a standard or recommended way to solve this issue?
If you only use prebuilt libraries, your best option is to employ the splits feature:
android {
…
splits {
abi {
enable true
reset()
include "armeabi-v7a"
universalApk false
}
}
}

How to include a .so library and .c files in Android Studio 1.5

How can I add a .so library in Android Studio and make calls to it through a .c file with native code?
I have googled for a week and I've tried every posible solution I've found but nothing.
The sites are this, this, this, this, and more...
I arrived to make calls to a native .c file but I cannot include the .so library because Android studio cannot find it.
I don't want to use the new experimental gradle yet.
The environment configuration is the next one:
Android Studio 1.5
Gradle 2.8
Android plugin version 1.3.0
JDK 1.8.0
This is part of my code and gradle configuration:
GRADLE FILE
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
....
ndk {
moduleName "ffmpegkit"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
PROJECT STRUCTURE
INCLUDE STATEMENTS IN .C FILE
As you can see, "libavcodec.so" is not found but the project structure is the correct according to some solutions I've found.
Does anybody know how can I solve this problem and use these .so libraries with .c files?
Thank you very much!
I assume your .c file is somewhere under ffmpegkit directory in your project. You copied the ffmpeg binaries to your project's jniLibs, too. So far so good.
You need to provide the path to ffmpeg include files so that your .c files could compile. You also must list the libraries that the linker needs to find the external references of libffmpegkit.so that you are building:
defaultConfig {
....
ndk {
moduleName "ffmpegkit"
abiFilter "armeabi"
cFlags "-I/qqq/ffmpeg"
ldLibs "-llog -L src/main/libs", "avformat", "avcodec", "avutil"
}
}
Make sure that the ffmpeg libraries are compiled with a compatible Android toolchain! Note that the order in which ffmpeg libraries are listed is important. Like, libavformat depends on libavcodec, therefore it should go before.

Android NDK - multlib support using gradle

My question is directed towards native Android development for 64bit Android systems.
I am looking for a way to configure the support of 32bit compiled native libraries at a 64bit Android system using the gradle build system. The libraries the application should use are only available as 32bit build. It would be very time consuming and error prone to port these libraries to 64bit.
Hence, I want to configure gradle to deploy these prebuilt 32bit binaries and to use a 32bit version of the Android application as well.
The current configuration leads to the following error:
E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: <application_name>, PID: 2170
java.lang.UnsatisfiedLinkError:
dalvik.system.PathClassLoader
[DexPathList[[zip file "/data/app/<application_name>/base.apk"],
nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]]
enter code here`couldn't find "libmynativelibrary.so"
at java.lang.Runtime.loadLibrary(Runtime.java:366)
It seems as though the PathClassLoader looks in the wrong directories. I checked the provided apk file and it is lacking the libraries. There is no lib folder inside the apk. The build system does not seam to include the 32bit libraries.
Since there is only one prebuild version for armv7 these libraries are in app/src/main/jnilibs folder.
I have to add that this setup works perfectly for any 32bit Android system. I tried it with the emulator and a physical device before.
How should one activate the multiarch 32/64bit support using gradle? Or how is it possible to deploy a 32bit application to a 64bit Android system using Android Studio/gradle?
I searched the web and found one link concerning the topic, but it is referring to the older build system: https://source.android.com/source/64-bit-builds.html. I do not know how to adopt the description to gradle.
I am using Android Studio (Build: 141.1989493, June 6, 2015).
The project/build.gradle is untouched. The app/build.gradle file looks like this:
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "<application_name>"
minSdkVersion 1
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
debug {
debuggable true
}
}
productFlavors {
armv7 {
ndk {
abiFilter "armeabi-v7a"
}
}
fat
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
The concept of mulilib is only for projects that are part of an Android system build and you shouldn't set the android:multiarch option as you only have 32bit libs since this option is only for apps that are providing both 32 and 64bit libraries to other installed application.
64-bit Android systems support 32-bit applications directly. You only need to properly package your app, with your .so files inside lib/(armeabi-v7a,x86,...) of the APK, as for any Android devices.
At the install time, the libs of the architecture that is preferred by the device will be installed. ie: if there is no x86_64 folder, the x86 libs will be installed / if there is no arm64-v8a folder, the armeabi-v7a libs will be installed, and your app will run in 32-bit mode.
If you don't have anything under lib, that means Android Studio doesn't know about your .so files. By default it will look for them inside jniLibs/(armeabi-v7a,x86,...), hence you should place them there or change sourceSets.main.jniLibs.srcDir to the directory of your choice.
In order to get 32bit application deployment for 64bit Android system one needs to define a armv7 productFlavor and a subfolder inside the jniLibs folder naming the corresponding architecture.
Product flavor definition in app/build.gradle:
android {
productFlavors {
armv7 { ndk { abiFilter "armeabi-v7a" } }
fat
}
}
Native library structure: 
app/src/main/jniLibs/armeabi-v7a

How to use the Renderscript Support Library with Gradle

Is it possible to use the Support Renderscript Library with Gradle? If so, how do you include it in your project?
Using Android Studio:
Add the following values to build.gradle for android gradle plugin v0.14+
android {
...
defaultConfig {
...
renderscriptTargetApi 19
renderscriptSupportModeEnabled true
}
...
}
For older versions of the android gradle plugin v0.13.3 and below
android {
...
defaultConfig {
...
renderscriptTargetApi 19
renderscriptSupportMode true
}
...
}
Once that is done, use android.support.v8.renderscript. anywhere in your app. The library jar and binaries are included automatically.
Gradle for Android has now Renderscript v8 support with only 2 lines in your build script. See answer by Austyn Mahoney. Keeping the original answer for historical purpose.
Old Answer:
Gradle supports native RS compilation, but not the RS support library. The reason is that the RS support library is hugely complicated compared to any other support library. The RS support library is actually a Java support library, a set of native libraries backing that Java lib, additional native libraries for every script you compile, and an alternate toolchain for generating both the standard LLVM bitcode and the native libraries for your scripts. Right now, only ADT and Ant support that; Gradle isn't there yet.
However, it's possible to use some parts of the RS support library from Gradle already. If you want to use the RS intrinsics, you can link the Java part of the support library (sdk/build-tools/android-4.3/lib/renderscript/renderscript-v8.jar) and the native components (sdk/build-tools/android-4.3/lib/renderscript/packaged/< arch >/*.so), and then you'll be set.
I know Gradle support for the support library is coming at some point in the not too distant future, but I don't have a firm ETA that I can share.
Following Tim's hint, I was able to get v8 support working with Gradle, here is my project layout:
I created libs folder, and copied files Tim mentioned under the SDK folder. And here is my build.gradle changes:
dependencies {
compile files('libs/renderscript-v8.jar')
}
android {
tasks.withType(com.android.build.gradle.tasks.PackageApplication) {
pkgTask -> pkgTask.jniFolders = new HashSet<File>();
pkgTask.jniFolders.add(new File(projectDir, 'libs'));
}
}
After that, I can import android.support.v8.renderscript.* and use the intrinsics.
I know this has been already answered, but I thought I'd share my experience with Android-Studio and Renderscript support with Build-tools 21.1.0.
This is what I found in build-system changelog lines 26-32:
Renamed a few properties to make things more consistent.
BuildType.runProguard -> minifyEnabled
BuildType.zipAlign -> zipAlignEnabled
BuildType.jniDebugBuild -> jniDebuggable
BuildType.renderscriptDebug -> renderscriptDebuggable
ProductFlavor.renderscriptSupportMode -> renderscriptSupportModeEnabled
ProductFlavor.renderscriptNdkMode -> renderscriptNdkModeEnabled
So you see, they have changed the properties name.
I just updated build.gradle to use:
renderscriptSupportModeEnabled true
Now the libraries are added to the project and you don't need to manually add them to your lib folder.
There is experimental support in the Gradle Android plugin at the time of this writing. See this test project for more info.
If anyone is interested in how to package this as a distributable binary .jar (e.g. for deploying to a maven repo) you can use this file structure for your .jar.
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>android</groupId>
<artifactId>renderscript</artifactId>
<version>19.0.3</version>
<description>Artifactory auto generated POM</description>
</project>
For build.gradle, add: compile 'android:renderscript:19.0.3' to your dependencies clojure.
PS: The renderscript library won't run on armv6 (armeabi), so make sure that Build.CPU_ABI is either armeabi-v7a, mips or x86.

Android studio, gradle and NDK

I am very new to this whole gradle and Android Studio support. I have managed to convert my android project to gradle using the export option.
But I am looking for some documentation or start point how to integrate the NDK build into the gradle build process.
If possible I also need some sort of "after" stage that copies the build binaries (.so files) to the asset directory.
We have released a first version of the integration as a preview in 1.3: http://tools.android.com/tech-docs/android-ndk-preview
The integration will stay a preview even after 1.3 becomes final. No current ETA as to when it'll be final (as of 2015/07/10).
More information here: http://tools.android.com/tech-docs/android-ndk-preview
UPDATE: The Android Studio with NDK support is out now: http://tools.android.com/tech-docs/android-ndk-preview
For building with a script the gradle solution below should work:
I am using my build script and added to my file (Seems to work for 0.8+): This seems to be equivalent to the solution below (but looks nicer in the gradle file):
android {
sourceSets {
main {
jniLibs.srcDirs = ['native-libs']
jni.srcDirs = [] //disable automatic ndk-build
}
}
}
The build unfortunately does not fail if the directory is not present or contains no .so files.
With the update of Android Studio to 1.0, the NDK toolchain support improved immensely (note: please read my updates at the bottom of this post to see usage with the new experimental Gradle plugin and Android Studio 1.5).
Android Studio and the NDK are integrated well enough so that you just need to create an ndk{} block in your module's build.gradle, and set your source files into the (module)/src/main/jni directory - and you're done!
No more ndk-build from the command line.
I've written all about it in my blog post here: http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/
The salient points are:
There are two things you need to know here. By default, if you have external libs that you want loaded into the Android application, they are looked for in the (module)/src/main/jniLibs by default. You can change this by using setting sourceSets.main.jniLibs.srcDirs in your module’s build.gradle. You’ll need a subdirectory with libraries for each architecture you’re targeting (e.g. x86, arm, mips, arm64-v8a, etc…)
The code you want to be compiled by default by the NDK toolchain will be located in (module)/src/main/jni and similarly to above, you can change it by setting sourceSets.main.jni.srcDirs in your module’s build.gradle
and put this into your module's build.gradle:
ndk {
moduleName "SeePlusPlus" // Name of C++ module (i.e. libSeePlusPlus)
cFlags "-std=c++11 -fexceptions" // Add provisions to allow C++11 functionality
stl "gnustl_shared" // Which STL library to use: gnustl or stlport
}
That's the process of compiling your C++ code, from there you need to load it, and create wrappers - but judging from your question, you already know how to do all that, so I won't re-hash.
Also, I've placed a Github repo of this example here: http://github.com/sureshjoshi/android-ndk-swig-example
UPDATE: June 14, 2015
When Android Studio 1.3 comes out, there should be better support for C++ through the JetBrains CLion plugin. I'm currently under the assumption that this will allow Java and C++ development from within Android Studio; however I think we'll still need to use the Gradle NDK section as I've stated above. Additionally, I think there will still be the need to write Java<->C++ wrapper files, unless CLion will do those automatically.
UPDATE: January 5, 2016
I have updated my blog and Github repo (in the develop branch) to use Android Studio 1.5 with the latest experimental Gradle plugin (0.6.0-alpha3).
http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/
http://github.com/sureshjoshi/android-ndk-swig-example
The Gradle build for the NDK section now looks like this:
android.ndk {
moduleName = "SeePlusPlus" // Name of C++ module (i.e. libSeePlusPlus)
cppFlags.add("-std=c++11") // Add provisions to allow C++11 functionality
cppFlags.add("-fexceptions")
stl = "gnustl_shared" // Which STL library to use: gnustl or stlport
}
Also, quite awesomely, Android Studio has auto-complete for C++-Java generated wrappers using the 'native' keyword:
However, it's not completely rosy... If you're using SWIG to wrap a library to auto-generate code, and then try to use the native keyword auto-generation, it will put the code in the wrong place in your Swig _wrap.cxx file... So you need to move it into the "extern C" block:
UPDATE: October 15, 2017
I'd be remiss if I didn't mention that Android Studio 2.2 onwards has essentially 'native' (no pun) support for the NDK toolchain via Gradle and CMake. Now, when you create a new project, just select C++ support and you're good to go.
You'll still need to generate your own JNI layer code, or use the SWIG technique I've mentioned above, but the scaffolding of a C++ in Android project is trivial now.
Changes in the CMakeLists file (which is where you place your C++ source files) will be picked up by Android Studio, and it'll automatically re-compile any associated libraries.
In Google IO 2015, Google announced full NDK integration in Android Studio 1.3.
It is now out of preview, and available to everyone: https://developer.android.com/studio/projects/add-native-code.html
Old answer: Gradle automatically calls ndk-build if you have a jni directory in your project sources.
This is working on Android studio 0.5.9 (canary build).
Download the NDK
Either add ANDROID_NDK_HOME to your environment variables or add ndk.dir=/path/to/ndk to your local.properties in your Android Studio project. This allows Android studio to run the ndk automatically.
Download the latest gradle sample projects to see an example of an ndk project. (They're at the bottom of the page). A good sample project is ndkJniLib.
Copy the gradle.build from the NDK sample projects. It'll look something like this. This gradle.build creates a different apk for each architecture. You must select which architecture you want using the build variants pane.
apply plugin: 'android'
dependencies {
compile project(':lib')
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.2"
// This actual the app version code. Giving ourselves 100,000 values [0, 99999]
defaultConfig.versionCode = 123
flavorDimensions "api", "abi"
productFlavors {
gingerbread {
flavorDimension "api"
minSdkVersion 10
versionCode = 1
}
icecreamSandwich {
flavorDimension "api"
minSdkVersion 14
versionCode = 2
}
x86 {
flavorDimension "abi"
ndk {
abiFilter "x86"
}
// this is the flavor part of the version code.
// It must be higher than the arm one for devices supporting
// both, as x86 is preferred.
versionCode = 3
}
arm {
flavorDimension "abi"
ndk {
abiFilter "armeabi-v7a"
}
versionCode = 2
}
mips {
flavorDimension "abi"
ndk {
abiFilter "mips"
}
versionCode = 1
}
fat {
flavorDimension "abi"
// fat binary, lowest version code to be
// the last option
versionCode = 0
}
}
// make per-variant version code
applicationVariants.all { variant ->
// get the version code of each flavor
def apiVersion = variant.productFlavors.get(0).versionCode
def abiVersion = variant.productFlavors.get(1).versionCode
// set the composite code
variant.mergedFlavor.versionCode = apiVersion * 1000000 + abiVersion * 100000 + defaultConfig.versionCode
}
}
Note that this will ignore your Android.mk and Application.mk files. As a workaround, you can tell gradle to disable atuomatic ndk-build call, then specify the directory for ndk sources manually.
sourceSets.main {
jniLibs.srcDir 'src/main/libs' // use the jni .so compiled from the manual ndk-build command
jni.srcDirs = [] //disable automatic ndk-build call
}
In addition, you'll probably want to call ndk-build in your gradle build script explicitly, because you just disabled the automatic call.
task ndkBuild(type: Exec) {
commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
I found "gradle 1.11 com.android.tools.build:gradle:0.9.+" supports pre-build ndk now, you can just put the *.so in the dir src/main/jniLibs.
when building gradle will package the ndk to the right place.
here is my project
Project:
|--src
|--|--main
|--|--|--java
|--|--|--jniLibs
|--|--|--|--armeabi
|--|--|--|--|--.so files
|--libs
|--|--other.jar
As Xavier said, you can put your prebuilts in /src/main/jniLibs/ if you are using gradle 0.7.2+
taken from: https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/ctDp9viWaxoJ
As of now (Android Studio v0.8.6) it's quite simple. Here are the steps to create a "Hello world" type app:
Download the Android NDK and put the root folder somewhere sane -- in the same location as the SDK folder, perhaps.
Add the following to your local.properties file:
ndk.dir=<path-to-ndk>
Add the following to your build.gradle file inside of the defaultConfig closure, right after the versionName line: ndk { moduleName="hello-world" }
In your app module's main directory, create a new folder called jni.
In that folder, create a file called hello-world.c, which you'll see below.
See the example Activity code below for an example of how to call a method (or is it a function?) in hello-world.c.
hello-world.c
#include <string.h>
#include <jni.h>
jstring
Java_me_mattlogan_ndktest_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz)
{
return (*env)->NewStringUTF(env, "Hello world!");
}
MainActivity.java
public class MainActivity extends Activity {
static {
System.loadLibrary("hello-world");
}
public native String stringFromJNI();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String testString = stringFromJNI();
TextView mainText = (TextView) findViewById(R.id.main_text);
mainText.setText(testString);
}
}
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 20
buildToolsVersion "20.0.0"
defaultConfig {
applicationId "me.mattlogan.ndktest"
minSdkVersion 15
targetSdkVersion 20
versionCode 1
versionName "1.0"
ndk {
moduleName "hello-world"
}
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
Find the full source code of a very similar app here (minus the NDK).
If you're on unix the latest version (0.8) adds ndk-build. Here's how to add it:
android.ndk {
moduleName "libraw"
}
It expects to find the JNI under 'src/main/jni', otherwise you can define it with:
sourceSets.main {
jni.srcDirs = 'path'
}
As of 28 JAN 2014 with version 0.8 the build is broken on windows, you have to disable the build with:
sourceSets.main {
jni.srcDirs = [] //disable automatic ndk-build call (currently broken for windows)
}
An elegant workaround is shown in https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/Z5yWAvCh4h4J.
Basically you create a jar which contains "lib/armeabi/yourlib.so" and then include the jar in the build.
A good answer automating the packaging of readily compiled .so-files is given in another (closed) thread. To get that working, I had to change the line:
from fileTree(dir: 'libs', include: '**/*.so')
into:
from fileTree(dir: 'src/main/libs', include: '**/*.so')
Without this change the .so files were not found, and the task for packaging them would therefore never run.
The answer from #plaisthos broke in the latest gradle version, but there is still a way to do it.
Create a native-libs directory in the root of your project directory and copy all y our libs into this directory.
Add the following lines to your build.gradle. Build and be happy.
task copyNativeLibs(type: Copy) {
from(new File(project(':<your project>').getProjectDir(), 'native-libs')) { include '**/*.so' }
into new File(buildDir, 'native-libs')
}
tasks.withType(Compile) { compileTask -> compileTask.dependsOn copyNativeLibs }
clean.dependsOn 'cleanCopyNativeLibs'
This is the code i use to build using android-ndk from gradle. For this add ndk directory path in gradle.properties ie . add ndkdir=/home/user/android-ndk-r9d and put all jni files in a folder native in src/main/ as you can see from code posted below. It will create jar with native libs which you can use normally as in System.loadLibrary("libraryname");
dependencies {
compile fileTree(dir: "$buildDir/native-libs", include: '*.jar')
}
task ndkBuild(type: Exec) {
commandLine "$ndkdir/ndk-build", "--directory", "$projectDir/src/main/native", '-j', Runtime.runtime.availableProcessors(),
"APP_PLATFORM=android-8",
"APP_BUILD_SCRIPT=$projectDir/src/main/native/Android.mk",
"NDK_OUT=$buildDir/native/obj",
"NDK_APP_DST_DIR=$buildDir/native/libs/\$(TARGET_ARCH_ABI)"
}
task nativeLibsToJar(type: Jar, description: 'create a jar with native libs') {
destinationDir file("$buildDir/native-libs")
baseName 'native-libs'
from fileTree(dir: "$buildDir/native/libs", include: '**/*.so')
into 'lib/'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn nativeLibsToJar
}
nativeLibsToJar.dependsOn 'ndkBuild'
I have used the following code to compile native dropbox libraries, I am using Android Studio v1.1.
task nativeLibsToJar(type: Zip) {
destinationDir file("$buildDir/native-libs")
baseName 'native-libs'
extension 'jar'
from fileTree(dir: 'src/main/libs', include: '**/*.so')
into 'lib/'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn(nativeLibsToJar)
}
I have used ndk.dir=/usr/shareData/android-ndk-r11b // path of ndk in local.properties file in android studio project. and
add this line : android.useDeprecatedNdk=true in gradle.properties file in android studio project.
More information here: http://tools.android.com/tech-docs/android-ndk-preview
To expand on what Naxos said (Thanks Naxos for sending me in the right direction!), I learned quite a bit from the recently released NDK examples and posted an answer in a similar question here.
How to configure NDK with Android Gradle plugin 0.7
This post has full details on linking prebuilt native libraries into your app for the various architectures as well as information on how to add NDK support directly to the build.gradle script. For the most part, you shouldn't need to do the work around zip and copy anymore.
Here are the steps that I used to get the NDK working in my Android Studio project.
I used this tutorial to help me out
https://software.intel.com/en-us/videos/using-the-ndk-with-android-studio
In order to use NDK you must add a NDK line to local.properties. So under your sdk.dir add
ndk.dir=C\:\\MyPathToMyNDK\ndk
In my apps build.gradle I have the following code
ndk {
moduleName "myLib"
ldLibs "log"
stl "gnustl_shared"
cFlags "-std=c++11 -frtti -fexceptions -pthread"
}
moduleName is the name you want to give your native code. I believe this is what the shared library will be called. ldLibs allows me to log to LogCat, stl is the stl that you want to import. There are lots of options, same as the Eclipse NDK. (http://www.kandroid.org/ndk/docs/CPLUSPLUS-SUPPORT.html)
cFlags are still a certain amount of black magic for me. I have not found a good source for all the options and what they give me. Search around StackOverflow for anything you need, that is where I found it. I do know that the c++11 allows me to use the new c++ 11 standard.
Here is an example of how I log to LogCat from the native code
__android_log_print(ANDROID_LOG_DEBUG, "TestApp", "Adding - String %d has a field name of %s and a value of %s", i, lKeyUTF8.c_str(), lValueUTF8.c_str());
configure project in android studio from eclipse: you have to import eclipse ndk project to android studio without exporting to gradle and it works , also you need to add path of ndk in local.properties ,if shows error then add
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = [] //disable automatic ndk-build callenter code here
}
in build.gradle file then create jni folder and file using terminal and run it will work
Now that Android Studio is in the stable channel, it is pretty straightforward to get the android-ndk samples running. These samples use the ndk experimental plugin and are newer than the ones linked to from the Android NDK online documentation. Once you know they work you can study the build.gradle, local.properties and gradle-wrapper.properties files and modify your project accordingly. Following are the steps to get them working.
Go to settings, Appearance & Behavior, System Settings, Android SDK, selected the SDK Tools tab, and check Android NDK version 1.0.0 at the bottom of the list. This will download the NDK.
Point to the location of the newly downloaded NDK. Note that it will be placed in the sdk/ndk-bundle directory. Do this by selecting File, Project Structure, SDK Location (on left), and supplying a path under Android NDK location. This will add an ndk entry to local.properties similar to this:
Mac/Linux: ndk.dir=/Android/sdk/ndk-bundle
Windows: ndk.dir=C:\Android\sdk\ndk-bundle
I have successfully built and deployed all projects in the repository this way, except gles3gni, native-codec and builder. I'm using the following:
Android Studio 1.3 build AI-141.2117773
android-ndk samples published July 28, 2015 (link above)
SDK Tools 24.3.3
NDK r10e extracted to C:\Android\sdk\ndk-bundle
Gradle 2.5
Gradle plugin 0.2.0
Windows 8.1 64 bit
NDK Builds and gradle (basic)
Generally building with the NDK is as simple as correctly specifying an ndkBuild path to Android.mk or cmake path to CMakeLists.txt. I recommend CMake over the older Android.mk because Android Studio's C/C++ support is based upon CLion and it uses CMake as its project format. This in my experience has tended to make the IDE more responsive on larger projects. Everything compiled in your project will be built and copied into the APK automatically.
apply plugin: 'com.android.library'
android {
compileSdkVersion 19
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 19
targetSdkVersion 19
ndk {
abiFilters 'armeabi', 'armeabi-v7a', 'x86'
// 64-bit support requires an Android API level higher than 19; Namely 21 and higher
//abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
externalNativeBuild {
cmake {
arguments '-DANDROID_TOOLCHAIN=clang',
'-DANDROID_PLATFORM=android-19',
'-DANDROID_STL=gnustl_static',
'-DANDROID_ARM_NEON=TRUE'
}
}
}
externalNativeBuild {
cmake {
path 'src/main/jni/CMakeLists.txt'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
Adding prebuilt libraries to the project (advanced)
Static libraries (.a) in your NDK build will automatically be included, but prebuilt dynamic libraries (.so) will need to be placed in jniLibs. This can be configured using sourceSets, but you should adopt the standard. You DO NOT NEED any additional commands in build.gradle when including prebuilt libraries.
The layout of jniLibs
You can find more information about the structure in the Android Gradle Plugin User Guide.
|--app:
|--|--build.gradle
|--|--src:
|--|--|--main
|--|--|--|--java
|--|--|--|--jni
|--|--|--|--|--CMakeLists.txt
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--.so Files
|--|--|--|--|--armeabi-v7a
|--|--|--|--|--|--.so Files
|--|--|--|--|--x86
|--|--|--|--|--|--.so Files
You can then validate the resulting APK contains your .so files, typically under build/outputs/apk/, using unzip -l myApp.apk to list the contents.
Building shared libraries
If you're building a shared library in the NDK you do not need to do anything further. It will be correctly bundled in the APK.
Just add this lines to app build.gradle
dependencies {
...
compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
}
task nativeLibsToJar(type: Zip, description: 'create a jar archive of the native libs') {
destinationDir file("$buildDir/native-libs")
baseName 'native-libs'
extension 'jar'
from fileTree(dir: 'libs', include: '**/*.so')
into 'lib/armeabi/'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn(nativeLibsToJar)
}
now.I can load the so success!
1.add the .so file to this path
Project:
|--src
|--|--main
|--|--|--java
|--|--|--jniLibs
|--|--|--|--armeabi
|--|--|--|--|--.so files
2.add this code to gradle.build
android {
splits {
abi {
enable true
reset()
include 'x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a', 'armeabi'
universalApk false
}
}
}
3.System.loadLibrary("yousoname");
goodluck for you,it is ok with gradle 1.2.3
If your project exported from eclipse,add the codes below in gradle file:
android {
sourceSets{
main{
jniLibs.srcDir['libs']
}
}
}
2.If you create a project in Android studio:
create a folder named jniLibs in src/main/ ,and put your *.so files in the jniLibs folder.
And copy code as below in your gradle file :
android {
sourceSets{
main{
jniLibs.srcDir['jniLibs']
}
}
}
While I believe SJoshi (oracle guy) has the most complete answer, the SWIG project is a special case, interesting and useful one, at that, but not generalized for the majority of projects that have done well with the standard SDK ant based projects + NDK. We all would like to be using Android studio now most likely, or want a more CI friendly build toolchain for mobile, which gradle theoretically offers.
I've posted my approach, borrowed from somewhere (I found this on SO, but posted a gist for the app build.gradle: https://gist.github.com/truedat101/c45ff2b69e91d5c8e9c7962d4b96e841 ). In a nutshell, I recommend the following:
Don't upgrade your project to the latest gradle build
Use com.android.tools.build:gradle:1.5.0 in your Project root
Use com.android.application in your app project
Make sure gradle.properties has: android.useDeprecatedNdk=true (in case it's complaining)
Use the above approach to ensure that your hours and hours of effort creating Android.mk files won't be tossed away. You control which targets arch(s) to build. And these instructions are kind to Windows users, who should theoretically be able to build on windows without special issues.
Gradle for Android has been a mess in my opinion, much as I like the maven concepts borrowed and the opinionated structure of directories for a project. This NDK feature has been "coming soon" for almost 3+ years.

Categories

Resources