实用

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文件,一起提供给别人使用,这样别人就不用那么麻烦了。

上一篇下一篇

猜你喜欢

热点阅读