Getting Started with Android Native JNI programming

Source: Internet
Author: User

In some cases, Java programming has not been able to meet our needs, such as a complex algorithm processing, it is necessary to use the JNI (Java Native Interface) technology;

    • JNI is actually a Java and c/cpp communication between the interface specification, Java can call C/cpp inside the function, similarly, c/cpp can also call Java class method;

Installation of the JNI development tool NDK:
In the latest NDK version, installing the NDK is simple and requires only the path of the NDK to be configured in the system environment variable;
At compile time, enter the project root directory, execute the command ndk-build to complete the compilation;

The following is an example of the first step-by-step study of JNI

First, HelloWorld

Create a new project, you do not even need additional settings, and then add a JNI directory to the project, and then you can start;

1. Create a new Java class Helloworld.java

Package Com.jni;public class HelloWorld {    static {        system.loadlibrary ("HelloWorld");    }    Public native String HelloWorld ();}

In HelloWorld, a method HelloWorld () is defined, but this method is declared to be native, and there is no specific implementation, and the specific function we implement in the following CPP file;

2. Add a helloworld.cpp under the JNI directory

#include <jni.h> #include <android/log.h> #include <string.h> #ifndef _included_com_jni_helloworld/ /1#define _included_com_jni_helloworld#ifdef __cplusplus//2extern "C" {#endif//2JNIEXPORT jstring Jnicall Java_com_jn I_helloworld_helloworld (jnienv *, jobject), #ifdef __cplusplus//3} #endif//3#ENDIF//1JNIEXPORT jstring Jnicall Java_co M_jni_helloworld_helloworld (JNIENV * env,        jobject obj) {    return Env->newstringutf ("HelloWorld");}

From the CPP file above can be clearly seen, it has a method, including the method declaration and method implementation of two parts; but I believe everyone can see that the command of the method is very strange, how so long method name?

Let's consider a question here, how does a method in a Java class invoke a method in C + +? To solve this problem, we must first look at this long method name;

In fact, this is one of the specifications of the JNI, used to map the Java method and the method in C/s;

Then look at the function name defined in the CPP: Java_com_jni_helloworld_helloworld

In fact, it is not difficult to see that the Java file and CPP file matching function name is defined as Java + package name + Java class name + method/function name, in the middle with _ delimited; Two of the parameters are:

      • ENV: The contents of the current thread, containing all the contents of the thread;
      • Obj: an instance of the current class that refers to the contents of a. java file (in this case, the HelloWorld class);

Here the HelloWorld method, in fact, just returned a word "HelloWorld";

3. Add a android.mk file under the JNI directory

Local_path: = $ (call My-dir) include $ (clear_vars) local_module    : = helloworldlocal_src_files: = Helloworld.cppinclude $ (build_shared_library)

4. Under the command line into the engineering directory to execute the ndk-build command, and then run the program, call the HelloWorld instance HelloWorld method can get its return string;

Second, JNI calls the Java class method (1)

With the above HelloWorld practiced hand, let's take a look at the implementation of the method that JNI calls the Java class;

1. The new construction of a Methodcall.java file is as follows

public class Methodcall {    final String tag = "Methodcall";    static {        system.loadlibrary ("Methodcall");    }    Public native String jniCallMethod1 ();    Public native String jniCallMethod2 ();    Public native String Jnicallstaticmethod ();    public void JavaMethod1 () {        LOG.E (tag, "javaMethod1");    }    Public String javaMethod2 () {        LOG.E (tag, "javaMethod2");        return "JAVAMETHOD2";    }    public static void Javastaticmethod (String input) {        log.e ("Methodcall", "" + input);}    }

The class has 6 methods, of which 3 are Java class methods, the other 3 is the native method, 3 native methods to call 3 Java methods respectively;

2. Add three native methods to implement Methodcall.cpp

