思考:把Android里的关键逻辑下沉到Native。比如核心、敏感、或者性能要求高的逻辑,从Java/Kotlin层挪到C/C++(so 库)里,通过JNI去调用。
- 提高了逆向成本(防破解、防篡改)
- 提升了性能(某些计算密集型场景)
- 隔离了关键算法(让 Java 层变成“壳”)
一、JNI的使用
- 配置NDK + CMake (Android Studio 里 SDK Tools 勾选 NDK、CMake)
2. 构建cpp目录
app/src/main/cpp/
├── CMakeLists.txt
└── native-lib.cpp
3. 构建 CMakeLists.txt
cmake_minimum_required(VERSION 3.22.1)
project("yinyin-lib") # 库名,对应 System.loadLibrary("yinyin-lib")
add_library(
${CMAKE_PROJECT_NAME}
SHARED
native-lib.cpp # 源码路径
)
find_library(
log-lib
log
)
target_link_libraries(
${CMAKE_PROJECT_NAME}
${log-lib}
)
4. 构建 native-lib.cpp
#include <jni.h>
#include <string>
// extern "C" 防止 C++ 名字被改编
extern "C" {
// ==================== 示例 1:无参数,返回 String ====================
JNIEXPORT jstring JNICALL
Java_com_example_use_1jni_1and_1so_MainActivity_helloJNI(JNIEnv* env, jobject thiz) {
std::string result = "Hello from C++";
return env->NewStringUTF(result.c_str());
}
// ==================== 示例 2:带参数,返回 int ====================
JNIEXPORT jint JNICALL
Java_com_example_use_1jni_1and_1so_MainActivity_addNumbers(JNIEnv* env, jobject thiz, jint a, jint b) {
return a + b;
}
// ==================== 示例 3:带 String 参数,返回 String ====================
JNIEXPORT jstring JNICALL
Java_com_example_use_1jni_1and_1so_MainActivity_reverseString(JNIEnv* env, jobject thiz, jstring input) {
const char* str = env->GetStringUTFChars(input, 0); //java string 转 c string
std::string s(str); // c string 转 c++ string
env->ReleaseStringUTFChars(input, str); // 释放 c string. 参数1:原始的 jstring,参数2:要释放的 C 字符串指针
std::reverse(s.begin(), s.end()); // 翻转string,并将值赋予s
return env->NewStringUTF(s.c_str()); // 创建新的java string并返回
}
} // extern "C"
5. 配置build.gradle中的NDK和CMake
ndk
android{
defaultConfig{
ndk {
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
}
}
}
cmake
android{
defaultConfig{
externalNativeBuild {
cmake {
cppFlags += ""
}
}
}
}
android {
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
}
}
}
- 再写 Kotlin external 接口 举个栗子
init {
System.loadLibrary("yinyin-lib")
}
external fun hello(): String
业务层调用hello()
此时已经跑通了~
Gradle → CMake → so → JVM → JNI → C++
- 再开始写真正的业务 JNI 接口 native-lib.cpp
举个栗子:校验、算法、加密、核心逻辑。
此时只是: 把 C++ 的实现变复杂, Kotlin 侧只改方法声明。
- 最后才是“业务层设计”
举个栗子
object NativeBridge {
external fun checkLicense(key: String): Boolean
}
JNI小结:
- NDK / CMake 环境 ↓
- CMakeLists.txt ↓
- native-lib.cpp(最小可运行函数) ↓
- System.loadLibrary ↓
- external fun ↓
- JNI 能跑通 ↓
- 扩展为真实业务
二、so的生成与使用
生成so:
- 配置完CMake会编译生成出来so。
- run只会生成当前设备ABI的so
- Build APK(s)或 assembleDebug 会生成所有ABI的so
- 生成的so位置在:\build\intermediates\cxx 或者 \build\intermediates\merged_native_libs\debug\mergeDebugNativeLibs\out\lib
使用so:
- 创建jniLibs。
app/
└── src/
└── main/
└── jniLibs
- 放置so库,目录结构如下:
app/
└── src/
└── main/
└── jniLibs/
├── arm64-v8a/
│ └── libyinyin-lib.so
├── armeabi-v7a/
│ └── libyinyin-lib.so
├── x86/
│ └── libyinyin-lib.so
└── x86_64/
└── libyinyin-lib.so
- 模块build.gradle配置jniLibs。
android {
sourceSets {
getByName("main") {
jniLibs.srcDirs("src/main/jniLibs")
}
}
}
- 业务层调用。
加载so库到进程中->配置方法->调用方法。 举个栗子:
System.loadLibrary("yinyin-lib")
external fun helloJNI(): String?