Wednesday, May 07, 2014

How to JNI with ADT Eclipse Android Development Toolchain

Get the toolchain:
- download ADT: e.g.: adt-bundle-linux-x86-20140321.zip
- download NDK e.g.: android-ndk-r9d-linux-x86.tar.bz2

unzip adt-bundle-linux-x86-20140321.zip
tar -xjf android-ndk-r9d-linux-x86.tar.bz2

this will create two directories:
- adt-bundle-linux-x86-20140321
- android-ndk-r9d


run eclipse:
cd adt-bundle-linux-x86-20140321/eclipse
eclipse

Configure Eclipse:
in menu: Window>Preferences
then select: Android>NDK
there you'll give the location to: fiull/path/to/android-ndk-r9d

Create an empty new project:
File>New>Project...
Android>Android Application Project

Application Name: test2
NEXT
NEXT
NEXT
Blank Activity, then NEXT
FINISH

Add support for NDK to this app:
right click on application name in project explorer "test2".
Android Tools>Add Native Support...

Keep proposed library Name: test2
Finish

two files have been created in the subfolder jni:
- test2.cpp
- Android.mk

Write the C code:
In project explorer: open jni/test2.cpp

it already contains
#include


write the following code in jni/test2.cpp:
extern "C"
{
JNIEXPORT int JNICALL Java_com_example_test2_Test2Wrapper_myfunc
      (JNIEnv * je, jobject jobj)
    {
            return (3);
    }
}

The function name must be composed as follow:
- Java_
- package name (here com.example.test2) with dots replaced by underscores
- your class name that will receive the native code (here Test2Wrapper)
- the function name (here myfunc)

The function type here is int and it returns the value 3.
The function receive two obligaroty parameters:
JNIEnv * je, jobject jobj

To have more parameters, add them after those two, like this e.g. with two integers p1 and p2:
JNIEXPORT int JNICALL Java_com_example_test2_Test2Wrapper_myfunc
      (JNIEnv * je, jobject jobj, jint p1, jint p2)

Write makefile:
Android.mk is the makefile.
It is already written, so here, for the moment, nothing more to do ;-).
It should look like:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := test2
LOCAL_SRC_FILES := test2.cpp
include $(BUILD_SHARED_LIBRARY)


LOCAL_MODULEis given the name of the compiled library.
LOCAL_SRC_FILES is given a list of c or c++ files to be compiled.

write the Java wrapper:
For each function of the library you want to call from Java, you need to implement a native method of a wrapper class.
In our example we want to name the wrapper class: Test2Wrapper

In project explorer, open: src/com.example.test2
In this directory you have the MainActivity.java file.
Right click on  com.example.test2
new>Class
Name:  Test2Wrapper
FINISH

Modify the code as follow:
package com.example.test2;
public class Test2Wrapper {
    static {
        System.loadLibrary("test2");
    }
    public static native int func();

}







System.loadLibrary is given the name of the library compiled by Android.mk i.e. the one given to LOCAL_MODULE, here test2.


Call and use the wrapper:
Open the file: MainActivity.java
Modify the onCreate method as follow:
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment()).commit();
        }

        // 2 lines added first to call the native function
        // then to display a message box with "3" written inside.
        String hello = Integer.toString(Test2Wrapper.func());
        new AlertDialog.Builder(this).setMessage(hello).show();

    }


Build and run the project:
Save all files. This should lead eclipse to compile automatically the files.
Right click on project name.
Run As>Android Application

That's all, folks!

0 Comments:

Post a Comment

<< Home