#include <jni.h> #include <android/log.h> #include <string.h> #ifndef _included_com_jni_methodcall# Define _included_com_jni_methodcall#ifdef __cplusplusextern "C" {#endifJNIEXPORT jstring jnicall java_com_jni_ METHODCALL_JNICALLMETHOD1 (jnienv *, jobject); Jniexport jstring jnicall java_com_jni_methodcall_jnicallmethod2 (jnienv *, jobject); Jniexport jstring jnicall Java_com_jni_methodcall_jnicallstaticmethod (jnienv *, jobject); #ifdef __cplusplus} #endif # Endifjniexport jstring jnicall java_com_jni_methodcall_jnicallmethod1 (jnienv * env, Jobject obj) {JmethodID mid ; Method Identification ID Jclass CLS = env->getobjectclass (obj);    object instance of class mid = Env->getmethodid (CLS, "JavaMethod1", "() V");    Env->callvoidmethod (obj, mid); Return Env->newstringutf ("JniCallMethod1");} Jniexport jstring jnicall java_com_jni_methodcall_jnicallmethod2 (jnienv * env, Jobject obj) {jmethodid mid;// Method Identification ID Jclass CLS = env->getobjectclass (obj); ClassThe object instance of mid = Env->getmethodid (CLS, "JavaMethod2", "() ljava/lang/string;");    Jstring js = (jstring) env->callobjectmethod (obj, mid); Return JS;} Jniexport jstring jnicall Java_com_jni_methodcall_jnicallstaticmethod (jnienv * env, Jobject obj) {jmethodID mi D Method Identification ID Jclass CLS = env->getobjectclass (obj);    object instance of class mid = Env->getstaticmethodid (CLS, "Javastaticmethod", "(ljava/lang/string;) V");    jstring input = Env->newstringutf ("Jnicallstaticmethod->>javastaticmethod");    Env->callstaticvoidmethod (CLS, Mid, input); Return Env->newstringutf ("Jnicallstaticmethod");}

There are 3 methods in the CPP file (I wrote the method names very clearly and intuitively, I believe that no annotations are needed to know which Java method to call)

We know that in Java programming, the call to a class is to create an object instance of a class first, and then call its method (this refers to the non-static method), then how do we call the Java method in C + + files?

Back to the above HelloWorld, when we say the method name, the following is a random reference to the parameters of the method, where the second parameter obj is actually we use in Java instance of the class, here, I believe is how to call the Java method of everyone understand it;

