对于MD5码,大家一定耳熟能详了,这里也不多做解释,由于在JDK中有相关封装,所以在java代码中很简单就可以获取,获取32位MD5如下:
public static String encrypt(String str) { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (Exception e) { e.printStackTrace(); return null; } char[] charArray = str.toCharArray(); byte[] byteArray = new byte[charArray.length]; for (int i = 0; i < charArray.length; i++) { byteArray[i] = (byte) charArray[i]; } byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); // 写法(1),忒不专业,不推荐//////////////////// // for (int i = 0; i < md5Bytes.length; i++) { // int val = ((int) md5Bytes[i]) & 0xff; // if (val < 16) { // hexValue.append("0"); // } // hexValue.append(Integer.toHexString(val)); // } // 写法(2)///////////////////////// // for (int i = 0; i < arr.length; ++i) { // sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1, // 3)); // } // 写法(3)///////////////////////////////////// // for (byte b : toencode) { // sb.append(Integer.toHexString((b & 0xf0) >>> 4)); // sb.append(Integer.toHexString(b & 0x0f)); // } // 写法(4) 封装好的格式化方法自有它的道理////////////////// for (int i = 0; i < md5Bytes.length; i++) { hexValue.append(String.format("%02x", ((int) md5Bytes[i]) & 0xff)); } return hexValue.toString(); }对于在代码里字符串的转换拼接过程,写法(1)网上疯传,但感觉好土,不建议大家使用,另外还有 写法(2)(3)(4),如果你是C转java的可能更习惯后面的,不纠结这个了,其实都可以,都列出来供大家参考吧。
既然java这么简单就可以获取md5码了,那干嘛还用jni调用C代码呢?这里只是把我在学习基于Android-NDK开发起步的一个小例子,大家就不要纠结这个了,就当做Hello-Jni吧
官方已经是r8e版本了,不过我没下载最新的,区别不大,对这个例子不会有影响。NDK全称:Native Development Kit,所以下载完就像对待sdk那样对待它就行了,找个目录解压,不过路径不要有中文和空格,不然日后会有麻烦,这个习惯一定要养成哦,前车之鉴。
我这里有精简的离线版20多M,有需要的可以联系我
由于我安装配置过程没有截图,详情参考:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/13/2136982.html
1.java代码中编写native 函数接口:
/** * getInfoMD5: native方法,在C代码里实现 */ public static native String getInfoMD5(String info);2.编译程序,确保bin目录已生成
3.打开cmd命令窗口,跳转到项目bin/classes目录下,使用 javah +包名+类名命令,回车,如无任何错误信息,则头文件生成成功。
4.项目中新建jni文件夹,打开classes目录找到.h文件复制进来,头文件格式如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_jerome_jni_JNIProcess */ #ifndef _Included_com_jerome_jni_JNIProcess #define _Included_com_jerome_jni_JNIProcess #ifdef __cplusplus extern "C" { #endif /* * Class: com_jerome_jni_JNIProcess * Method: getInfoMD5 * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_jerome_jni_JNIProcess_getInfoMD5 (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif
5.C编码对头文件中的方法进行实现
/* * Class: com_jerome_jni_JNIProcess * Method: getInfo * Signature: (Ljava/lang/String;I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_jerome_jni_JNIProcess_getInfoMD5(JNIEnv* env, jclass clazz, jstring jInfo) { char* jstr = Jstring2CStr(env, jInfo); MD5_CTX context = { 0 }; MD5Init(&context); MD5Update(&context, jstr, strlen(jstr)); unsigned char dest[16] = { 0 }; MD5Final(dest, &context); int i; char destination[32]={0}; for (i = 0; i < 16; i++) { sprintf(destination, "%s%02x", destination, dest[i]); } LOGI("%s", destination); return (*env)->NewStringUTF(env, destination); }
android.mk文件用于告知编译系统编译信息:
(1)Android.mk文件首先需要指定LOCAL_PATH变量,用于查找源文件。
由于一般情况下Android.mk和需要编译的源文件在同一目录下,所以定义成如下形式:
LOCAL_PATH:=$(call my-dir)
上面的语句的意思是将LOCAL_PATH变量定义成本文件所在目录路径。
(2)Android.mk中可以定义多个编译模块,每个编译模块都是以include $(CLEAR_VARS)开始
以include $(BUILD_XXX)结束。
include $(CLEAR_VARS)
CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除除LOCAL_PATH以外的所有LOCAL_XXX变量,
如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_SHARED_LIBRARIES,LOCAL_STATIC_LIBRARIES等。
include $(BUILD_STATIC_LIBRARY)表示编译成静态库
include $(BUILD_SHARED_LIBRARY)表示编译成动态库。
include $(BUILD_EXECUTABLE)表示编译成可执行程序
对于动态库静态库我的理解还很浅显,希望对这方面研究透彻的童鞋能给些指点。
makefile文件还有很多内容,后续继续研究分享
好了,一切准备完毕就可以编译了,打开cygwin cd到项目根目录(温馨提示:cygwin 中,我们的磁盘在 /cygdrive下),执行ndk-build(这里根据你配置的不同而不同,你或许要这样$NDK/ndk-build
),如果看到这样的结果,那恭喜你,编译成功!
函数调用跟普通函数相同,有个前提就是调用之前在类中或调用方法的Activity中先静态加载:
static { System.loadLibrary("process"); }library名称为你所实现接口的那个c文件的名称。