My preferred API for cross-language integration is SWIG.
While there are many tutorials available to explain how to create an integrated Android Studio project that includes java and native C++, I struggled to find one that treated the two components separately.
Here is my solution.
Build The Library From The Sources
I used Window 10 as the main development environment and Android Studio for the main application building however I found that it was easier to build the library on the command line under Cygwin.
Install Android Studio from here : https://developer.android.com/studio/install.html
Install NDK, CMake and LLDB from within Android Studio using :
File | Settings | SDK Tools
Then tick the boxed and click OK
When you try to build a C program that includes header files such as stdio.h you will receive an error message along the lines of :
/home/John/Android/Sdk/ndk-bundle/sysroot/usr/include/linux/types.h:21:10: fatal error: 'asm/types.h' file not found
#include <asm/types.h>
^~~~~~~~~~~~~
1 error generated.
The solution is here : https://github.com/android-ndk/ndk/issues/510
Modify setup-toolchain.mk as follows :
--- a/build/core/setup-toolchain.mk
+++ b/build/core/setup-toolchain.mk
@@ -152 +152 @@
- -isystem $(SYSROOT_INC)/usr/include/$(header_triple_$(TARGET_ARCH))
+ -isystem $$(call host-path,$(SYSROOT_INC)/usr/include/$(header_triple_$(TARGET_ARCH)))
Open up a Cygwin command prompt and cd to the folder with the library source. Set the path environment variables to the tools :
export PATH=$PATH:/cygdrive/c/Users/John/AppData/Local/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64
export PATH=$PATH:/cygdrive/c/Users/John/AppData/Local/Android/Sdk/ndk-bundle/build
Build an application or library :
ndk-build NDK_PROJECT_PATH=$(pwd) APP_BUILD_SCRIPT=$(pwd)/Android.mk
That should generate the .so and all the necessary .java wrapper files.
Adding The Library To An Android Studio Project
For my project, I started with the simple GraphView (http://www.android-graphview.org/) application : described in this video https://www.youtube.com/watch?v=zbTvJZX0UDk. The source code is available here : https://github.com/mitchtabian/CreateSimpleGraphView. Thanks Mitch for the great tutorial.
Added to app/build.gradle
sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
jniLibs.srcDir 'siglib_wrap' // Import precompiled libraries in your project.
}
copy full SWIG installation, from above, to : project/app/src/main/java/com/numerix_dsp/siglib_wrap
copy .so to : project/app/src/main/jniLibs
References
[1] The Main Reference : http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/
[2] SWIG Android : http://orx-project.org/wiki/en/tutorials/community/enobayram/swig_android
[3] SWIG Wrapping : https://stackoverflow.com/questions/30110579/how-do-i-wrap-an-existing-c-library-for-use-with-android-studio-with-swig-give
[4] JNI : https://stackoverflow.com/questions/21096819/jni-and-gradle-in-android-studio/26693354#26693354
[5] SWIG : http://www.swig.org/Doc3.0/
http://www.swig.org/Doc3.0/Android.html
http://www.swig.org/Doc3.0/Java.html
[6] Android Libraries : https://developer.android.com/studio/projects/android-library.html
[7] Android C/C++ : https://developer.android.com/studio/projects/add-native-code.html
[8] Compiling Libraries For Android : https://tariqzubairy.wordpress.com/2012/03/09/arm-binaries-static-library-for-android/
Application Source Code
package com.numerix_dsp.siglib_graph;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import siglib_wrap.siglib_wrap;
import siglib_wrap.siglib_wrapJNI;
import siglib_wrap.SLSignal_t;
import siglib_wrap.SLSignalFillMode_t;
import siglib_wrap.SWIGTYPE_p_double;
public class SigLib_Graph extends AppCompatActivity {
private siglib_wrap mSigLib;
static {
try {
System.loadLibrary("siglib_wrap");
} catch (UnsatisfiedLinkError e) {
System.err.println("siglib_wrap library failed to load.\n" + e);
System.exit(1);
}
}
int SAMPLE_LENGTH = 512;
LineGraphSeries<DataPoint> series;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sig_lib__graph);
mSigLib = new siglib_wrap();
SWIGTYPE_p_double SinePhase = mSigLib.new_doubleArray(1);
mSigLib.doubleArray_setitem(SinePhase, 0, 0.0);
SWIGTYPE_p_double timeArray = mSigLib.new_doubleArray(SAMPLE_LENGTH);
SWIGTYPE_p_double nullArray = mSigLib.new_doubleArray(1);
mSigLib.SDA_SignalGenerate (timeArray, // Output array pointer
SLSignal_t.SIGLIB_SINE_WAVE, // Signal type - Sine wave
siglib_wrapJNI.SIGLIB_ONE_get(), // Signal peak level
SLSignalFillMode_t.SIGLIB_FILL, // Fill (overwrite) or add to existing array contents
0.015, // Signal frequency
siglib_wrapJNI.SIGLIB_ZERO_get(), // D.C. Offset
siglib_wrapJNI.SIGLIB_ZERO_get(), // Unused
siglib_wrapJNI.SIGLIB_ZERO_get(), // Signal end value - Unused
SinePhase, // Signal phase - maintained across array boundaries
nullArray, // Unused
SAMPLE_LENGTH); // Output dataset length
GraphView graph = (GraphView) findViewById(R.id.graph1);
series = new LineGraphSeries<DataPoint>();
for(int i =0; i<SAMPLE_LENGTH; i++) {
series.appendData(new DataPoint((double)i, siglib_wrap.doubleArray_getitem(timeArray, i)), true, SAMPLE_LENGTH);
}
graph.addSeries(series);
}
}
The full Android Studio project can be downloaded as part of the SigLib evaluation package, from here : http://www.numerix-dsp.com/eval/
Evaluate The Numerix-DSP Libraries : http://www.numerix-dsp.com/eval/
Copyright © 2018 Delta Numerix