前言

  本文记录一个Java层与JNI层參数与数据交互的应用程序开发过程。为实现一个功能完整的带Java与JNI的应用程序打下基础。

本文如果读者已搭建好Android的Eclipse与NDK开发环境,包含通过ADB连接手机的配置。

1. 构建主要的Android应用程序

 

1.1 引导界面配置



  打开Eclipse,"File"->"New"->"Android
Application Project",在弹出界面,配置例如以下(红色框表示不是默认,是作者改动过的地方,下同):



  之后,一路点击"Next >"。直到"Finish"。点击"Finish"之后,自己主动回打开例如以下界面:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2xvdWRfZGVza3RvcA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

  

1.2 XML文件配置


  我们能够看到一个虚拟的应用界面,当中有一行文字"Hello
world!"。

点击上图右下角的activity_main.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文件里就会有该控件的布局描写叙述。


1.3 执行应用程序

  能够再src文件夹下有个MainActivity.java,这是上面引导界面配置完毕后自己主动生成的代码。
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层接口


  Java与C/C++交互分为两边:一边是Java层:在Java层的类中声明本地接口函数,并在公共接口函数调用,使得须要訪问JNI层函数的类调用这些公共函数就可以;还有一边是JNI层:JNI层有相应于Java层中本地函数的相应函数,也有其他普通函数,在Java层本地函数被调用时,实际上终于会运行相应的C/C++层函数。

2.1 Java层包括JNI本地函数的类

  
  右键点击src文件夹下的com.napolean.app,选择"New"->"Class",在弹出的界面中输入类名"NativeInterface","Finish"就可以完毕NativeInterface类的创建。在生成的NativeInterface.java中的空类NativeInterface中加入Native函数及其封装的公共接口,详细代码例如以下:
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");
} }
  所创建的Native函数有初始化函数、退出函数和处理函数。

当中处理函数包括输入字节流、Buffer宽度、Buffer高度,返回处理后的字节流。接下来三个函数各自是三个Native函数的公共接口。


  最后在static中调用System.loadLibrary()。当中引號内为后面JNI层动态库库名。实际生成的动态库名会在Android.mk中指定的库名前加入lib之后加入.so,即声明为xxx的库,终于生成libxxx.so。值得注意的是:在上述载入函数中必须使用xxx而不能使用全名。而且在Android中指定的库名不能带lib前缀,否则无法载入。


2.2 本地函数在JNI层的实现


  首先创建jni目录:右键点击project名,"New"->"Folder"。输入"jni"。创建jni目录。



  接着。在终端输入javah命令,创建依据NativeInterface中声明native函数相应的JNI层函数接口,在project根文件夹下详细命令为
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层动态库编译配置


  假设你亲手创建project。就会发现头文件和函数定义的字符以下有黄色下划线。这是由于Eclipse找不到jni.h和android/log.h的头文件。所以须要在Eclipse配置JNI层特有的头文件路径。

  第一步,加入C/C++特性。右键点击jni目录,"New"->"Other"。在弹出界面例如以下选择:



在下一个界面中的指定project类型中选择"Shared
Library"(这一步并不重要,由于后面须要改动编译工具),点击"Finish",Eclipse就開始转换工作。

  第二步,改动编译工具。右键点击project名,"Properties"。弹出例如以下界面,当中左边栏中的"C/C++
Build"与"C/C++ General"是上一步转换工作完毕后新的。选择"C/C++ Build"。在"Builder Settings"标签中,去掉"Use default build command"前的勾,输入"ndk-build",点击"Apply"应用,例如以下所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2xvdWRfZGVza3RvcA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


  第三步,配置头文件路径。在"C/C++
General"->"Paths and Symbols"->"Includes"->"GNU C++"中加入头文件路径。

点击右边的"Add...",加入四个路径。然后点击"Apply"应用。




当中,四个头文件路径为:
/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/

  第四步。创建Android.mk。右键点击jni目录,"New"->"File",输入Android.mk。

加入例如以下代码:

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层中调用本地函数


  Java层调用JNI层本地函数的方法,例如以下所看到的。

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();
} }

附录:很多其它内容


  參见我的ChinaUnix博客文章:http://blog.chinaunix.net/uid-20746260-id-3910616.html









