基于Eclipse的Android JNI层测试应用开发过程记录
前言
本文记录一个Java层与JNI层参数与数据交互的应用程序开发过程,为实现一个功能完整的带Java与JNI的应用程序打下基础。本文假设读者已搭建好Android的Eclipse与NDK开发环境,包括通过ADB连接手机的配置。
1. 构建基本的Android应用程序
1.1 引导界面配置
1.2 XML文件配置
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" />其中的字符串就定义在res文件夹下values文件夹中的strings.xml中。我们对hello_world的值做修改,如下:
<?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>根据需要,可以将上图中模拟应用界面的左边栏中的控件拖入模拟应用界面上放置,相应地,XML文件中就会有该控件的布局描述。
package com.napolean.app; import android.os.Bundle; import android.app.Activity; import android.view.Menu; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public 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; } }插入手机连接上ADB,或者配置一个Android模拟器,点击运行程序,即可看到应用程序运行并显示我们所修改的字符串。关于手机如何通过ADB连接以及Android模拟器的配置,在此不作展开。
2. 构建Java与C/C++交互的JNI层接口
2.1 Java层包含JNI本地函数的类
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"); } }
2.2 本地函数在JNI层的实现
javah -classpath bin/classes -d jni com.napolean.app.NativeInterface运行命令后,在jni文件夹下就会生成一个名为com_napolean_app_NativeInterface.h的头文件,里面包含有的接口函数如下:
/* 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 __cplusplus extern "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生成这个头文件的目的是免去手动编写JNI层的接口函数,并无其它用途,使用后可删除。在jni文件夹下创建NativeInterface.cpp,将上述头文件中所有内容拷入,经过改造,如下:
#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 __cplusplus extern "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上述改造的代码主要是将函数声明改为函数定义,并且添加了打印信息的支持。
2.3 JNI层动态库编译配置
/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/
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := NativeInterface LOCAL_SRC_FILES := NativeInterface.cpp LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
第五步,编译生成动态库。点击Eclipse菜单栏中的"Project"->"Build Project",即可完成编译。在libs/armeabi/文件夹下生成了"libNativeInterface.so"动态库。
2.4 Java层中调用本地函数
package com.napolean.app; import android.os.Bundle; import android.app.Activity; import android.view.Menu; public class MainActivity extends Activity { private NativeInterface myJNI; @Override protected 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); } @Override public 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(); } }
附录:更多内容
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。