In Java, each method actually has an ID, we can not directly call a Java method through obj in C + +, we have to get the ID of the method, obtained by Getmethodid (), need to pass in the class type, method name, method signature ( The method signature will refer to the signature rules later in the article, and then the Java method is called in the thread, via Env->call****method (), passing in the object instance, method ID, or other parameters; (only a few of these methods are shown above. Other methods if you need to use to find data to solve the problem;

3. Write the Android.mk file and add the following after the Android.mk file

Include $ (clear_vars) local_module    : = methodcalllocal_src_files: = Methodcall.cppinclude $ (build_shared_library)

4. Execute the ndk-build command, the following is the result of executing 3 jnicall**** methods respectively

Third, jni method of calling Java Class (1)

Above is an example of C + + calling Java method, and then a C call Java Method Example

1.Java file Methodcall1.java

Package Com.jni;public class MethodCall1 {    static {        system.loadlibrary ("Methodcall1");    }    public static int value = 0;    public static void Javamethod () {        value = n;    }    public native int Jnicalljavamethod ();}

2.methodcall.c

#include <string.h> #include <jni.h>jint java_com_jni_methodcall1_jnicalljavamethod (jnienv* env, Jobject Thiz)//env: The contents of the current thread, containing all the threads of the thread; Thiz: an instance of the current class, referring to the contents of the. java file {    jint si;    Jfieldid FID; A field that actually corresponds to a field or property inside a Java class;    Jclass cls = (*env)->getobjectclass (env, thiz); The object instance of the class    jmethodid mid = (*env)->getstaticmethodid (env, CLS, "Javamethod", "() V");//The ID of a method    //(i) v  (i ) I    if (mid = = NULL) {        return-1;    }    (*env)->callstaticvoidmethod (env, CLS, mid); Call the callback method    FID = (*env)->getstaticfieldid (env, CLS, "value", "I");//Remove the Value field    if (fid = = NULL) {        return-2;    }    Si = (*env)->getstaticintfield (env, CLS, FID); Take out the value corresponding to the field (the value of the FID field)    return si;    return (*env)->newstringutf (env, "init success");}

3. Perfect Android.mk file, refer to two inside the fourth step;

4. Run the Code

MethodCall1 MC1 = new MethodCall1 (); LOG.E (tag, methodcall1.value + "+" + mc1.jnicalljavamethod ());

Iv. method Signature Rules

JNI type Signature Rules
Java type Type signature Java type Type signature
Boolean Z Long J
Byte B Float F
Char C Double D
Short S Class L fully qualified class name;
Int I Array [Element type signature

The above are the signature characters for various data types

    • The signature of the basic data type is simple, just a selected letter;
    • The signature rule for a class is: "L" + Fully qualified class name + ";" Three parts, of which the fully qualified class name is separated by "/";

Signature of the method: "(parameter signature)" + "return value signature"

For example Java method long Fun (int n, String str, int[] arr);
According to the above signature rules can get its signature as: (iljava/lang/string;[ I) J
The above signature is divided into two parts: inside the parentheses are the parameters of the function, the contents of the parameters are divided into three parts "I", "ljava/lang/string;", "[i", there is no space between them; the return type signature of the function is outside the parentheses. It is important to note that if the function return type is void, the return type is signed as V;

Five, dynamic registration function

The previous two and San du are the names of the methods in C/s + + to map functions, in fact, JNI also provides us with the function of dynamic registration function;

1. Adding Java files Dynamicregistermethod.java

Package Com.jni;public class Dynamicregistermethod {    static {        system.loadlibrary ("Dynamicregistermethod");    } Public    native String Dynamicregistermethod ();}

2. Add a C file

#include <string.h> #include <jni.h> #ifndef _included_org_spring_springutils#define _included_org_ Spring_springutilsjstring jnicall Java_dynamicregistermethod (jnienv * env, Jobject obj) {return (*env)->NewStringUT F (env, "Dynamicregistermethod");} Static Jninativemethod gmethods[] = {{"Dynamicregistermethod", "() ljava/lang/string;", (void*) java_dynamicregist Ermethod}};static int Registernativemethods (JNIENV * env, const char* className, jninativemethod* gmethods, int n    Ummethods) {Jclass clazz;    Clazz = (*env)->findclass (env, className);    if (clazz = = NULL) return jni_false;    if ((*env)->registernatives (env, Clazz, Gmethods, Nummethods) < 0) {return jni_false; } return jni_true;}            static int registernatives (jnienv* env) {if (!registernativemethods (env, "Com/jni/dynamicregistermethod", Gmethods,    sizeof (Gmethods)/sizeof (Gmethods[0])) {return jni_false; } return jni_true;} Jint jni_onlOad (javavm* vm, void* reserved) {jint result =-1;    jnienv* env = NULL;    if ((*VM)->getenv (VM, (void * *) &env, jni_version_1_4)) {goto fail;    } if (registernatives (env) = Jni_true) {goto fail;    } result = Jni_version_1_4; Fail:return result;} #endif

3. Configure the compilation in the Android.mk file (omit, refer to the previous example)

4.ndk-build Compiling a project

Dynamicregistermethod DRM = new Dynamicregistermethod (); LOG.E (tag, Drm.dynamicregistermethod ());

Execution Result:

Can see through the dynamic registration method, but also a successful call to the native method;

Vi. Join the link library

In the program development process, will be frequently used to debug, there are many ways, the following is to say this is through the log printing information to print the program running some of the state values;

Modify the Android.mk file to add a line of code

Include $ (clear_vars) Local_ldlibs + =-llog//ldlibs: Connect Libs, followed by a libs,-llog that requires a link to represent the log library in Android; include $ (build_ Shared_library)

Once you have added the log library, you can print the log information directly from the C + + file;

Call the log printout information in C + +:

#include <android/log.h>
__android_log_print (android_log_error, "Hello", "Livingstone");    __android_log_print (android_log_debug, "Hello", "Livingstone%d", 23);

Example drag-tube address:

Https://github.com/a284628487/JniSample

Getting Started with Android Native JNI programming

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.