基于Eclipse的Android JNI层測试应用开发过程记录
前言
本文记录一个Java层与JNI层參数与数据交互的应用程序开发过程。为实现一个功能完整的带Java与JNI的应用程序打下基础。
本文如果读者已搭建好Android的Eclipse与NDK开发环境,包含通过ADB连接手机的配置。
1. 构建主要的Android应用程序
1.1 引导界面配置
Application Project",在弹出界面,配置例如以下(红色框表示不是默认,是作者改动过的地方,下同):
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2xvdWRfZGVza3RvcA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
1.2 XML文件配置
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文件里就会有该控件的布局描写叙述。
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");
}
}
当中处理函数包括输入字节流、Buffer宽度、Buffer高度,返回处理后的字节流。接下来三个函数各自是三个Native函数的公共接口。
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层动态库编译配置
Library"(这一步并不重要,由于后面须要改动编译工具),点击"Finish",Eclipse就開始转换工作。
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="">
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();
} }
附录:很多其它内容
基于Eclipse的Android JNI层測试应用开发过程记录的更多相关文章
- Android studio及eclipse中的junit单元測试
转载请标明出处:http://blog.csdn.net/nmyangmo/article/details/51179106 前一段时间有人问我单元測试的相关内容,我稍作总结做日志例如以下: 由于我接 ...
- android手机安全性測试手段
android手机安全性測试手段 罗列一下自己经常使用的android手机安全性測试攻击手段: 1. fiddler和tcpdump+wireshark抓包分析,模拟改动http请求參数,检验漏洞 2 ...
- 基于eclipse创建android的helloworld工程
基于eclipse创建android的helloworld工程 之前用过Android studio感觉很慢,决定采用eclipse来学习Android开发.下面来看是怎么创建的. 选择File--- ...
- 基于Eclipse的Android开发环境搭建
1. Java开发环境搭建 1.1 JDK下载安装 JDK(Java Development Kit )是针对Java开发人员发布的软件开发工具包.JDK 是整个Java的核心,包括了Java运行 ...
- 基于QTP的自己主动化測试框架介绍
继前面用了七章介绍了基于QTP的自己主动化測试框架,以下再用几个视频再补充一下. 视频一:基本框架特点介绍说明 .框架的特点从正反两面进行了分析以及主要思想 http://v. ...
- 基于eclipse搭建android开发环境-win7 32bit
基于eclipse搭建android开发环境-win7 32bit 前言:在使用朋友已搭建的Android开发环境时,发现朋友的开发环境版本较低且在update SDk时失败,便决定根据网上文章提示从 ...
- Android开发和測试实践 - 接入友盟统计
这两年一直在做无线的測试,兴许还会继续去做无线的測试,可是之前由于时间的原因一直都没有非常细致的了解到代码层面. 最近抽出时间自己做了些app的开发,决定假设想把移动的測试做好做深入.有一定的app开 ...
- 利用Continuous Testing实现Eclipse环境自己主动单元測试
当你Eclipse环境中改动项目中的某个方法时,你可能因为各种原因没有执行单元測试,结果代码提交,悲剧就可能随之而来. 所幸infinitest(http://infinitest.github.io ...
- Android 进行单元測试难在哪-part3
原文链接 : HOW TO MAKE OUR ANDROID APPS UNIT TESTABLE (PT. 1) 原文作者 : Matthew Dupree 译文出自 : 开发技术前线 www.de ...
随机推荐
- 123.static静态函数与类模板
#include <iostream> using namespace std; //静态函数没有this指针,无需创建对象就可以直接调用 template<class T> ...
- 分享一下js正则中惰性与贪婪
首先引入一个介绍比较详细的网站 http://www.cnblogs.com/yuaima/p/5258513.html http://www.jb51.net/article/31491.htm 接 ...
- 127.0.0.1和localhost和本机IP三者的区别!
1, 先来说下回送地址(Loopback Address): 回送地址是主机用于向自身发送通信的一个特殊地址(也就是一个特殊的目的地址).可以这么说:同一台主机上的两项服务若使用回送地址而非分配的主机 ...
- 在Windows下如何创建虚拟环境(默认情况下)
很多小伙伴平时在使用Python的时候,有的项目需要使用Python2来进行开发,有的项目则是需要Python3来进行开发.当不清楚怎么分开环境的时候,此时两个环境开始打架,彼此傻傻分不清楚.虚拟环境 ...
- Pycharm在Ubuntu14.04中的基本使用指南
前几天给大家分享了:如何在VMware虚拟机中安装Ubuntu14.04系统.今天给大家分享一下在Ubuntu14.04中如何简单的使用Pycharm.1.启动Pycharm,将进入Pycharm的启 ...
- vue.js 第一课:实例化vue
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- PostgreSQL递归查询实现树状结构查询
在Postgresql的使用过程中发现了一个非常有意思的功能,就是对于须要相似于树状结构的结果能够使用递归查询实现.比方说我们经常使用的公司部门这样的数据结构.一般我们设计表结构的时候都是相似以下的S ...
- win7中下mysql-5.6.22免安装配置
windows下mysql免安装配置 1. 下载mysql免安装压缩包 下载mysql-5.6.22-winx64.zip 解压到本地D:\mysql-5.6.22-winx64 2. 修改配置文件 ...
- Outlook中设置会议的提醒
https://support.office.com/en-us/article/Set-or-remove-reminders-7a992377-ca93-4ddd-a711-851ef359792 ...
- SAR(遥感、卫星) 图像常用数据集
Brazilian Coffee Scenes数据集较小,5MB左右: UC Merced Land Use Dataset(数据集规模较大,300MB+) MSTAR public targets ...