Skip to content

Sogrey/AndroidJniMD5

Repository files navigation

title date tags categories comments toc
JNI Md5加密生成so文件
2018-07-25 13:39:13 -0700
JNI
Md5
JNI
true
true

JNI Md5加密生成so文件

Codacy Badge CodeFactor

IDE工具:Android Studio 编译环境:JDK1.8+Android SDK+NDK

1 新建项目

选中“Include C++ support”,一直“Next”.

等待项目构建完成后

看到 java包同级有个cpp的包就是存放c++代码的。

而里native-lib.cpp的代码很简单,就是打印出一句“Hello from C++”:

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring

JNICALL
Java_sogrey_android_1jni_1md5_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

运行一下:

这就表示我们的C++环境正常,可以开始写我们自己的代码了。

2 新建Jni工具类

新建一个JNIUtils.java

package sogrey.android_jni_md5;

/**
 * Created by Sogrey on 2018/8/3.
 */

public class JNIUtils {
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

MainActivity.java中的相关代码删掉

tv.setText(stringFromJNI());

也改成

tv.setText(new JNIUtils().stringFromJNI());

3 生成.h文件,编写cpp文件

Android studio的Terminal中依次执行命令:

cd app/src/main/java javah -jni sogrey.android_jni_md5.JNIUtils

将生成的sogrey_android_jni_md5_JNIUtils.h头文件剪贴到cpp包下,并复制一份重命名为sogrey_android_jni_md5_JNIUtils.cpp.

编辑复制的.cpp文件,删掉多余代码只留下需要我们实现的那个方法,加上返回方法体,并导入之前的.h文件

#include "sogrey_android_jni_md5_JNIUtils.h"
/*
 * Class:     sogrey_android_jni_md5_JNIUtils
 * Method:    stringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_sogrey_android_1jni_1md5_JNIUtils_stringFromJNI
        (JNIEnv *env, jobject obj){
}

方法需要返回jstring,可以参照之前native-lib.cpp里的代码实现,引入提示需要导入string:

#include <string>

则最终代码就是:

#include <string>
#include "sogrey_android_jni_md5_JNIUtils.h"
/*
 * Class:     sogrey_android_jni_md5_JNIUtils
 * Method:    stringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_sogrey_android_1jni_1md5_JNIUtils_stringFromJNI
        (JNIEnv *env, jobject obj){
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

4 修改CMakeLists.txt文件

我们刚刚添加了一个新的c++文件,现将它加到CMakeLists中,刚才的native-lib.cpp已经没有用了,注掉它

重新编译运行看会不会得到和之前一样的结果。(结果是一样的) 在build>intermediates>cmake>debug>obj下就能找到生成的.so文件了

5 添加getMd5(String)的native方法

JNIUtils.java中添加下面native方法:

    /**
     * 获取指定字符串md5值
     * @param content 要md5加密的字符串
     * @return md5加密串
     */
    public native String getMd5(String content);

重复第三步操作。或者熟练了直接在sogrey_android_jni_md5_JNIUtils.h文件中添加:

/*
 * Class:     sogrey_android_jni_md5_JNIUtils
 * Method:    getMd5
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_sogrey_android_1jni_1md5_JNIUtils_getMd5
        (JNIEnv *, jobject, jstring);

同样,需要在sogrey_android_jni_md5_JNIUtils.cpp中去实现它:

/*
 * Class:     sogrey_android_jni_md5_JNIUtils
 * Method:    getMd5
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_sogrey_android_1jni_1md5_JNIUtils_getMd5
        (JNIEnv *env, jobject obj, jstring str){
    //TODO 实现方法逻辑
}

6 实现MD5加密

md5的加密方法网上很多,这里给出一个c++实现的[MD5.cpp,MD5.h].直接将两个文件引入到cpp包下, 在sogrey_android_jni_md5_JNIUtils.cpp引入

#include "MD5.h"

getMD5方法实现:

/*
 * Class:     sogrey_android_jni_md5_JNIUtils
 * Method:    getMd5
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_sogrey_android_1jni_1md5_JNIUtils_getMd5
        (JNIEnv *env, jobject obj, jstring str) {
    const char *originStr;
    //将jstring转化成char *类型
    originStr = env->GetStringUTFChars(str,JNI_FALSE);
    MD5 md5 = MD5(originStr);
    std::string md5Result = md5.hexdigest();
//    //将char *类型转化成jstring返回给Java层
    return env->NewStringUTF(md5Result.c_str());
}

其中:JNI_FALSE 是个宏定义表示 jboolean false

#define JNI_FALSE 0
#define JNI_TRUE 1

运行一把,得到md5字符串

7 生成.so文件

在cmake.txt中添加

#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})

用来指定生成的so文件存储路径,点击build>Make project,看到在jniLibs文件夹下生成支持4中不同内核的so文件。

想要配置指定内核平台,修改Module下的build.gradle中的android>defaultConfig 添加:

externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters "arm64-v8a","armeabi-v7a","x86","x86_64"
//Error:ABIs [armeabi] are not supported for platform. Supported ABIs are [armeabi-v7a, arm64-v8a, x86, x86_64].
            }
        }

8 修改库名称

默认生成的so库名称是native-lib,怎么修改为自定义的名称呢。

首先,修改CMakeLists.txt内容:修改add_librarytarget_link_libraries第一个参数为我们想自定定义的名称,比如md5Lib

同样需要修改JNIUtils.javaSystem.loadLibrary(String)的参数为上面我们自定义的名称md5Lib

重新点击build>Make project,看到在jniLibs文件夹下生成新的so文件。

项目源码地址github