基于Eclipse的Android JNI层測试应用开发过程记录的更多相关文章

  1. Android studio及eclipse中的junit单元測试

    转载请标明出处:http://blog.csdn.net/nmyangmo/article/details/51179106 前一段时间有人问我单元測试的相关内容,我稍作总结做日志例如以下: 由于我接 ...

  2. android手机安全性測试手段

    android手机安全性測试手段 罗列一下自己经常使用的android手机安全性測试攻击手段: 1. fiddler和tcpdump+wireshark抓包分析,模拟改动http请求參数,检验漏洞 2 ...

  3. 基于eclipse创建android的helloworld工程

    基于eclipse创建android的helloworld工程 之前用过Android studio感觉很慢,决定采用eclipse来学习Android开发.下面来看是怎么创建的. 选择File--- ...

  4. 基于Eclipse的Android开发环境搭建

    1.  Java开发环境搭建 1.1  JDK下载安装 JDK(Java Development Kit )是针对Java开发人员发布的软件开发工具包.JDK 是整个Java的核心,包括了Java运行 ...

  5. 基于QTP的自己主动化測试框架介绍

    继前面用了七章介绍了基于QTP的自己主动化測试框架,以下再用几个视频再补充一下.        视频一:基本框架特点介绍说明 .框架的特点从正反两面进行了分析以及主要思想      http://v. ...

  6. 基于eclipse搭建android开发环境-win7 32bit

    基于eclipse搭建android开发环境-win7 32bit 前言:在使用朋友已搭建的Android开发环境时,发现朋友的开发环境版本较低且在update SDk时失败,便决定根据网上文章提示从 ...

  7. Android开发和測试实践 - 接入友盟统计

    这两年一直在做无线的測试,兴许还会继续去做无线的測试,可是之前由于时间的原因一直都没有非常细致的了解到代码层面. 最近抽出时间自己做了些app的开发,决定假设想把移动的測试做好做深入.有一定的app开 ...

  8. 利用Continuous Testing实现Eclipse环境自己主动单元測试

    当你Eclipse环境中改动项目中的某个方法时,你可能因为各种原因没有执行单元測试,结果代码提交,悲剧就可能随之而来. 所幸infinitest(http://infinitest.github.io ...

  9. Android 进行单元測试难在哪-part3

    原文链接 : HOW TO MAKE OUR ANDROID APPS UNIT TESTABLE (PT. 1) 原文作者 : Matthew Dupree 译文出自 : 开发技术前线 www.de ...

随机推荐

  1. 23. Angular 中用 a 标签 href 路由时在浏览器中显示异常 "%2F" 路由失败问题1

    这个是angular1.6默认给hash路由上添加了!(感叹号),导致出错,修改方法如下(添加配置,去掉默认前缀感叹号):   angular.module('routingDemoApp',['ng ...

  2. MySQL自定义函数(四十六)

    MySQL自定义函数 一.什么是MYSQL自定义函数? mysql当中的自定义函数,我们简称为UDF,它实际上是一种对MySQL扩展的途径,其用法与内置函数相同. 二.自定义函数应该具备哪些条件? 我 ...

  3. 轻松掌握Ubuntu Linux的3D桌面快捷键使用

    视频下载地址: http://115.com/file/be4n23v6#linux3d.rar 轻松掌握Ubuntu Linux的3D桌面快捷键使用 高级3D桌面展示 本文出自 "李晨光原 ...

  4. 紫书 例题 9-7 UVa 11584 (线性结构上的动态规划)

    这道题判断回文串的方法非常的秀! 这里用到了记忆化搜索,因为会有很多重复 同时用kase来区分每一组数据 然后还有用递归来判断回文,很简洁 然后这种线性结构的动态规划的题,就是把 当前的这个数组分成两 ...

  5. Introducing ASLR for FreeBSD

    Shawn WebbOliver Pinter10 July 2014http://www.hardenedbsd.org/ [ 1. Introduction ]Security in FreeBS ...

  6. HDU 4173 Party Location(计算几何,枚举)

    HDU 4173 题意:已知n(n<=200)位參赛选手的住所坐标.现要邀请尽可能多的选手来參加一个party,而每一个选手对于离住所超过2.5Km的party一律不去,求最多能够有多少个选手去 ...

  7. 带你彻彻底底弄懂Scroller

    Scroller的使用 这是一个滑动帮助类.并不能够使View真正的滑动,而是依据时间的流逝.获取插值器中的数据.传递给我们.让我们去配合scrollTo/scrollBy去让view产生缓慢滑动,产 ...

  8. android framework 02

    Android底层开发1.安装Ubuntu系统2.Ubuntu配置开发环境: sudo apt-get install git-core gnupg flex bison gperf zip sudo ...

  9. Server.MapPath()的用法

    http://blog.csdn.net/qiuhaifeng_csu/article/details/19416407 Server.MapPath(string path)作用是返回与Web服务器 ...

  10. svg(1) path路径

    注: 笔记来自于http://www.jb51.net/html5/72250.html  以及http://blog.csdn.net/u013291076/article/details/2707 ...