前言
需求:需要在NDK层对一个Java层的字符串进行RSA加密,然后对加密的结果进行Base64返回到Java层
方案:选择使用OpenSSL来实现。
编译libssl.a和libcrypto.a静态库
在github上找到了一个项目,可以直接将OpenSSL编译成Android可以使用的,项目地址为
- openssl_for_ios_and_android ( https://github.com/leenjewel/openssl_for_ios_and_android )
但是这个项目有点小问题,部分编译脚本需要做点改动,改动后的项目见
- openssl_for_ios_and_android ( https://github.com/lizhangqu/openssl_for_ios_and_android )
主要做了3个改动:
- 将最低版本支持从Android 21改到了Android 14
- 修复一个armeabi-v7a无法编译出来的问题
- 升级了openssl的版本到openssl-1.1.0e
之后将项目clone下来,进入到tools目录,执行build-openssl4android.sh编译脚本
./build-openssl4android.sh android-armeabi armeabi-v7a
./build-openssl4android.sh android armeabi
这里只编译了armeabi-va7和armeabi架构CPU的so,如果有需要,请自行更改命令参数编译X86等架构的so。
经过很长时间的编译。。。大概要10来分钟吧。。。在根目录下的output会产生一个android目录,里面有openssl-armeabi和openssl-armeabi-v7a两个文件夹,包含了openssl的头文件以及编译好的.a静态库
实现JNI函数
编译好后.a静态库,就可以创建jni项目了
进入jni项目根目录,创建Application.mk文件
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-14
APP_OPTIM := release
APP_STL := c++_static
APP_THIN_ARCHIVE := true
APP_CPPFLAGS := -fpic -fexceptions -frtti
APP_GNUSTL_FORCE_CPP_FEATURES := pic exceptions rtti
进入jni项目根目录,创建Android.mk文件
LOCAL_PATH := $(call my-dir)
#引用libcrypto.a
include $(CLEAR_VARS)
LOCAL_MODULE := libcrypto
LOCAL_SRC_FILES := $(LOCAL_PATH)/openssl/$(TARGET_ARCH_ABI)/lib/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)
#引用libssl.a
include $(CLEAR_VARS)
LOCAL_MODULE := libssl
LOCAL_SRC_FILES := $(LOCAL_PATH)/openssl/$(TARGET_ARCH_ABI)/lib/libssl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := \
native.cpp \
LOCAL_C_INCLUDES :=$(LOCAL_PATH)/openssl/openssl-$(TARGET_ARCH_ABI)/include
TARGET_PLATFORM := android-14
#静态库依赖
LOCAL_STATIC_LIBRARIES := libssl libcrypto
LOCAL_LDLIBS += -latomic -lz -llog
include $(BUILD_SHARED_LIBRARY)
进入jni项目根目录,拷贝编译好的openssl文件
接着将第一步编译好的静态库文件进行拷贝,将output目录下android整个目录进行拷贝,拷贝到jni项目根目录下,拷贝完成后将android目录重命名为openssl
进入jni项目根目录,创建native.cpp,搭建基础的结构
#include "jni.h"
template<typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define NELEMS(x) (sizeof(ArraySizeHelper(x)))
#ifndef CLASSNAME
#define CLASSNAME "com/fucknmb/Test"
#endif
jstring native_rsa(JNIEnv *env, jobject thiz, jstring base64PublicKey, jstring content) {
return NULL;
}
static const JNINativeMethod sMethods[] = {
{
const_cast<char *>("native_rsa"),
const_cast<char *>("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
reinterpret_cast<void *>(native_rsa)
}
};
int registerNativeMethods(JNIEnv *env, const char *className, const JNINativeMethod *methods,
const int numMethods) {
jclass clazz = env->FindClass(class