Android-通过JNI和NDK生成so库
2022-06-05 本文已影响0人
超人TIGA
正在工作时,突然被同事问到:“秘钥放在哪里比较安全,X总说我这样写不行。”
其实很多时候,app都需要用到一些敏感的数据,例如加密的秘钥、一些渠道的APP_ID等,但如果被别人反编译拿到这些数据,就很有可能会造成损失。
那怎么增加被获取的难度?就是将这些数据放到C/C++的文件内,然后将其生成为so库,交给app应用层去调用。因为C/C++反汇编的难度,怎么都比反编译一个apk要难,这样就能更加有效地保证敏感数据的安全了。
一、工具准备
下载AndroidStudio,并确保下载好了NDK和CMake。 image.png二、新建一个项目
普通项目也行,C++项目也行,由于C++项目会自动配置CMakeList文件,所以我这里直接创建C++项目了。 image.png三、编写JNI工具类
创建一个Java类,并在内部定义你需要的方法。
image.png
public class MyJavaJNI {
static {
System.loadLibrary("JniTest");
}
public native String getKeyStr();
}
四、将工具类编译为class文件
首先,在Android Studio中打开terminal,在这里打开的,其实就是终端,并不需要管环境配置,因为Android Studio其实已经都关联好了。 image.png然后,跳转到工具类所在的目录,并编译文件,之后再返回到java目录。
cd com/cjy/solibrarydemo
javac MyJavaJNI.java
cd..
cd..
cd..
最后,通过命令javah -jni com.cjy.solibrarydemo.MyJavaJNI生成C文件。完成后,你会看到跟下图差不多的文件结构。
image.png
五、创建JNI文件夹,并且把第四步中的C文件放进去。
右键app项目,new出JNI文件夹。 image.png 将C文件放进去,并将后缀名改为.c。 image.png六、修改CMakeList文件并编写方法。
CMakeLists.txt
cmake_minimum_required(VERSION 3.18.1)
set(srcDir ${CMAKE_SOURCE_DIR}/../..)
project("solibrarydemo")
add_library(
javaJni
SHARED
${srcDir}/main/jni/com_cjy_solibrarydemo_MyJavaJNI.c
)
add_library( # Sets the name of the library.
solibrarydemo
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
target_link_libraries( # Specifies the target library.
solibrarydemo
javaJni
# Links the target library to the log library
# included in the NDK.
${log-lib})
com_cjy_solibrarydemo_MyJavaJNI.c
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_cjy_solibrarydemo_MyJavaJNI */
#ifndef _Included_com_cjy_solibrarydemo_MyJavaJNI
#define _Included_com_cjy_solibrarydemo_MyJavaJNI
#define keyStr "123456789"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_cjy_solibrarydemo_MyJavaJNI
* Method: getKeyStr
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring
JNICALL Java_com_cjy_solibrarydemo_MyJavaJNI_getKeyStr
(JNIEnv *env, jclass objt){
return (*env)->NewStringUTF(env,keyStr);
};
#ifdef __cplusplus
}
#endif
#endif
七、生成so库
先配置你需要生成的CPU架构,在build.gradle中增加配置项。
externalNativeBuild {
cmake {
cppFlags ''
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
开始生成so库。
image.png 查看结果: image.png 这里的libjavaJni.so,就是我们需要的so库了。
八、使用so库
一般的情况下,都是自己的项目,那使用的做法就很简单,将所有架构的so文件,复制到libs文件夹中,然后在你需要调用方法的地方直接调用就行了。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Example of a call to a native method
binding.sampleText.text = MyJavaJNI.getKeyStr()
}
但是如果是需要提供给别人用的,那就不能这样了。因为别人复制了你的so文件之余,还需要新建工具类的全路径,一模一样的那种,再复制工具类(MyJavaJNI.java)进去,才能正常使用。
这时候我们应该将工具类打包成aar或者jar文件,一起提供给别人使用,这样别人就不用那么麻烦了。