基于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 ...
随机推荐
- 分享一下vue ui的分页的用法
var newToAddLeave = function(){ var goIndex = { template:` <i-table :columns="overTimeList.c ...
- codefroces 650A. Watchmen
A. Watchmen time limit per test 3 seconds memory limit per test 256 megabytes input standard input o ...
- 利用反射实现Servlet公共类的抽取
一次请求的执行过程: 请求:发送请求地址-->到达web.xml中,找到地址对应的servlet类-->通过反射调用该类的构造函数,创建该servlet类的对象-->通过当前对象调用 ...
- 【Codeforces Round #424 (Div. 2) B】Keyboard Layouts
[Link]:http://codeforces.com/contest/831/problem/B [Description] 两个键盘的字母的位置不一样; 数字键的位置一样; 告诉你第一个键盘按某 ...
- 【Uva 1336】Fixing the Great Wall
[Link]: [Description] 给你长城上的n个修补点,然后你的位置为x; 你需要依次去这n个点,然后把它们全部修好. 但是修的前后顺序不一样的话,花费不一样. 如果立即把第i个点修好的话 ...
- C# async/await异步编程深入理解
异步函数简介 一般指 async 修饰符声明得.可包含await表达式得方法或匿名函数. 声明方式 异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字.async可以出现在返回值 ...
- 研究一些复杂java开源软件代码的体会(转)
原文地址:http://herman-liu76.iteye.com/blog/2349026 有时候看源代码是非常有趣的事情,象是思考游戏,象是思考棋局... 平时做J2EE项目中, ...
- Windows操作系统下将Redis安装为服务
安装服务: E:/Redis/Redis-x64-3.2.100/redis-server.exe --service-install E:/Redis/Redis-x64-3.2.100/redis ...
- 洛谷 P2690 接苹果
P2690 接苹果 题目背景 USACO 题目描述 很少有人知道奶牛爱吃苹果.农夫约翰的农场上有两棵苹果树(编号为1和2), 每一棵树上都长满了苹果.奶牛贝茜无法摘下树上的苹果,所以她只能等待苹果 从 ...
- [React] Validate Custom React Component Props with PropTypes
In this lesson we'll learn about how you can use the prop-types module to validate a custom React co ...