jni简介及openSSL静态动态编译
jni的定义
即java native interface,提供了若干api实现了java和其他语言的通信(c & c++)。
jni的优点及缺点
优点
- 可以使用标准java api不能提供的功能,比如DICOM(医学数字成像和通信)。
- 保护核心代码,c/c++的库反汇的难度较大,可以将加密key,或者重要的字符串信息之类的。
- 便于移植,用c/c++写的库文件可以方便的在嵌入式平台上再次使用。类似与cocos2d-x,只需要编写一次代码,经过不同开发平台编译之后可以在android,ios,pc上面运行。
缺点
- 一旦使用jni,程序不再垮平台,需要在不同的系统环境下重新编译(arm,arm64,x86,mips等不同cpu架构都需要重新编译)
- 程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,应该让本地方法集中在少数几个类中。这样就降低了java和c之间的耦合性。
ndk
native development kit,是一系列工具的集合,帮助开发者快速开发C(c++)的动态库,并能自动将so和java应用一起打包成apk。NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件,就可以创建出so。
C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)
cpu7种架构:armeabi,armeabi-v7a,x86,mips,arm64- v8a,mips64,x86_64
android不同版本相关:
5.0中ndk支持64位
6.0中需要静态编译openssl库(正在讲OpenSSL替换为BoringSSL)
7.0中直接不允许调用非公有的api
ndk环境配置及openssl静态编译及动态编译介绍
下载ndk(android-ndk-r10),并配置ndk的环境变量。
windows环境下配置ndk变量与配置java和android环境变量相同。
动态编译直接通过cmd命令行执行ndk-build来运行。
静态编译通过windows编译的话经常报一些包找不到等错误。
下载cygwin(模拟Linux环境,其实开发ndk只需要上面的ndk环境即可正常开发,需要cygwin的原因是ndk在windows环境上面经常出问题,交叉编译各种bug)。
配置cygwin的注意事项:
1.安装的时候记得勾选shell 和devel
2.配置环境变量:
2.1 配置cygwin中的ndk环境变量(不用配置也行):
在etc目录下的profile下配置如下:
PATH="/usr/local/bin:/usr/bin:${PATH}/cygdrive/d/android-ndk-r11c:${PATH}"
2.2 配置ndk-build的指令:
在home中的user(根据电脑用户名不一样而改变)下的.bash_profile中配置如下:
export NDK_BUILD=/cygdrive/d/android-ndk-r10/ndk-build(要注意等号左右不能带空格)
openssl的动态编译库的编译(需要so):
编译所需要的so文件:
第一种方法(自己编译):
- 下载github上面的官方的开源项目openssl
- 配置android脚本,脚本地址
- 具体配置方法
-
注意:cygwin用此种方法编译的话,则需要在安装的时候配置wget,make(Devel目录下)等一系列命令。
如果不想重新安装cygwin则可以利用apt-cyg命令(http://blog.youkuaiyun.com/forlong401/article/details/8517711).
第二种方法:
动态编译的步骤(eclipse):
- 在eclipse上面建立一个新的项目。或者在原有项目中也可。
- 将自己写的.c和.h以及android.mk,Application.mk放入jni目录中
- 得到so文件之后,将其放入ndk中对应的android版本平台里面(eg: android-ndk-r10/platforms/android-19)中,并根据不同平台将libcrypto和libssl的so分别放入到对应的lib中。
- 将openssl的头文件放入项目中,具体的放置的路径可以配置(openssl项目中有include目录下)
- 配置android.mk,Application.mk文件
- cd 到工程目录
- 执行ndk-build命令(如果在cygwin中执行配置了命令,则根据自己配置的命令执行,如$NDK_BUILD)
得到动态编译的so文件。
注意事项:
写的.c文件中的包名要跟自己调用的方法的包名一样。
eg: 假设我要编译一个用openssl的so,so的名称为zty
则android.mk配置可以写成:
#即jni目录下面一层的路径
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := zty
#openssl的头文件放置的目录
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../openssl/include
#log包
LOCAL_LDLIBS += -lcrypto -lssl -llog
LOCAL_SRC_FILES += encryptkey.c base64.c
include $(BUILD_SHARED_LIBRARY)
Application.mk配置主要写编译平台和版本,但是基本不用写版本,只需要写平台即可.
eg:
APP_ABI := armeabi armeabi-v7a x86 mips
APP_ABI := alll 表示所有平台都支持
openssl静态编译则需要(libcrypto.a,libssl.a):
android6.0之后必须要静态编译openssl库,不然会crash。
编译静态编译需要的.a文件:
第一种方法(自己编译):
- 配置android脚本步骤同动态编译
- 可以利用github上面有的项目OpenSSL1.0.1cForAndroid
- 修改crypto文件夹下的Android.mk文件, 在#target对应的include修改
include$(BUILD_SHARED_LIBRARY)------->include $(BUILD_STATIC_LIBRARY)
- 修改ssl文件夹下的Android.mk文件,在#target对应的include修改
include$(BUILD_SHARED_LIBRARY)------->include $(BUILD_STATIC_LIBRARY)
- 修改apps文件夹下的Android.mk文件,添加 LOCAL_LDLIBS += -lz
- cd 到工程目录
- 执行命令ndk-build(同样是在application中配置平台)
- 在工程目录的obj文件夹下可以找到 libcrypto.a,libssl.a
第二种方法(直接下载):
静态编译的步骤(eclipse):
- 在eclipse上面建立一个新的项目。或者在原有项目中也可。
- 将自己写的.c和.h以及android.mk,Application.mk放入jni目录中
- 将得到的.a文件按平台目录不同分别放在自己项目的jni目录下。
- 将openssl的头文件放入项目中,具体的放置的路径可以配置(openssl项目中有include目录下)
- 配置android.mk,Application.mk文件
- cd 到工程目录
- 执行ndk-build命令(如果在cygwin中执行配置了命令,则根据自己配置的命令执行,如$NDK_BUILD)
- 得到静态编译的so文件。
eg: 假设我要编译一个用openssl的so,so的名称为zty
则android.mk配置可以写成:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcrypto
LOCAL_SRC_FILES := libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libssl
LOCAL_SRC_FILES := libssl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := zty
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../openssl/include
#调用静态库
LOCAL_STATIC_LIBRARIES += libcrypto libssl
LOCAL_LDLIBS += -llog
LOCAL_SRC_FILES += encryptkey.c base64.c
include $(BUILD_SHARED_LIBRARY)