基于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 ...
随机推荐
- Installation from source on Windows 7 with Visual C++2012
在这部分说明里,你将会学习到在配备有Visual C++的Windows平台下从源码安装ViSP.下面的这些安装步骤已经在32位Windows系统,CMake3.1和Visual Studio 201 ...
- 【ios开发学习 - 第二课】iOS项目文件夹结构
文件夹结构 AppDelegate Models Macro General Helpers Vendors Sections Resources 一个合理的文件夹结构首先应该是清晰的.让人一眼看 ...
- android反编译odex文件
关于android的反编译工具,相信大家并不陌生 如APK-TOOL,dex2jar APK-TOOL 用于反编译出布局文件 下载地址http://code.google.com/p/android- ...
- 什么是PV和UV?
技术角度 1个PV是指从浏览器发出一个对网络server的Request,网络server接到Request之后.会開始把该Request相应的一个Page(Page就是一个网页)发送到client的 ...
- 用ElasticSearch,LogStash,Kibana搭建实时日志收集系统
用ElasticSearch,LogStash,Kibana搭建实时日志收集系统 介绍 这套系统,logstash负责收集处理日志文件内容存储到elasticsearch搜索引擎数据库中.kibana ...
- win7中下mysql-5.6.22免安装配置
windows下mysql免安装配置 1. 下载mysql免安装压缩包 下载mysql-5.6.22-winx64.zip 解压到本地D:\mysql-5.6.22-winx64 2. 修改配置文件 ...
- 绕过open_basedir读文件脚本
绕过open_basedir读文件脚本 2016年11月13日 01:28:21 阅读数:1221 参加了一场2016年的sycsec感觉又学到不少东西 废话不多说,首先啥是open_basedir? ...
- Java 关于运算结果
今天发现一个自己的一个知识误区 原来有些自己以为会发生异常的运算,并没有异常发生,只要运算符两端存在至少一个浮点数 比如: public class Demo { /** * @param args ...
- 小项目: low版本的 员工信息程序:
### 附加两个文件1 user_info 和worker_info flag = False def logon(): #登录函数 global flag usr = input('Username ...
- Spark Tachyon编译部署(含单机和集群模式安装)
Tachyon编译部署 编译Tachyon 单机部署Tachyon 集群模式部署Tachyon 1.Tachyon编译部署 Tachyon目前的最新发布版为0.7.1,其官方网址为http://tac ...