Test Application Development Process record of Android JNI Layer Based on Eclipse

Source: Internet
Author: User
Tags manual writing


Preface


This article records the development process of an application that interacts with parameters and data at the Java layer and JNI layer, laying the foundation for implementing a fully functional application with Java and JNI. This article assumes that the reader has set up the Eclipse and NDK development environments for Android, including the configuration of connecting the mobile phone through ADB.


1. Build basic Android applications1.1 Boot Interface Configuration
Open Eclipse, "File"-> "New"-> "Android Application Project". On the pop-up page, configure as follows (the red box indicates that it is not the default and is the place modified by the author, below ):



Click "Next>" until "Finish ". After you click "Finish", the following page is automatically displayed:


   1.2 XML file configuration
We can see a virtual application interface with a line of text "Hello world! ". Click activity_main.xml in the lower-right corner, as defined below:
    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/hello_world" />
The strings are defined in strings. xml in the values folder under the res folder. Modify the value of hello_world as follows:
<?xml version="1.0" encoding="utf-8"?><resources>    <string name="app_name">app</string>    <string name="action_settings">Settings</string>    <string name="hello_world">Napolean: Hello Android Application!</string></resources>
You can drag the control in the left sidebar of the simulated application interface to the simulated application interface and place it. Accordingly, the layout description of the control is displayed in the XML file.

1.3 run the application
You can have MainActivity. java in the src directory. This is the code automatically generated after the preceding guide interface is configured.
package com.napolean.app;import android.os.Bundle;import android.app.Activity;import android.view.Menu;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}
Insert the mobile phone to connect to ADB, or configure an Android simulator. Click Run program to view the program running and display the modified string. This section does not describe how to connect your mobile phone to the Android simulator through ADB.

2. Build a JNI layer interface for Java to interact with C/C ++
Java interacts with C/C ++ on two sides: one side is the Java layer: declare the local interface function in the class of the Java layer, and call the public interface function, so that the classes that need to access the JNI-layer functions can call these public functions. The other side is the JNI layer: The JNI layer has the corresponding functions corresponding to the local functions in the Java layer, as well as other common functions, when a Java-layer Local function is called, the corresponding C/C ++ layer function is actually executed.

2.1 right-click the class containing the JNI local function on the Java layer and choose com. napolean. app, select "New"-> "Class", and enter the Class name "NativeInterface" and "Finish" in the pop-up interface to create the NativeInterface Class. Add the Native Function and Its encapsulated public interface to the null class NativeInterface in the generated NativeInterface. java. The Code is as follows:
package com.napolean.app;public class NativeInterface {private native void native_init();private native void native_exit();private native byte[] native_process(byte[] in_buffer, int width, int height);public void NativeInit() {native_init();}public void NativeExit() {native_exit();}public void NativeProcess(byte[] in_buffer, int width, int height) {native_process(in_buffer, width, height);}static {        System.loadLibrary("NativeInterface");    }}
The created Native functions include initialization functions, exit functions, and processing functions. The processing function includes the input byte stream, Buffer width, and Buffer height. The processed byte stream is returned. The next three functions are the public interfaces of the three Native functions.
Finally, call System. loadLibrary () in static, where the dynamic library name in the JNI layer is enclosed in quotation marks. The actually generated dynamic library name adds lib before the library name specified in Android. mk, that is, the library declared as xxx, and finally generates libxxx. so. It is worth noting that the above loading function must use xxx but not the full name, and the library name specified in Android cannot contain the lib prefix; otherwise, it cannot be loaded.
2.2 Implementation of local functions in the JNI Layer
First, create the jni Folder: Right-click the project name, "New"-> "Folder", and enter "jni" to create the jni Folder.



