IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Android JNI使用

    FranzKafka95发表于 2023-06-27 12:59:25
    love 0
    Read Time:2 Minute, 21 Second

    经常做Android开发的朋友不可避免地会接触到一个词:JNI,其英文全称为Java-Native Interface,JNI的作用即在于通过JNI可以让我们从Java代码调用到C++代码。

    一般我们在开发APP时,由于Framework层没有对应的框架实现,可能需要调用C/C++编写的代码,或者是出于安全需要将核心代码使用C/C++编写,进而通过JNI来调用。

    使用JNI需要提前配置NDK,因为C++代码依赖于NDK环境。在AndroidStudio中配置NDK时首先需要通过File->Settings->System Settings->Android SDK->SDK Tools内选择NDK进行下载,并通过File->Project Structure->Android NDK location配置其路径。

    AndroidStudio中配置使用JNI大致可遵循如下步骤:

    1.在app/src/main目录下创建cpp目录,并添加CMakeLists.txt,其内容大致如下:

    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
     
    # Sets the minimum version of CMake required to build the native library.
    # 设置cmake 的最小版本  一般系统自动生成
    cmake_minimum_required(VERSION 3.4.1)
     
    # 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.
    #设定目标产物类型、名称、源码等信息
    add_library( # Sets the name of the library.
                 # 设置生成.so 的文件名,最终产物为libnative-lib.so
                 native-lib
                 # Sets the library as a shared library.
                 #设置库的类型  一种静态文件  STATIC .a   一种动态文件  SHARED .so
                 SHARED
                 # Provides a relative path to your source file(s).
                 # 需要编译的c/c++ 文件,以CMakeLists.txt所在目录为基准的相对目录
                 src/main/cpp/main.cpp )
    
    # Searches for a specified prebuilt library and stores the path as a
    # variable. Because CMake includes system libraries in the search path by
    # default, you only need to specify the name of the public NDK library
    # you want to add. CMake verifies that the library exists before
    # completing its build.
    # 依赖的NDK第三方库--
    find_library( # Sets the name of the path variable.
                  dependencies-lib
                  # Specifies the name of the NDK library that
                  # you want CMake to locate.
                  EGL, #依赖libEGL.so
                  nativehelper #依赖libnativehelper.so
                  log )#依赖liblog.so
     
    # Specifies libraries CMake should link to your target library. You
    # can link multiple libraries, such as libraries you define in this
    # build script, prebuilt third-party libraries, or system libraries.
     
    target_link_libraries( # Specifies the target library.
                           # 指定链接的目标库
                           native-lib
     
                           # Links the target library to the log library
                           # included in the NDK.
                           ${dependencies-lib } )

    关于CMake的更多使用信息,可以参考我的这篇博客。

    2.在app/build.gradle中将gradle与cmake进行关联,如下所示:

    android {
       defaultConfig {
    	externalNativeBuild{
          cmake{
    	  cflags “_D”
    	  cppflags “-frtti”,”-fexceptions”
    	  abiFilters ‘x86’,’x86_64’,’armabi’,’armeabi-v7a’,’arm64-v8a’
          }
       }
        .......
        externalNativeBuild {
            cmake {
    	    //通过path关键字指定CMakeLists.txt路径
    	    //该路径是是以build.gradle为基准的相对路径
                path "CMakeLists.txt"
            }
        }
    }

    3.添加关键代码,关键代码的添加分为两部分,一部分是C/C++代码,另外一部分是Java代码。

    首先是Java代码,包括加载JNI库,同时声明native 函数。如下示例:

    //here we will load jni library
    static {
         System.loadLibrary("natiave-lib"); //该名称对应cmake中的add_library所添加的库名
    }
    // Native method declaration
    private native boolean nUpdateTexture(HardwareBuffer buffer, int textureId);

    然后我们需要编写C/C++代码:

    //必须要引用jni.h头文件
    #include <jni.h>
    
    //此外有两个重要的函数JNI_OnLoad、JNI_OnUnload是需要去完成的
    //当native library被加载时(如调用System.loadLibrary),JAVA VM将会调用JNI_Onload,返回JNI版本
    JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
    
    }
    
    //当JAVA类加载器发生GC时,该函数将会被JAVA VM进行调用。通常该函数将用于清理工作。
    JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* /*reserved*/) {
    
    }

    此外我们还需要了解一下JNI中的数据类型,以便将Java中的数据类型与native原生类型做匹配:

    Java TypeNative TypeDescription
    booleanjbooleanunsigned 8 bits
    bytejbytesigned 8 bits
    charjcharunsigned 16 bits
    shortjshortsigned 16 bits
    intjintsigned 32 bits
    longjlongsigned 64 bits
    floatjfloat32 bits
    doublejdouble64 bits
    voidvoidN/A

    除了原生数据类型,JNI中也存在与Java中对应的复合类型,其对应关系如下:

    Java Type Native Type
    java.lang.Classjclass
    java.lang.Stringjstring
    arraysjarray
    java.lang.Throwablejthrowable

    在编写完相关代码后,在Androud Studio中你可以在Build窗口中查看编译相关的报错信息;如果你需要更准确地获取C/C++相关的诊断信息,可以在app/.cxx目录下找到更多的有效信息,如CMakeCache.txt等。

    Happy
    Happy
    1 100 %
    Sad
    Sad
    0 0 %
    Excited
    Excited
    0 0 %
    Sleepy
    Sleepy
    0 0 %
    Angry
    Angry
    0 0 %
    Surprise
    Surprise
    0 0 %

    The post Android JNI使用 first appeared on FranzKafka Blog.



沪ICP备19023445号-2号
友情链接