This article describes the Windows environment that builds the Android NDK development environment and creates a simple Android application that uses native code.
First, Environment construction
Second, JNI function binding
Iii. examples
First, Environment construction
1. Operating system: Windows7 64-bit
2. Install Java, the latest JDK8 seemingly do not support, dare to toss the classmate can try, download JDK7 installation can, don't forget to add the JDK Bin directory to the PATH environment variable. Http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html. "Jdk-7u71-windows-x64.exe"
3. Download Android ADT bundle,https://developer.android.com/sdk/index.html. "Adt-bundle-windows-x86_64-20140702.zip"
4. [optional] update to the latest using SDK manager, the API level has been updated to 21 when editing this article.
5. Download the NDK Development Kit, unzip it, the path must be fixed do not change easily, because Eclipse's NDK plugin configures this path. Https://developer.android.com/tools/sdk/ndk/index.html. "ANDROID-NDK-R10B"
6. Install the NDK plugin, in Eclipse, open the menu Help>install New software,work with drop-down menu to select Android Developer Tools Update Site, The following will appear in the Developer Tools grouping, expand select Android Native Development Tool, click Finish installation. Instead of selecting the other plugins in developer tools, they are already installed.
There is no need to use Cygwin from the NDK R7, so these are all the environmental building steps.
Second, JNI function binding
Create an Android Project in Eclipse first. Then add Native support, right-click on the new project in Project Explorer, select Android Tools>add Native supports from the menu, create the JNI directory and android.mk automatically, and configure C\c + + include path.
There are two ways to bind a Java method call native method in JNI: One is auto-binding, only the C function name and the Java method name can be automatically bound according to certain rules. You can use the Javah tool to handle the rules of the binding, make the header file easy to work with, or you can define your own function according to the rules, without using the method of generating the header file. The specific rules are:
1. Add the prefix "Java_" to the C function.
2. The dots in the package path in Java are converted to underscores, and the class and method names remain the same, separated by underscores.
3. There are two more parameters in the C method than the Java method at the front, jnienv* and Jobject. The former is a struct pointer that interacts with the C code and the Java code, which is the representative of the Java object that called the function in C code.
4. The Java call native method also involves the passing of parameters and return values, the type in Java is converted to the corresponding type in C, can be precisely corresponding to the type has a basic data type (such as Jint, jdouble), an array (such as Jintarray), String (jstring), other types are treated as Object (Jobject).
For example, a class of activity defined in Java:
Package Com.example.myhellojni;public class Myhellojniactivity extends Activity { private native String Getnativestring ();}
The corresponding function in the C file:
Jstring java_com_example_myhellojni_myhellojniactivity_getnativestring (jnienv* env, Jobject thiz) { return ...;}
There is also a dynamic registration method that allows a C code-defined function to be bound to a method in Java without having to follow a naming convention. This binding is implemented in C code and needs to be registered in the callback function jni_onload when the dynamic link library is loaded. Registration method See Code:
#include <jni.h> #include <stdlib.h>
The native method to bind to Java jstring ajey_getnativestring (jnienv* env, Jobject thiz) {return (*env)->newstringutf (env, "what ? This is a native string!!!! ");} A small technique for calculating the size of an array, only for arrays, not for pointers (because the pointer's sizeof does not have a pointer to the size of the memory) #define Size_of_array (Array) (sizeof (array)/sizeof (array[0)) Static Jninativemethod gmethods[] = {//This struct array is the parameter passed to the Register function, which defines the corresponding relationship between the Java method and the C function.
The members are followed by the Java method name, the parameter and return value signature string, the corresponding C function name {"Getnativestring", "() ljava/lang/string;", (void*) ajey_getnativestring},}; static int registernatives (jnienv* env) {
Find the Java class first. Note that there is no way to define which class is in gmethods, which needs to be specified at the time of registration. Jclass clazz = (*env)->findclass (env, "com/ajeyone/myhellojni/myhellojniactivity"); if (clazz = = NULL) {return jni_false; }
This step is really registered place if ((*env)->registernatives (env, Clazz, Gmethods, Size_of_array (gmethods)) < 0) {return JN I_false; } return jni_true;} Jint jnicall jni_onload (javavm* vm, void* reserved) {jnienv* env = NULL;
The first step is to get jnienv if ((*VM)->getenv (VM, (void**) &env, jni_version_1_4)! = JNI_OK) {return-1; }//Second step to register if (!registernatives (env)) {return-1; }//Successfully returned a constant representing JNI VERSION, failed to return-1 return jni_version_1_4;}
The above code has a strange place: The env pointer (also the VM pointer) uses this method to invoke the function: (*env)->function (env, ...), because jnienv is actually a pointer type defined by typedef, then jnienv* Env is a level two pointer, so it needs to be used (*env), and a bit like the invocation of object member functions in C + +, but the code is not compiled in C + + but compiled with C, in fact, the struct defines a function pointer, so you need to pass the "this" pointer to the past explicitly, That is, env itself. Jni.h also defines an object-based access jnienv for C + +, actually wrapping the C function to make it easier to use in C + +, if your code is written in a CPP file, then the C + + object is used. At this point jnienv is no longer a typedef pointer, but a class type, directly using Env->function (...). , and there's no need to pass env as the first parameter to the function.
Iii. examples
When using Android Tools>add Native Development Support, the library name is defined as Myhellojni. Note that you should not forget to write the code to load the dynamic library, or you must not find the native method. C\c++ code in eclipse does not compile automatically when it is saved, you need to choose Build yourself in the menu or trigger compilation when you run the app.
The entire contents of the activity in the preceding Java code:
Package Com.ajeyone.myhellojni;import Android.app.activity;import Android.os.bundle;import Android.widget.TextView ;p ublic class Myhellojniactivity extends Activity {@Overrideprotected void onCreate (Bundle savedinstancestate) { Super.oncreate (savedinstancestate); TextView Text = new TextView (this);
Text.settext (Getnativestring ()); Setcontentview (text); Keep it simple, do not use layout file}private native String getnativestring (); static {//Put here is the general practice, if there is a need to load system.loadlibrary elsewhere (" Myhellojni "); Don't forget to load the dynamic library}}
First knowledge of Android NDK