Then, enter the javah command on the terminal and create the JNI-layer function interface corresponding to the declared native function according to NativeInterface. The specific command in the project root directory is
javah -classpath bin/classes -d jni com.napolean.app.NativeInterface
After running the command, a header file named com_napolean_app_NativeInterface.h is generated in the jni folder. the header file contains the following interface functions:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_napolean_app_NativeInterface */#ifndef _Included_com_napolean_app_NativeInterface#define _Included_com_napolean_app_NativeInterface#ifdef __cplusplusextern "C" {#endif/* * Class:     com_napolean_app_NativeInterface * Method:    native_init * Signature: ()V */JNIEXPORT void JNICALL Java_com_napolean_app_NativeInterface_native_1init  (JNIEnv *, jobject);/* * Class:     com_napolean_app_NativeInterface * Method:    native_exit * Signature: ()V */JNIEXPORT void JNICALL Java_com_napolean_app_NativeInterface_native_1exit  (JNIEnv *, jobject);/* * Class:     com_napolean_app_NativeInterface * Method:    native_process * Signature: ([BII)[B */JNIEXPORT jbyteArray JNICALL Java_com_napolean_app_NativeInterface_native_1process  (JNIEnv *, jobject, jbyteArray, jint, jint);#ifdef __cplusplus}#endif#endif
The purpose of generating this header file is to avoid manual Writing of interface functions at the JNI layer, which is useless and can be deleted after use. Create NativeInterface. cpp in the jni folder and paste all the content in the header file. The transformation is as follows:
#include <jni.h>#include <android/log.h>#define LOG_TAG "APP"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)#ifndef _Included_com_napolean_app_NativeInterface#define _Included_com_napolean_app_NativeInterface#ifdef __cplusplusextern "C" {#endif/* * Class:     com_napolean_app_NativeInterface * Method:    native_init * Signature: ()V */JNIEXPORT void JNICALL Java_com_napolean_app_NativeInterface_native_1init  (JNIEnv *, jobject){LOGI("APP native init.");}/* * Class:     com_napolean_app_NativeInterface * Method:    native_exit * Signature: ()V */JNIEXPORT void JNICALL Java_com_napolean_app_NativeInterface_native_1exit  (JNIEnv *, jobject){LOGI("APP native exit.");}/* * Class:     com_napolean_app_NativeInterface * Method:    native_process * Signature: ([BII)[B */JNIEXPORT jbyteArray JNICALL Java_com_napolean_app_NativeInterface_native_1process  (JNIEnv *, jobject, jbyteArray, jint, jint){LOGI("APP native process.");}#ifdef __cplusplus}#endif#endif
The Code modified above is mainly to change the function declaration to the function definition, and added support for printing information.

2.3 JNI layer dynamic library compilation Configuration
If you create a project by yourself, you will find a yellow underline under the header file and function-Defined Characters, because Eclipse cannot find the header files of jni. h and android/log. h. Therefore, you need to configure the header file path unique to the JNI layer in Eclipse.

Step 1: add the C/C ++ feature. Right-click the jni folder, and choose "New"-> "Other". In the displayed page, select:



Select "Shared Library" in the specified project type in the next interface (this step is not important, because the compilation tool needs to be modified later), click "Finish", and Eclipse starts the conversion.
Step 2: Modify the compilation tool. Right-click the project name and click "Properties". The following page is displayed, the "C/C ++ Build" and "C/C ++ General" in the left sidebar are new after the previous conversion. Select "C/C ++ Build". In the "Builder Settings" tab, remove the check box before "Use default build command" and enter "ndk-build ", click "Apply", as shown below:



Step 3: configure the header file path. Add the header file path in "C/C ++ General"-> "Paths and Symbols"-> "program des"-> "gnu c ++. Click "Add..." on the right, Add four paths, and click "Apply.



The four header file paths are:
/home/work/android/android-ndk-r9/platforms/android-18/arch-arm/usr/include//home/work/android/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.6/include//home/work/android/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include//home/work/android/android-ndk-r9/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.6/include/

Step 4: Create Android. mk. Right-click the jni folder, "New"-> "File", and enter Android. mk. Add the following code:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := NativeInterfaceLOCAL_SRC_FILES := NativeInterface.cppLOCAL_LDLIBS := -lloginclude $(BUILD_SHARED_LIBRARY)

Step 5: compile and generate a dynamic library. Click "Project"-> "Build Project" in the Eclipse menu bar to complete compilation. The "libNativeInterface. so" dynamic library is generated in the libs/armeabi/folder.

2.4 call local functions in Java Layer
The Java layer calls the local functions of the JNI layer as follows.
package com.napolean.app;import android.os.Bundle;import android.app.Activity;import android.view.Menu;public class MainActivity extends Activity {private NativeInterface myJNI;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);byte[] in_buffer = new byte[1920*1080*3/2];int width = 1920;int height = 1080;myJNI = new NativeInterface();myJNI.NativeInit();myJNI.NativeProcess(in_buffer, width, height);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}protected void onDestroy() {myJNI.NativeExit();super.onDestroy();}}


Appendix: More
See my ChinaUnix blog: http://blog.chinaunix.net/uid-20746260-id-3910616.html







Related Article

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.