初识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 或 ...
随机推荐
- 黄聪:win7 QQ自动远程协助 提示关闭了远程桌面
最近在使用QQ自动远程协助的时候,输入完远程验证密码后,提示“关闭了远程桌面” 系统环境:win7 64位 问题描述:在使用QQ自动远程协助,对方QQ提示关闭了远程桌面. 解决办法:将2台电脑的时间调 ...
- es6 let
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- HDFS snapshot操作实战
Hadoop从2.1.0版开始提供了HDFS SnapShot的功能.一个snapshot(快照)是一个全部文件系统.或者某个目录在某一时刻的镜像.快照在下面场景下是非常有用:防止用户的错误操作:管理 ...
- CentOS7:Puppet推送Zabbix Agent
创建zabbix模块目录: $ mkdir -p /etc/puppet/modules/zabbix/{manifests,templates} 创建init.pp清单: $ cat /etc/pu ...
- Codeforces 732D [二分 ][贪心]
/* 不要低头,不要放弃,不要气馁,不要慌张 题意: n天进行m科考试,每科考试需要a的复习时间,n天每天最多可以考一科.并且指定哪天考哪科. 注意考试那天不能复习. 问最少需要多少天可全部通过考试. ...
- 视频演示eworkflow集成定制aspx页面的过程
eworkflow自定义工作流系统,集成eform自定义表单,可以做到在线编辑流程,在线编辑表单.eform也提供在线建立业务表,维护表字段等,所以通过eworkflow+eform可以在线完成业务流 ...
- slickedit的alias配置
使用slickedit很喜欢它的多语言支持,可以快速查看变量的定义和结构.我一般写verilog较多,使用emcas很方便,但是感觉查看代码结构不太方便(也可能是我不会设置).所以希望能够在slick ...
- openlayers优化项
做了一个简单的样式,但是做的不怎么样:希望和大家讨论下载动态图那里,怎么能够提高效率,提高数据,能够快速反应:一般的处理方法是什么?
- DES对称性加密
using System; using System.Security.Principal; using System.Security.Permissions; using System.Secur ...
- 天地图应用ArcGIS发布的服务
本文包含三个部分:利用ArcMap将Excel的数据转化为ArcGIS MXD文件.利用ArcMap发布服务.天地图添加ArcGIS发布的服务. 一 MXD文件的生成 假设在Excel中存有两个点的坐 ...