I am trying to add the VTK to my native Android project in AS 3.3. I have installed the NDK r17c. I would like to use some of the VTK functionalities in my native application. Also, I am using gradle 3.3.2 for building my android project and CMake 3.6.4 for building native side of the project. My problem is that I haven't found a suitable tutorial (I am new to Android native development) for importing the VTK into the Android Studio using all building tools that I have described. Is there a way to do that?
Also, I would like to add that I am using Windows 7 OS.
EDIT: I had updated my CMakeLists.txt file with some lines I had found relevant in the official example (https://github.com/Kitware/VTK/tree/master/Examples/Android). I would like to use VTK inside my native-lib library:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
link_directories(src/main/jni/japi src/main/jni/acquisition)
file(GLOB native_SRC
"src/main/jni/japi/*.h"
"src/main/jni/japi/*.cpp"
)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
${native_SRC})
file(GLOB acquisition_SRC
"src/main/jni/acquisition/*.h"
"src/main/jni/acquisition/*.cpp"
)
#file(GLOB acquisition_SRC
# "src/main/jni/acquisition/*.h"
# )
add_library( acquisition-lib STATIC ${acquisition_SRC})
#add_library(
# acquisition-lib
#
# STATIC
#
# src/main/jni/acquisition/test-lib.h
# src/main/jni/acquisition/test-lib.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
target_link_libraries( native-lib acquisition-lib )
set(OpenCV_DIR "../opencv/src/sdk/native/jni")
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV libraries: ${OpenCV_LIBS}")
target_link_libraries(native-lib ${OpenCV_LIBS})
target_link_libraries(acquisition-lib ${OpenCV_LIBS})
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libippicv.a -Wl,--exclude-libs,libippiw.a")
##ADDED for including the VTK
find_package(VTK COMPONENTS
vtkInteractionStyle
vtkRenderingOpenGL2
vtkRenderingFreeType
vtkTestingCore
vtkTestingRendering
)
include(${VTK_USE_FILE})
target_link_libraries( native-lib ${VTK_LIBRARIES} )
Ok, it took me about a week to get this working, but it paid off. I will list all the things I needed to do to be able to use VTK in my android application.
STEP 1: Building VTK on Linux machine
Because Android is based on the Linux OS, you need to build libraries in .a or .so format. To do this, the easiest thing to do is to build VTK on Linux machine. So you have to install Linux to your machine eather as dual boot or, as in my case, install a virtual machine that runs Linux.
After that, you need to install all the thing needed to download and build VTK for Android. Here is the list of the things you need to download and install to your Linux machine:
Download and install the Android NDK- I downloaded the same version that I am using in my Android Studio - r17c
Download and install the Android SDK , i.e. Android Studio
Download and install ANT
Download and install Java
Download and install CMake - also after I installed it, I needed to run: sudo apt-get update && sudo apt-get install build-essential
Download and install Git
Install OpenGL - I used: sudo apt-get install freeglut3-dev
Define ANDROID_NDK environment variable - point it to unzipped android NDK folder
Define ANT_HOME environment variable - point it to unzipped ANT folder
Define JAVA_HOME environment variable - point it to unzipped Java JRE folder
Define ANDROID_SDK environment variable - point it to the location of Android/Sdk folder
Define CMAKE_HOME environment variable - point it to the location of your installed CMake
Add to PATH enviroment variable: ANT_HOME/bin, JAVA_HOME/bin, ANDROID_SDK/platform-tools, ANDROID_SDK/tools, CMAKE_HOME/bin
After the installation of the all the needed tools above, you need to download the VTK source code using git:
Create an 'vtk' folder somewhere
cd vtk
git clone https://github.com/Kitware/VTK.git
Now, you can go and build the VTK:
mkdir vtk/vtk-android
cd vtk-android
ccmake ../VTK
press c (configure)
press c (configure)
press q (quit)
cmake -DVTK_ANDROID_BUILD=ON -DANDROID_NATIVE_API_LEVEL=23 -DANDROID_ARCH_ABI=arm64-v8a ../VTK - here I defined the 23 api level because that is what I am using in my applicatin. Also, here is where you define the architecture ABI of your targeted devices. My device is arm64-v8a so I am using that. In order to build VTK for other architectures, you will need to build for every each one of them. Also, you can edit this in the next step!
ccmake ../VTK
OPTIONAL: at this point, you can define additional modules you need in your application. If you just skip this step, the modules (.a files) you will get are:
vtkCommonColor, vtkCommonComputationalGeometry, vtkCommonCore,
vtkCommonDataModel, vtkCommonExecutionModel, vtkCommonMath, vtkCommonMisc,
vtkCommonSystem, vtkCommonTransforms, vtkDICOMParser, vtkdoubleconversion,
vtkexpat, vtkFiltersCore, vtkFiltersExtraction, vtkFiltersGeneral,
vtkFiltersGeometry, vtkFiltersHybrid, vtkFiltersModeling, vtkFiltersSources,
vtkFiltersStatistics, vtkfreetype, vtkglew, vtkImagingCore,
vtkImagingFourier, vtkImagingMath, vtkImagingSources, vtkInfovisCore,
vtkInteractionStyle, vtkIOCore vtkIOGeometry, vtkIOImage, vtkIOInfovis,
vtkIOLegacy, vtkIOPLY, vtkIOXML, vtkIOXMLParser, vtkjpeg, vtkjsoncpp,
vtklibxml2, vtklz4, vtklzma, vtkmetaio, vtkParallelCore, vtkpng,
vtkRenderingCore, vtkRenderingFreeType, vtkRenderingOpenGL2,
vtkRenderingVolume, vtkRenderingVolumeOpenGL2, vtksys, vtkTestingRendering,
vtktiff, vtkWrappingTools, vtkzlib
If these modules are not sufficient for you, you need to add some lines to VTK/CMake/vtkAndroid.cmake file because there the build for android is defined. Lines you add must look like:
-DVTK_MODULE_ENABLE_VTK_[name-of-the-module]:STRING=YES
You can find out all possible name-of-the-module values if you press t (toggle) and scroll to VTK_MODULE_ENABLE_VTK_... part of the configuration.
c (configue)
g (generate)
make
Ok, so the build process starts. On my laptop it took ~30mins (I assigned 3GB of RAM to the virtual machine).
STEP 2 : Importing the VTK to the Android Studio
After the build process is finished, you need to copy the folder vtk/vtk-android/CMakeExternals/Install/vtk-android to the your Windows machine.
The folder lib contains the build VTK library as a set of static libraries (.a files), and the folder include contains all the header files of the VTK you neeed to get the VTK working in full.
Now, in your Android Studio project, create a new Android Library module called vtk.
Create the src/main/jni folder and inside that folder copy the lib and include folder described above.
In jni folder crate an vtk-lib.cpp file which will serve as an interface from your Java code to the VTK library. An example may be:
#include <jni.h>
#include <vtkConeSource.h>
extern "C"
JNIEXPORT void JNICALL
Java_link_to_your_java_function(
JNIEnv *env,
jobject /*this*/) {
vtkConeSource *cone = vtkConeSource::New();
cone->SetHeight(3.0);
cone->Delete();
}
In the build.gradle file of your vtk module, add this lines:
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_CPP_FEATURES=rtti exceptions",
"-DANDROID_STL=gnustl_shared"
abiFilters 'arm64-v8a'
}
}
}
...
externalNativeBuild {
cmake {
path "src/main/jni/CMakeLists.txt"
}
}
}
After that, to the jni folder add a CMakeLists.txt file which will be used for building the module:
cmake_minimum_required(VERSION 3.4.1)
set(LIB_DIR ${PROJECT_SOURCE_DIR}/lib/${ANDROID_ABI})
add_library(vtk-common-color STATIC IMPORTED)
set_target_properties(vtk-common-color
PROPERTIES IMPORTED_LOCATION
${LIB_DIR}/libvtkCommonColor-8.90.a)
#53 more libraries from lib folder
add_library( vtk-lib SHARED ${PROJECT_SOURCE_DIR}/vtk-lib.cpp)
target_include_directories(vtk-lib PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(
vtk-lib
-Wl,--start-group -L ${TARGET_OUT}
vtk-common-color
#53 more libraries names
-Wl,--end-group
)
And that's it, voila!
You can
start with the official example on GitHub:
NativeVTK is built around the
Android native interface and does not have any Java code associated with it.
Any unser interface elements would need to be created in C++ using regular
VTK widgets or other OpenGL elements. This is best for applications that
are mainly focused on rendering or visualization with very minimal user
interface. In this example all the key code is in jni/main.cxx and it will
look very much like the regular VTK code you are used to.
It doesn't use Android Studio, and for good! Loading huge amounts of 3rd party native code into Android Studio is both useless and frustrating. It is much better to have such libraries compiled with their native build tools, and only import small modules that require lots of changes and/or interactive debugging.
I have an Android project with a app/src/CMakeLists.txt file like this
cmake_minimum_required(VERSION 3.4.1)
add_library( # Specifies the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
main/cpp/native-lib.cpp )
I also have a app/src/main/cpp/native-lib.cpp file in my project.
When I run ninja in a terminal I get this error
ninja: error: loading 'build.ninja': No such file or directory
I'm not familiar with the NDK and I'm trying to run the project with ninja but I'm not able to find any clear documentation or example.
Android NDK uses CMake to build projects, but instead of run ninja separately, you should run below gradle command to trigger your NDK project build.
./gradlew externalNativeBuild
Internally, CMake will use the ninja build system to compile and link the C/C++ sources for your apps.
I am trying to integrate the Hyperledger indy SDK. However, when running my code I get the error
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.UnsatisfiedLinkError: dlopen failed: library "libgnustl_shared.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1657)
I am trying to follow the documentation provided in the project repo. I tried using the sample project on this blog .
I was able to build the *.so libraries under a linux virtual machine, the copied the built files in my android studio project on windows.
I added the files inside my project's jniLibs forlder for each architecture.
Added the code to load the library inside my mainActivity
static{
System.loadLibrary("indy");
}
Tried creating a CMake file
cmake_minimum_required(VERSION 3.4.1)
add_library(indy SHARED IMPORTED)
include_directories(src/main/jniLibs/${ANDROID_ABI}/include)
My gradle file includes:
android{
defaultconfig{
...
ndk{
moduleName "indy"
abiFilters 'armeabi-v7a'
}
}
...
sourceSets {
main {
jniLibs.srcDir 'src/main/jniLibs'
}
}
externalNativeBuild {
cmake {
path file('../CMakeLists.txt')
}
}
}
Still, keep on getting the same error when I launch the app.
I am aware that the bash script that builds the libraries on linux uses the android-ndk-r16b-linux-x86_64 tools so I tried downgrading my ndk in android studio to use the same version but had no luck.
The output of the build script is
include/
indy_anoncreds.h
indy_core.h
...
lib/
libindy.a
libindy.so
libindy_shared.so
How can I use this libraries in my android studio project?
The issue is mainly related to the nature of libraries. Libraries are dynamic in Android and needs to be linked at runtime.
libindy.so depends on stl, openssl, libsodium and libzmq.
You will find libgnustl_shared.so in NDK.
All the other needed prebuilt libraries are also available here.
What you need to do is make sure these libraries are present in the jniLibs folder and load these in order libraries before libindy.
System.loadLibrary("libgnustl_shared");
.
.
System.loadLibrary("indy");
Alternate approach:
There is a subproject in Indy where we are using libindy as dependency and we try to create a one fat dynamic library which has all the dependencies.
Link
If you follow the steps like vcx you dont have to have all the defendant l libraries in jniLibs as they will be already part of final .so file
The command which make one fat dynamic library with all the symbols and dependencies is this (from the link pasted above)
${LIBVCX}/target/${CROSS_COMPILE}/release/libvcx.a \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libz.so \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libm.a \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/liblog.so \
${LIBINDY_DIR}/libindy.a \
${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so \
${OPENSSL_DIR}/lib/libssl.a \
${OPENSSL_DIR}/lib/libcrypto.a \
${SODIUM_LIB_DIR}/libsodium.a \
${LIBZMQ_LIB_DIR}/libzmq.a \
${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so -Wl,--no-whole-archive -z muldefs
I'm trying to get C++ code to work with react-native (see this for the general steps).
I've generated my project with react-native init, generated the JNI bindings by using Djinni. I'm now trying to build the application and test it on my android emulator (cd $PROJECT_ROOT/android && ./gradlew installDebug). It seems like the header files aren't found, their directories aren't included :
> ./gradlew installDebug
(...)
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugNdk
Warning: Deprecated NDK integration enabled by useDeprecatedNdk flag in gradle.properties will be removed from Android Gradle plugin soon.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental.
In file included from $PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.cpp:4:
$PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.hpp:6:10: fatal error: 'cpp_bridge_text.hpp' file not found
#include "cpp_bridge_text.hpp"
^~~~~~~~~~~~~~~~~~~~~
1 error generated.
make: *** [$PROJECT_ROOT/android/app/build/intermediates/ndk/debug/obj/local/armeabi-v7a/objs/app/$PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.o] Error 1
:app:compileDebugNdk FAILED
FAILURE: Build failed with an exception.
I managed to get past this small issue by creating hard links to the headers causing issues. Which leads me to this :
> ./gradlew installDebug
(...)
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugNdk
Warning: Deprecated NDK integration enabled by useDeprecatedNdk flag in gradle.properties will be removed from Android Gradle plugin soon.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental.
In file included from $PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.cpp:4:
In file included from $PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.hpp:7:
$PROJECT_ROOT/app/src/main/jni/djinni_support.hpp:20:10: fatal error: 'exception' file not found
#include <exception>
^~~~~~~~~~~
1 error generated.
make: *** [$PROJECT_ROOT/android/app/build/intermediates/ndk/debug/obj/local/armeabi-v7a/objs/app/$PROJECT_ROOT/android/app/src/main/jni/NativeCppBridgeText.o] Error 1
:app:compileDebugNdk FAILED
FAILURE: Build failed with an exception.
In this case, it seems like even standard libraries aren't included.
My question is : how do I explicitly specify gradle to add directories to its search/indlude path?
In regular Android projects, it seems that you can edit Android.mk/Application.mk files. There aren't such files in my folders ; I think that gradle actually generates an Android.mk file (in $PROJECT_ROOT/android/app/build/intermediates/ndk/debug/Android.mk), I tried editing it (LOCAL_C_INCLUDES field) to add my directories, but it gets overwritten when I try another build.
Thanks in advance.
You can edit this in $PROJECTROOT/android/app/build.gradle :
android {
defaultConfig {
(...)
ndk {
(...)
cFlags = "-Ipath/to/directory/"
}
}
}
However, you will most likely encounter other issues (I know that for a fact, because I did). I'd recommend you to use the modern and user-friendly CMake integration.
I'm gonna write down the general steps so that I can find it again sometime in the future :
Add your files to the android project (under android studio or another IDE). There should be files in your java/ folder, files in your jni/ folder (JNI bridge files), and files in your cpp/ folder (the native C++).
Add a CMakeLists.txt file to your module (usually named app if you're using react-native).
In this file, respect the following structure :
cmake_minimum_required(VERSION 3.4.1)
add_library( # Name of the library
$(YOUR_LIBRARY_NAME)
# Sets it as a shared library
SHARED
# Relative path to the source file(s)
path/to/your/file.cpp path/to/other/file.cpp )
# Allows you to add folders to the search path : similar to -Ipath/to/your/headerfolder/
include_directories(path/to/your/headerfolder/)
# Allows you to have special compilation flags for the specified library's compilation
target_compile_options( $(YOUR_LIBRARY_NAME)
PRIVATE # You can also use PUBLIC/INTERFACE
-std=gnu++11 ) # Your option ; I needed this in my case
Once it's done, you need to link gradle to your native library :
If you're using android studio, just use the information available in this guide as it's very well explained.
If you aren't, I also advise you to check out this guide, because it's really well explained.
After that, you can either build the project in android studio, or cd $(PROJECTROOT)/android && ./gradlew installDebug. It should work.
Good luck!
I'm trying to add another cmake project which has CMakeLists.txt file as a compilation dependency which i can use in another .cpp file.
Location of project which i want to add: Users/brainfreak/Downloads/assimp-master/
Location of main project: /Users/brainfreak/AndroidStudioProjects/ModelShow/app/src/main/cpp/hellojni.cpp
This is used as a native code in a Android Studio project. I followed the tutorial in https://developer.android.com/studio/projects/add-native-code.html#create-cmake-script under "Include other CMake projects"
This is the main CMakeLists.txt that i came up with:
/Users/brainfreak/AndroidStudioProjects/ModelShow/app/src/main/cpp/CMakeLists.txt
cmake_minimum_required( VERSION 2.6 )
add_library(model-lib SHARED hellojni.cpp)
set (src_dir Users/brainfreak/Downloads/assimp-master/)
set (output_dir Users/brainfreak/Downloads/assimp-master/output)
file(MAKE_DIRECTORY ${output_dir})
add_subdirectory(${src_dir} ${output_dir})
add_library(assimp STATIC IMPORTED)
set_target_properties( assimp PROPERTIES IMPORTED_LOCATION
${output_dir}/${ANDROID_ABI}/assimp)
include_directories(${src_dir}/include)
target_link_libraries(model-lib assimp)
The error i always get:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing process /Users/brainfreak/Android/sdk/cmake/3.6.3155560/bin/cmake with arguments {--build /Users/brainfreak/AndroidStudioProjects/ModelShow/app/.externalNativeBuild/cmake/debug/x86 --target model-lib}
ninja: error: 'Users/brainfreak/Downloads/assimp-master/output/x86/assimp', needed by '/Users/brainfreak/AndroidStudioProjects/ModelShow/app/build/intermediates/cmake/debug/obj/x86/libmodel-lib.so', missing and no known rule to make it
I don't know what file to place under "${output_dir}/${ANDROID_ABI}/" for the script to find. Can you tell where i'm going wrong?
Assuming that you got one of the latest releases from https://github.com/assimp and followed the instructions (note that this was tested with NDK r14, available for download from https://developer.android.com/ndk/downloads/older_releases), you have produced file libassimp.so inside project "Code" folder. Make sure that you build the x86 version of the library.
Copy this file to /Users/brainfreak/Downloads/assimp-master/output/x86/, and prepare your CMakeLists.txt:
cmake_minimum_required( VERSION 2.6 )
add_library(model-lib SHARED hellojni.cpp)
set (src_dir /Users/brainfreak/Downloads/assimp-master/)
set (output_dir /Users/brainfreak/Downloads/assimp-master/output)
file(MAKE_DIRECTORY ${output_dir})
add_subdirectory(${src_dir} ${output_dir})
add_library(assimp STATIC IMPORTED)
set_target_properties( assimp PROPERTIES IMPORTED_LOCATION
${output_dir}/${ANDROID_ABI}/libassimp.so)
include_directories(${src_dir}/include)
target_link_libraries(model-lib assimp)
Note that the file that your script was missing slash (/) before Users which could cause the confusion.
Don't forget to set abiFilters in your app/build.gradle:
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'x86'
}