初识Android NDK
本文介绍Windows环境下搭建Android NDK开发环境,并创建一个简单的使用Native代码的Android Application。
一、环境搭建
二、JNI函数绑定
三、例子
一、环境搭建
1. 操作系统:Windows7 64位
2. 安装Java,最新的JDK8貌似还不支持,敢于折腾的同学可以试试,下载JDK7安装即可,别忘了添加JDK的bin目录到PATH环境变量。http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html。"jdk-7u71-windows-x64.exe"
3. 下载Android ADT Bundle,https://developer.android.com/sdk/index.html。"adt-bundle-windows-x86_64-20140702.zip"
4. [可选]使用SDK Manager更新到最新,本文编辑之时API Level已经更新到21了。
5. 下载NDK开发包,解压即可,路径要固定不要轻易改动,因为Eclipse的NDK插件会配置这个路径。https://developer.android.com/tools/sdk/ndk/index.html。"android-ndk-r10b"
6. 安装NDK插件,在Eclipse中,打开菜单Help>Install New Software,Work with里用下拉菜单选择Android Developer Tools Update Site,下面就会出现Developer Tools的分组,展开选择Android Native Development Tool,点击Finish安装。不用选择Developer Tools里面其他的插件,它们已经安装好了。
从NDK r7开始就不需要使用cygwin了,因此以上就是所有的环境搭建步骤。
二、JNI函数绑定
先在Eclipse中创建一个Android Project。然后添加Native支持,在Project Explorer中右键选择新建的工程,在菜单中选择Android Tools>Add Native Support,会自动创建好JNI目录和Android.mk,以及配置好C\C++ Include路径。
JNI中Java方法调用Native方法的绑定有两种方法:一种是自动绑定,只需要C函数名和Java方法名称按照一定的规则能匹配上就能自动绑定。可以通过javah工具将绑定的规则都处理好,生成头文件方便使用,也可以根据规则自己定义函数,不使用生成头文件的方法。具体的规则是:
1. C函数要加上前缀"Java_"。
2. Java中package路径中的圆点要转换成下划线,类名和方法名都保持原样,用下划线隔开。
3. C方法中比Java方法多了两个参数放在最前面,JNIEnv*和jobject。前者是起到C代码和Java代码交互作用的一个结构体指针,后者是调用这个函数的Java对象在C代码中的代表。
4. Java调用Native方法还涉及到参数和返回值的传递,Java中的类型会转换为C中的对应类型,可以精确对应的类型有基本数据类型(如jint, jdouble)、数组(如jintArray)、String(jstring),其他类型一律当做Object(jobject)。
例如Java中定义的一个Activity的类:
package com.example.myhellojni;
public class MyHelloJniActivity extends Activity {
private native String getNativeString();
}
在C文件中的对应函数:
jstring Java_com_example_myhellojni_MyHelloJniActivity_getNativeString(JNIEnv* env, jobject thiz) {
return ...;
}
还有一种动态注册的方法,使得C代码定义的函数不必遵守命名规则也可以与Java中的方法绑定起来。这种绑定是在C代码中实现的,需要在加载这个动态链接库的时候的回调函数JNI_OnLoad中注册。注册方法见代码:
#include <jni.h>
#include <stdlib.h>
// 要绑定到Java的native方法
jstring ajey_getNativeString(JNIEnv* env, jobject thiz) {
return (*env)->NewStringUTF(env, "what? this is a native string!!!!");
} // 计算数组大小的小技巧,只能用于数组,不能用于指针(因为指针的sizeof得不到指针指向内存的大小)
#define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof(array[0])) static JNINativeMethod gMethods[] = { // 这个结构体数组是传给register函数的参数,定义了java方法和C函数的对应关系
// 成员依次是java方法名称、参数和返回值签名字符串、对应的C函数名
{ "getNativeString", "()Ljava/lang/String;", (void*)ajey_getNativeString },
}; static int registerNatives(JNIEnv* env) {
// 先找到java的class。注意gMethods中并没有定义是哪个类的方法,需要在注册的时候指明。
jclass clazz = (*env)->FindClass(env, "com/ajeyone/myhellojni/MyHelloJniActivity");
if (clazz == NULL) {
return JNI_FALSE;
}
// 这一步是真正注册的地方
if ((*env)->RegisterNatives(env, clazz, gMethods, SIZE_OF_ARRAY(gMethods)) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
} jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
// 第一步获取JNIEnv
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
// 第二步注册
if (!registerNatives(env)) {
return -1;
}
// 成功返回表示JNI version的常量,失败返回-1
return JNI_VERSION_1_4;
}
以上代码有一个奇怪的地方:env指针(vm指针也是这样)使用这种方式来调用函数:(*env)->function(env, ...),原因是JNIEnv实际上是typedef定义的指针类型,那么JNIEnv* env就是二级指针,因此需要(*env)->的方式来使用;而且有点像C++中对象成员函数的调用,但这些代码不是用C++编译的而是用C编译的,实际上是结构体中定义了函数指针,所以需要将"this"指针显式地传递过去,也就是env本身。jni.h中也为C++定义了基于对象的访问JNIEnv的方式,实际上是对C函数的包装,使其在C++中更容易使用,如果你的代码是写在cpp文件中的,那么使用的就是C++对象的方式,这时JNIEnv不再是一个typedef的指针,而是一个类类型,直接使用env->function(...)就行了,而且也不需要将env当做第一个参数传递给function。
三、例子
使用Android Tools>Add Native Development Support的时候,将Library名称定义成MyHelloJni。需要注意的是不要忘记写加载动态库的代码,否则肯定是找不到Native方法的。在Eclipse中C\C++代码不会在保存时自动编译,需要自己在菜单中选择Build或者在运行App时触发编译。
前面Java代码中Activity的全部内容:
package com.ajeyone.myhellojni; import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView; public class MyHelloJniActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView text = new TextView(this);
text.setText(getNativeString());
setContentView(text); // 保持简单,未使用layout文件
} private native String getNativeString(); static { // 放在这里是一般的做法,如果有需求可以在其他地方加载
System.loadLibrary("MyHelloJni"); // 千万不要忘了加载动态库
}
}
初识Android NDK的更多相关文章
- Android NDK开发初识
神秘的Android NDK开发往往众多程序员感到兴奋,但又不知它为何物,由于近期开发应用时,为了是开发的.apk文件不被他人解读(反编译),查阅了很多资料,其中有提到使用NDK开发,怀着好奇的心理, ...
- Android NDK开发Hello Word!
在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...
- Android NDK debug 方法
最近又频繁遇到 NDK 的错误,记录一下debug调试的一些经验,以备后续查看 一般来说,在Android Studio中的Monitor中将过滤器的 LOG TAG 设置为 "DEBUG& ...
- android NDK debug 遇到的问题与解决方法
最近在研究android NDK 的eclipse调试,遇到点问题,总结一下: 1.Unknown Application ABI :在application.mk里面添加APP_PLATFORM ...
- Android SDK Android NDK Android Studio 官方下载地址
2016.12 Android Studio Windows Includes Android SDK https://dl.google.com/dl/android/studio/install/ ...
- Android NDK之JNI陷阱
背景: 最近一个月一直在做移植库的工作,将c代码到share library移植到Android平台.这就涉及到Android NDK(native develop kit)内容.这里只想记录下JNI ...
- Android NDK开发
Android NDK 开发教程(极客学院) 一.Android NDK环境搭建 使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin( ...
- Eclipse+CDT+GDB调试android NDK程序(转)
Eclipse+CDT+gdb调试android ndk程序 先介绍一下开发环境,在这个环境下,up主保证是没有问题的. ubuntu 11.10 eclipse 3.7(indego) for ja ...
- android NDK入门 windows下安装cygwin
一.Android NDK环境简介 Android NDK 是运行于Android 平台上的Native Development Kit 的缩写. Android 应用开发者可以通过NDK 调用C 或 ...
随机推荐
- 公司系统的license授权
在我的电脑的myeclipse的whnaproject项目下.可直接编译生成license.xml中所需要的授权码. 引用了spring-license-0.02.jar. package com.w ...
- Linux通过NAT方式配置网络
步骤:1.将虚拟机的网卡VMware Network Adapter VMnet8改成DHCP自动获取IP.2.将Linux虚拟机的网卡自定义连接到VMware Network Adapter VMn ...
- python(29)强大的zip函数
zip函数:它是python的内建函数,(与序列有关的内建函数有:sorted().reversed().enumerate().zip()),其中sorted()和zip()返回一个序列(列表)对象 ...
- 自己写的基于bootstrap风格的弹框插件
自己写的一款基于bootstrap风格的弹框插件,暂时只有确认框.提示框.后续功能扩展.bug修改再更新. ;(function($){ //默认参数 var PARAMS; var DEFAULTP ...
- Java性能调优
一.JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) 永久代(Perm) 其中New和Tenured属于堆内存,堆内存会从JV ...
- SQL时间相关
SQL --本周第一天 SELECT DATEADD(Day,-(DATEPART(Weekday,getdate())+@@DATEFIRST-)%,getdate()) --or ,getdate ...
- sql语句-ALTER TABLE
在工作中常遇到要维护数据库表的列,这里主要介绍sql语句中的ALTER TABLE 语句.ALTER TABLE 语句用于在已有的表中添加.修改或删除列. 如需在表中添加列,请使用下列语法: ALTE ...
- Druid安装-单机
单机版安装 下载安装包http://static.druid.io/artifacts/releases/druid-0.9.1.1-bin.tar.gz 安装 解压缩 安装zookeeper cu ...
- 对OpenCV直方图的数据结构CvHistogram的理解
前几天被OpenCV的直方图的数据结构CvHistogram弄得很纠结.上网一搜,也没什么相关的资料.现在有点头绪了,就写点东西,让后面的人好走一些吧. 先来看看CvHistogram的定义: typ ...
- linux下的gcc编译器
1. 编译单个文件成可执行文件 gcc hello.c 生成默认的可执行文件a.out 2. 编译单个文件为指定名字的可执行文件,使用-o选项指定文件名字 gcc -o test main.c 生成文 ...