不同的 Android 设备使用不同的 CPU,而不同的 CPU 支持不同的指令集。CPU 与指令集的每种组合都有专属的应用二进制接口 (ABI)。ABI(Application binary interface)应用程序二进制接口。不同的 CPU 与指令集的每种组合都有定义的 ABI (应用程序二进制接口),一段程序只有遵循这个接口规范才能在该 CPU 上运行,所以同样的程序代码为了兼容多个不同的 CPU,需要为不同的 ABI 构建不同的库文件。当然对于 CPU 来说,不同的架构并不意味着一定互不兼容。
// Example of a call to a native method TextViewtv= binding.sampleText; tv.setText(stringFromJNI()); }
/** * A native method that is implemented by the 'myso' native library, * which is packaged with this application. */ publicnative String stringFromJNI(); //native 函数的声明 }
so 库需要在运行时调用 System.loadLibrary(…) 加载,一般有 2 种调用时机:
1、在类静态初始化中: 如果只在一个类或者很少类中使用到该 so 库,则最常见的方式是在类的静态初始化块中调用;
2、在 Application 初始化时调用: 如果有很多类需要使用到该 so 库,则可以考虑在 Application 初始化等场景中提前加载。
native-lib.cpp JNI 函数的静态注册规则
1 2 3 4 5 6 7 8 9 10
#include<jni.h> #include<string>
extern"C"JNIEXPORT jstring JNICALL Java_com_example_myso_MainActivity_stringFromJNI( JNIEnv* env, jobject /* this */){ std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); }
extern "C":指定 C++ 代码使用 C 风格的链接,以避免 C++ 名称修饰(name mangling),确保 Java 可以找到这个函数。
JNIEXPORT 和 JNICALL:是宏定义,用于指示 JNI 的函数返回类型和调用约定。表示一个函数需要暴露给共享库外部使用时。 在 Window 和 Linux 上有不同的定义
1 2 3 4 5 6 7 8 9 10 11 12 13
// Windows 平台 : #define JNIEXPORT __declspec(dllexport) #define JNIIMPORT __declspec(dllimport)
// Linux 平台: #define JNIIMPORT #define JNIEXPORT __attribute__((visibility ("default")))
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html. # For more examples on how to use CMake, see https://github.com/android/ndk-samples. # Sets the minimum CMake version required for this project. //这些注释提供了有关如何在 Android Studio 中使用 CMake 的文档链接和示例,供开发者参考。 cmake_minimum_required(VERSION 3.22.1) //该行指定此项目所需的最低 CMake 版本。确保使用的 CMake 版本符合要求。 # Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, # Since this is the top level CMakeLists.txt, the project name is also accessible # with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level # build script scope). project("myso") //这里声明了项目的名称为 "myso",在整个 CMake 文件中,可以通过 ${PROJECT_NAME} 和 ${CMAKE_PROJECT_NAME} 访问这个名称。 # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. # # In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define # the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME} # is preferred for the same purpose. # # In order to load a library into your app from Java/Kotlin, you must call # System.loadLibrary() and pass the name of the library defined here; # for GameActivity/NativeActivity derived applications, the same library name must be # used in the AndroidManifest.xml file. add_library(${CMAKE_PROJECT_NAME} SHARED # List C/C++ source files with relative paths to this CMakeLists.txt. native-lib.cpp) //add_library 创建一个名为 ${CMAKE_PROJECT_NAME} 的库(在这里是 " myso "),并指定为共享库(SHARED)。这表示生成的库可以被其他应用程序共享使用。 //native-lib.cpp 是要编译的源文件,使用相对路径引用。 # Specifies libraries CMake should link to your target library. You # can link libraries from various origins, such as libraries defined in this # build script, prebuilt third-party libraries, or Android system libraries. target_link_libraries(${CMAKE_PROJECT_NAME} # List libraries link to the target library android log) //这一部分指定了要链接到目标库的其他库,包括 Android 系统库 android 和 log。这些库通常用于 Android 开发中的日志记录和其他系统功能。
# 编译出一个动态库 native-lib,源文件只有 src/main/cpp/native-lib.cpp add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp )
# 找到预编译库 log_lib 并link到我们的动态库 native-lib中 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. native-lib # Links the target library to the log library # included in the NDK. ${log-lib} )
functionhook_native(){ var libnative_addr = Module.findBaseAddress('libnative-lib.so');//so 文件名 console.log("libnative_addr is => ",libnative_addr) var stringfromJNI3 = libnative_addr.add(0xf454);//hook 的函数地址 baseadress+偏移 console.log("stringfromJNI3 address is =>",stringfromJNI3);
var stringfromJNI3_2 = Module.findExportByName('libnative-lib.so', "_Z14stringFromJNI3P7_JNIEnvP7_jclassP8_jstring") console.log("stringfromJNI3_2 address is =>",stringfromJNI3_2);