Site icon Experience, Digital Engineering and Data & Analytics Solutions by Apexon

Android development – Marrying Android with NDK Part2

Testing

We will now attempt to go through these steps. Assuming you already have environment ready to start Android and NDK development.

Create Android project

Create an Android project called “MyFirstJNI“, with package “com.example.myfirstjni“.

  To create new project, right click on File ->New -> Android Application Project. Give project name and select an API. Here in this case I have, Application Name as “My First JNI”, Project name as “MYFirstJNI” and package name “com.example.myfirstjni”.

Create java source

For this Paper, we will use simple c program – Palindrome Checker – that accepts string from user and returns boolean, True if string is Palindrome and False if string is not Palindrome.

We will start by defining C function prototype as Java methods(can be called as native methods wrapper). This class will be used to load library and expose native methods.

In this example we will create Java class JNIWrapper. This class will expose isPalindrome native method.

package com.example.myfirstjni;
public class JNIWrapper {
//Declare native method
private static native boolean isPalindrome(String inString);
// Provide additional functionality and call native method
public static boolean checkPalindrome(String inString){
return isPalindrome(inString);
}
// Load library
static {
System.loadLibrary("palindromeChecker");
}
}

 

Make JNI folder

Create a folder named “jni” in the Eclipse project’s root directory. (Right-click on the project -> New -> Folder). Create a subfolder “include” under “jni” for storing the header files.

Create C/C++ Header file using “javah”

Now, we will create header file using “javah” utility.

Open terminal(cmd in windows). Navigate to include folder that we created in last step.

$ javah -classpath ../../bin/classes/ -o Palindrome.h com.example.myfirstjni.JNIWrapper

Here,

  You need to use the fully-qualified class name (including package) and not the (.class) extension.

This will create header called “Palindrome.h” under include folder. Refresh your eclipse project.

Header file contains prototype function,

JNIEXPORT jboolean JNICALL Java_com_example_myfirstjni_JNIWrapper_isPalindrome (JNIEnv *, jclass, jstring);

The native method “isPalindrome(String inString)” mapped in the above header in the native code.

Write C code

Now, this is the time to implement functionality in C source.

Right-click on jni folder -> New -> File. Give name “Palindrome.c” to the file. This will create C source file called “Palindrome.c”.

#include <jni.h>
#include "include/Palindrome.h"
JNIEXPORT jboolean JNICALL Java_com_example_myfirstjni_JNIWrapper_isPalindrome
(JNIEnv *env, jclass this, jstring string){
const char *text = (*env)->GetStringUTFChars(env, string, 0);
int begin, middle, end, length = 0;
jboolean isPalindrome = JNI_FALSE;
while ( text[length] != '\0' )
length++;
end = length - 1;
middle = length/2;
for( begin = 0 ; begin < middle ; begin++ )
{
if ( text[begin] != text[end] )
{
isPalindrome = JNI_FALSE;
break;
}
end--;
}
if( begin == middle ){
isPalindrome = JNI_TRUE;
}
return isPalindrome;
}

This native code gets string and returns true if string is palindrome and false if string is not palindrome.

Create Android.mk

Create an Android makefile called “Android.mk” under “jni” directory. Right-click on “jni” folder -> New -> File and give name “Android.mk”. This file is used for Android build tools.

For our Paper, we will have following in our makefile.

# Defines the root to all other relative paths
# The macro function my-dir, provided by the build system, # specifies the path of the current directory (i.e. the
# directory containing the Android.mk file itself)
LOCAL_PATH := $(call my-dir)
# Clear all LOCAL_XXX variables with the exception of
# LOCAL_PATH (this is needed because all variables are global)
include $(CLEAR_VARS)
# List all of our C files to be compiled (header file
# dependencies are automatically computed)
LOCAL_SRC_FILES := Palindrome.c
# The name of our shared module (this name will be prepended by lib and postfixed by .so)
LOCAL_MODULE := palindromechecker
# Collects all LOCAL_XXX variables since "include $(CLEAR_VARS)" # anddetermineswhattobuild(in this case a shared library)
include $(BUILD_SHARED_LIBRARY)
  There are number of sample Android.mk files in the samples/ directory of the NDK. It’s easiest to copy the “Android.mk” file from another (sample) project.

Build NDK

Start terminal(CMD in windows), change directory to project root directory. Run “ndk-build” command.

  The command “ndk-build” comes from the NDK’s installation directory. So easiest way is to add this directory in PATH.
$ ndk-build
Compile thumb : palindromechecker <= Palindrome.c
SharedLibrary : libpalindromechecker.so
Install : libpalindromechecker.so => libs/armeabi/libpalindromechecker.so

Note: To remove generated libraries, run

$ ndk-build clean
Clean: palindromechecker [armeabi]
Clean: stdc++ [armeabi]

Run the android app

Refresh eclipse project and you will see library “libPalindromeChecker.so” is generated under libs->armeabi.

We are almost done with the native side of the code. Now, call “checkPalindrome(String inString)” method anywhere from your Android project. And it will call native method to return whether string is palindrome or not.

  Check logcat to confirm that the shared library “libpalindromechecker.so” is loaded.

Complexities integrating NDK

Conclusion

NDK integration can be painless if you follow all the steps carefully. However, using NDK as a solution is not always ideal. Before going down the path of using NDK, try to optimize the Java code to achieve the desired results. While using NDK, you need to weigh the benefits achieved against the complexities. By performing tests on your application, you can ascertain the gain that will be achieved by using NDK.

Some rules of thumb:

NDK should be used for:

NDK should not be used for:

None Edit Labels
Exit mobile version