Android APP中时常用到JNI(java本地调用),如果接触过反编译方面的知识,肯定会觉得Android APP是如此地透明。
本文主要总结Android APP用JNI的两种方式,第一种就是在源码下编译源文件生成.so文件 ;第二种是Eclipse配置NDK,不管是哪种方式都有以下的步骤:
1、编写包含native方法的java文件,native关键字申明的方法即是JNI方法。
2、将此java文件通过javac和javah命令转成.h文件
3、通过.h文件来编写.c文件
4、编写Android.mk文件
5、编译生成.so文件
不同的在于生成.so文件的方式,如果Eclipse中配置了NDK的话,每次刷新或者是clean都会自动去执行Android.mk文件生成.so文件,如果是在源码下编译的话,需要你有linux环境,在linux环境下编译源文件生成.so库。
这里说一下详细的步骤,方便以后查阅:
1、编写java文件SignUtil
package com.dxd.jnidemo;
public class SignUtil {
protected static native String getMD5(String str) ;
}
2、通过java文件生成.h文件
将java文件拷贝至你喜欢的目录,这里我拷贝到了桌面的jni目录,执行如下命令生成.h文件
3、通过.h文件来编写.c文件
我这里的.h文件名为com_dxd_jnidemo_SignUtil.h从这个名字可以看出SignUtil.java文件所属的包名,这个头文件的内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_dxd_jnidemo_SignUtil */
#ifndef _Included_com_dxd_jnidemo_SignUtil
#define _Included_com_dxd_jnidemo_SignUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_dxd_jnidemo_SignUtil
* Method: getMD5
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_dxd_jnidemo_SignUtil_getMD5
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
我们可以看到有一个方法的声明为JNIEXPORT jstring JNICALL Java_com_dxd_jnidemo_SignUtil_getMD5(JNIEnv *, jclass ,jstring) ;
是的,他就是jni方法。现在来实现这个接口,创建一个名叫com_dxd_jnidemo_SignUtil.c的c文件,内容如下:
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_dxd_jnidemo_SignUtil_getMD5
(JNIEnv *env, jclass jcls, jstring jstr){
return(*env)->NewStringUTF(env, (char *)"Just a Demo!");
}
4、编写Android.mk文件,名字就叫Android.mk。
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE)
LOCAL_SRC_FILES:= \
com_dxd_jnidemo_SignUtil.c
LOCAL_MODULE_TAGS:= optional
LOCAL_MODULE:= libsign_dxd
include $(BUILD_SHARED_LIBRARY)
5A、Android源码下编译
将.h文件.c文件和Android.mk文件一起拷贝到android源码环境的某个目录,然后进入到该目录mm命令进行编译即可,将生产的libsign_dxd.so文件拷贝至Android工程libs/armeabi目录下。在java代码static块中加载该.so库时,只需要写成System.loadLibrary("sign_dxd") ;即可。前面的lib和后缀名可以省略。然后调用native方法就可以了。
5B、Eclipse中配置了NDK坏境
在Android主目录下新建一个目录叫jni,建议取这个名字,方便理解,然后将.h文件.c文件和Android.mk文件拷贝至其中。
在Android工程的libs目录下新建一个目录armeabi,好!如果NDK环境是配置成功的,那么当你刷新工程或是clean工程之后,就会在libs/armeabi下生成libsign_dxd.so文件,当我run工程的时候,.so文件就自动编译到apk中了。关于Eclipse中NDK的配置网上教程很多,我现在用的是Eclipse(内置CDT) + NDK r7b,别忘了,当不能生成.so文件时,要去查看是否为该android工程指定了NDK环境。
关于NDK的配置,我抄了某网友的博文,大体如下:
1、下载NDK 后在你喜欢的目录解压它。
2、打开Eclipse,新建一个android工程我这里是TestNdk,并在这个工程主目录下新建一个jni目录,该目录时用来存放.h .c 和Android.mk文件的
3、在弹出的【Edit Configuration】对话框中,配置选项卡【Main】。
在“Name“中输入新builders的名称(我取名为Ndk_Builder)。
在“Location”中输入nkd-build.cmd的路径。
(我的是D:\AndroidDev\android-ndk-r7b\ndk-build.cmd,根据各自的ndk路径设置,也可以点击“Browser File System…”来选取这个路径)。
在“Working Diretcoty”中输入${workspace_loc:/TestNdk}(也可以点击“Browse Workspace”来选取TestNdk目录)。
4、【Edit Configuration】对话框中,配置选项卡【Refresh】。
勾选“Refresh resources upon completion”,
勾选“The entire workspace”,
勾选“Recuresively include sub-folders”。
5、【Edit Configuration】对话框中,配置选项卡【Build options】。
勾选“After a “Clean””,
勾选“During manual builds”,
勾选“During auto builds”,
勾选“Specify working set of relevant resources”。
6、点击“Specify Resources…”
勾选TestNdk工程,点击”finish“。
点击“OK“,完成配置。
OK,到这里Eclipse就能够自动调用NDK编译jin目录下的C/C++代码了。