android ndk的使用 jni

        最近android项目中底层加密方法需要用c实现,这样调用就需要用到jni了,以下是我学习的一点心得,写出来分享一下:

1、准备工具

需要Android NDK和windows下c、c++代码的编译器cygwin

android-ndk-r9-windows.zip下载地址:http://developer.android.com/tools/sdk/ndk/index.html

cygwin下载地址:http://u.115.com/file/clvy46eb

 

2、环境配置

1. 解压缩NDK和cygwin,并配置cygwin的环境变量。

例如:我解压缩到D盘根目录,那么在环境变量的path中添加:”D:\cytwin\bin;”,

如下图所示。

clip_image002

2. 在命令行中进入cygwin目录,并执行cygwin.bat,如果你不是用Administrator账号登录的系统,那么会在cygwin\home\文件夹中生成一个以你的登录名命名的新的文件夹。

clip_image004

3. 修改新生成文件夹中的“.bash_profile ”文件,用UE或editplus等文本编辑器打开,在最后增加:

NDK=/cygdrive/d/android-ndk-r6

export NDK

然后保存关闭。

d/android-ndk-r6表示ndk在d盘,如果你的ndk放到了其他盘符或路径,例如放到e:\sdk目录中,那么就改为e/sdk/android-ndk-r6。

(如果是Administrator账号登录,直接修改Administrator文件夹中的文件。)

clip_image006

四.开始使用

1.在命令行窗口中进入cygwin目录,执行cygwin.bat

2.进入android-ndk中的samples文件夹里的某个项目文件夹,这里以hello-jni为例

进入文件夹的方式与MS-DOS类似,用cd + 空格 + 盘符+ 路径即可,例子见下图

3.执行$NDK/ndk-build编译

clip_image008

4.例子编译成功后得到libhello-jni.so文件,到此环境就配置好了

 

五、在自己的项目中使用jni
1、首先写java调用的native方法,示例代码如下:

package com.magic.point;

public class EncryptJNI {

 

static {

System.loadLibrary("magic-point-jni");

}

 

public static native void  init();

 

public static native String  getHiddenString(int index);

}

 

2、在jni中c的方法名名称需要是固定格式,我们可以javac EncryptJNI 编译java文件,然后用

javah -jni com.magic.point.EncryptJNI 编译生成com_magic_point_EncryptJNI.h头文件,格式如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class com_magic_point_EncryptJNI */

 

#ifndef _Included_com_magic_point_EncryptJNI

#define _Included_com_magic_point_EncryptJNI

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     com_magic_point_EncryptJNI

 * Method:    init

 * Signature: ()V

 */

JNIEXPORT void JNICALL Java_com_magic_point_EncryptJNI_init

  (JNIEnv *, jclass);

 

/*

 * Class:     com_magic_point_EncryptJNI

 * Method:    getHiddenString

 * Signature: (I)Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_com_magic_point_EncryptJNI_getHiddenString

 

  (JNIEnv *, jclass, jint);

#ifdef __cplusplus

}

#endif

 

#endif

我们可以看到命名格式如下:

JNIEXPORT jstring JNICALL Java_全包名_类名_getHiddenString()

3、接下来我们就可以新建一个Hellojni.c文件,导入com_magic_point_EncryptJNI.h头文件,在c里面具体实现头文件中的方法,完成后将com_magic_point_EncryptJNI.h和Hellojni.c文件复制到android-ndk-r9/samples/hello-jin/ 的jni目录下,修改mk配置文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Hello-jin      //编译生成的so文件名称

LOCAL_SRC_FILES := Hellojin.c     //需编译的文件

include $(BUILD_SHARED_LIBRARY)

执行$NDK/ndk-build编译将生成libHello-jni.so文件,将libHello-jni.so文件复制到android工程libs目录下,调用String result=EncryptJNI.getHiddenString(0); 即可。

 

 六,jni中的类型转换

在jni中的数据类型和java中可直接使用的类型不用,需要转换一下,以下列出char 转jstring类型和jstring类型转char的方法

 1、char 转 jstring

const char * name;
jstring jstr = (*env)->NewStringUTF(env,name);

 

2、jstring 转 char

 

char* jstringToChar(JNIEnv* env, jstring jstr) 

       char* rtn = NULL; 

       jclass clsstring = (*env)->FindClass(env,"java/lang/String"); 

       jstring strencode = (*env)->NewStringUTF(env,"utf-8"); 

       jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B"); 

       jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr, mid, strencode); 

       jsize alen = (*env)->GetArrayLength(env,barr); 

       jbyte* ba = (*env)->GetByteArrayElements(env,barr, JNI_FALSE); 

       if (alen > 0) 

       { 

                 rtn = (char*)malloc(alen + 1); 

                 memcpy(rtn, ba, alen); 

                 rtn[alen] = 0; 

       } 

       (*env)->ReleaseByteArrayElements(env,barr, ba, 0); 

       return rtn; 

}

 

 

猜你喜欢

转载自zxs19861202.iteye.com/blog/1930673