Android NDK 使用入门

来源:互联网 发布:发饰品牌 知乎 编辑:程序博客网 时间:2024/05/17 06:48

新开通了MSDN博客,第一篇先写下今天做的一个NDK的例子吧。

因为也是几个月前才转做JAVA,所以对JNI也不是很熟悉,个人感觉NDK跟JNI区别主要是NDK直观来讲,就是个工具集,可以很方便的生成.so文件.

常规步骤。

一、安装cygwin.因为android是基于linux的系统,处理器是ARM的,所以在window平台上开发android程序,需要一个交叉编译器。cygwin可以模拟linux操作系统,使用make和gcc对源文件编译。cygwin的安装方法,网上很多。记得安装时装make和gcc的选项设为install. 安装后在cygwin中输入"make -v" 和 "gcc -v"检测是否成功安装两个工具。

二、下载NDK,应该需要翻墙,现在最新版本都r5或r6了吧,我机子上之前同事传给我的 android ndk r4,解压到任意地方,如D:/ndk。接下来需要设置环境变量指到它的目录。

三、找到cygwin的安装目录home/<你的用户名>/.bash_profile,打开这个文件,在最后添加NDK=/cygdrive/<你的盘符>/<android ndk 目录> 例如NDK=/cygdrive/d/android/android-ndk-r4-windows export NDK

其中"NDK"这个名字随便起,类似于window里的环境变量。重启cygwin,输入cd $NDK进入对应目录,就成功了。

四、与老版本不一样,现在就可以直接编译.so文件了。在cygwin中进入到你的源文件目录,直接$NDK/ndk-build 就可以编译文件了。可以先用NDK自带的例子测试,如我的目录NDK_r4b/samples/hello-jni/jni。也就是用$NDK(第三条中设置的路径)中的ndk-build脚本去完成编译。脚本中还是调用cygwin的make实现编译的。

测试demo:

一、用eclipse创建一个android工程,可以直接跑出来hello android的那种。一会用此工程显示通过jni取出的数据。我创建的activity类为ndk,包名为com.ndk。

二、设计JNI接口。在工程ndk类同级目录下创建文件Utility.java。内容输入

package com.ndk;

public class Utility {
 
 public native int sum(int a, int b);

}

三、生成C/C++头文件。为了生成时能够找到目录,先把Utility.java拷到工程bin文件夹下,通过javac 编译Utility.java生成class文件,把此class文件拷到子目录对应包文件夹下(bin/com/ndk)。在dos中进入到bin目录,输入"javah -jni com.ndk.Utility",此时会生成com_ndk_Utility.h文件。内容如下(注:如果java文件的包名变化,也要重新生成C/C++文件,今天刚发现编译器报调用一个JNI 方法时UnsatisfiedLinkError错误,最后发现是包名变化导致的,原以为只改包名没影响呢)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ndk_Utility */

#ifndef _Included_com_ndk_Utility
#define _Included_com_ndk_Utility
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ndk_Utility
 * Method:    sum
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_ndk_Utility_sum
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

四、实现本地文件。在工程目录下建一个jni文件,把上面生成的.h文件拷到此文件夹下(用ndk-build编译时,它默认去找jni文件夹下的Android.mk文件,如果不放到此文件夹下,编译时提示找不到文件),创建同名的.c或.cpp文件,然后用实现此函数。注:如果用C语言实现,函数形参要加变量名,否则会报错。实现如下

 

#include "com_ndk_Utility.h"

JNIEXPORT jint JNICALL Java_com_ndk_Utility_sum
  (JNIEnv *env, jobject obj, jint a, jint b)
{
    int c = a + b;
    return c;
}

五、编写Android.mk文件

LOCAL_PATH := $(call my-dir) //系统提供,指定当前路径

include $(CLEAR_VARS)   //系统提供,指明GNU makefile文件

LOCAL_MODULE    := utility //库名,生成文件可能会被添加上前缀,但在程序调用时仍使用此名
LOCAL_SRC_FILES := com_ndk_Utility.c //源文件列表

include $(BUILD_SHARED_LIBRARY) //系统提供,指定makefile脚本

 

六、生成动态连接库(.so)文件

常规步骤第四条,生成的.so文件被放在../libs/armeabi文件夹下,会有提示。

七、程序中装载动态库.修改原工程文件如下:

public class ndk extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView  tv = new TextView(this);
        Utility test = new Utility();
        int a = test.sum(20, 15);
        tv.setText("result : " + a);
        setContentView(tv);
    }
    static {
        System.loadLibrary("utility");
    }
}

八、运行工程测试结果。


补:有一个开源组织,对发布了优化版本的NDK,可以支持宽字节,静态分析等,如果有特殊需求官方无法满足的话,可以考虑一下:

http://www.crystax.net