Androdi

    xiaoxiao2021-03-25  169

    作为一个菜鸟,一直没有接触和学习NDK,和JNI方面的知识,趁着最近项目不是很赶,来了解一下,共勉。

    JNI:Java Native Interface(Java 本地接口),它是为了方便Java调用C、C++等本地代码所封装的一层接口。

    NDK:Native Development Kit(本地开发工具包),通过NDK可以在Android中更加方便的通过JNI来访问本地代码。

    创建支持 C/C++ 的新项目

    下载 NDK 和构建工具

    只需要在创建的时候,在 Configure your new project 选项中,勾选 Include C++ Support 选项。其他的自己体会

    将 C/C++ 代码添加到现有的项目中

    如果你想将 native code 添加到一个现有的项目中,请按照下面的步骤操作:

    创建新的 native source 文件,并将其添加到你的 Android Studio 项目中。如果你已经有了 native code,也可以跳过这一步。

    创建一个 CMake 构建脚本。如果你已经有了一个 CMakeLists.txt 构建脚本,或者你想使用 ndk-build 然后有一个 Android.mk 构建脚本,也可以跳过这一步。

    将你的 native library 与 Gradle 关联起来。Gradle 使用构建脚本将源码导入到你的 Android Studio 项目中,并且将你的 native library (也就是 .so 文件)打包到 APK 中。

    一旦你配置好了项目,你就可以在 Java 代码中,使用 JNI 框架开调用原生函数(native functions)。只需要点击 Run 按钮,就可以编译运行你的 APP 了。

    创建新的 native source 文件

    请按照下面的方法来创建一个 cpp/ 目录和源文件(native source files):

    打开IDE左边的 Project 面板,选择 Project 视图。找到你项目的 module > src 目录,右键点击 main 目录,选择 New > Directory。输入目录的名字(比如 cpp),然后点击 OK。右键点击刚才创建好的目录,选择 New > C/C++ Source File。输入文件名,比如 native-lib。在 Type 菜单下拉选项中,选择源文件的扩展后缀名,比如 .cpp。如果你也想创建一个头文件,点击 Create an associated header 选项框。点击 OK。

    创建 CMake 构建脚本

    现在,你可以添加 CMake 命令来配置你的构建脚本了。为了让 CMake 将源代码(native source code)编译成 native library。需要在编译文件中添加 cmake_minimum_required() 和 add_library() 命令:

    # Sets the minimum version of CMake required to build your native library. # This ensures that a certain set of CMake features is available to # your build. cmake_minimum_required(VERSION 3.4.1) # Specifies a library name, specifies whether the library is STATIC or # SHARED, and provides relative paths to the source code. You can # define multiple libraries by adding multiple add.library() commands, # and CMake builds them for you. When you build your app, Gradle # automatically packages shared libraries with your APK. add_library( # Specifies 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 ) #然而,为了让 CMake 在编译时期能定位到你的头文件,你需要在 CMake 构建脚本中添加 include_directories() # Specifies a path to native header files. include_directories(src/main/cpp/include/)

    生成的.so文件为 lib[name].so,在加载到java中的时候,只需要name就可以了,如下。

    static { System.loadLibrary(“native-lib”); }

    注意:如果你将 CMake 脚本里面的 library 重命名了,或者移除了。你需要清理一下你的工程。在 IDE 的菜单栏中选择 Build > Clean Project。

    添加 NDK APIs

    Android NDK 提供了一些有用的 native APIs。将 NDK librarys 添加到 CMakeLists.txt 脚本文件中,就可以使用这些 API 了。

    NDK中的libary有一部分预编译过了

    预编译的 NDK librarys 已经存在在 Android 平台中了,所以你不需要编译它们,或者是将其打包到你的 APK 中。因为这些 NDK librarys 已经是 CMake 搜索路径的一部分,你甚至不需要提供你本地安装的 NDK 路径。你只需要向 CMake 提供你想使用的 library 名字。

    将 find_library() 命令添加到你的 CMake 构建脚本中,这样就可以定位 NDK library 的位置,并将其位置存储在一个变量之中。你可以在构建脚本的其他地方使用这个变量,来代指 NDK library。下面的示例代码将 Android-specific log support library 的位置存储到变量 log-lib 中:

    find_library( # Defines the name of the path variable that stores the # location of the NDK library. log-lib # Specifies the name of the NDK library that # CMake needs to locate. log ) NDK 同样也包含一些只包含源码的 library //下面的命令告诉 CMake 去构建 android_native_app_glue.c,这个命令可以管理 NativeActivity 的生命周期以及点击输入,并将其导入静态库中,然后将其链接至 native-lib: add_library( app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in the # build script, prebuilt third-party libraries, or system libraries. # You need to link static libraries against your shared native library. target_link_libraries( native-lib app-glue ${log-lib} )

    添加其他的预编译库

    添加预编译库和添加本地库(native library)类似。由于预编译库是已经构建好的,你想就要使用 IMPORTED 标志去告诉 CMake ,你只需要将其导入到你的项目中即可:

    add_library( imported-lib SHARED IMPORTED )

    然后你需要使用 set_target_properties() 命令去指定库的路径,就像下面的代码那样。

    一些库会根据不同的 CPU 使用不同的包,或者是 Application Binary Interfaces(ABI),并且将他们归类到不同的目录中。这样做的好处是,可以充分发挥特定的 CPU 架构。你可以使用 ANDROID_ABI 路径变量,将多个 ABI 版本的库添加到你的 CMake 构建脚本中。这个变量使用了一些 NDK 默认支持的 ABI,以及一些需要手动配置到 Gradle 的 ABI,比如:

    add_library(...) set_target_properties( # Specifies the target library. imported-lib # Specifies the parameter you want to define. PROPERTIES IMPORTED_LOCATION # Provides the path to the library you want to import. #指定路径 imported-lib/src/${ANDROID_ABI}/libimported-lib.so )

    为了让 CMake 在编译时期能找到你的头文件,你需要使用 include_directories() 命令,并且将你的头文件地址传进去:

    include_directories( imported-lib/include/ )

    在 CMake 构建脚本中使用 target_link_libraries() 命令,将预构建库与你本地库相关联:

    target_link_libraries( native-lib imported-lib app-glue ${log-lib} )

    当你构建你的 APP 的时候,Gradle 会自动将导入的库打包到你的 APK 中。你可以使用 APK Analyzer 来检查。

    关联本地库与 Gradle

    右键点击你想链接本地库的 module,比如 app module,然后从菜单中选择 Link C++ Project with Gradle

    手动配置 Gradle

    如果要手动将 Gradle 与你的本地库相关联,你需要在 module 层级的 build.gradle 文件中添加 externalNativeBuild {} 代码块,并且在该代码块中配置 cmake {} 或 ndkBuild {}:

    指定 ABI

    一般情况下,Gradle 会将你的本地库构建成 .so 文件,然后将其打包到你的 APK 中。如果你想 Gradle 构建并打包某个特定的 ABI 。你可以在你的 module 层级的 build.gradle 文件中使用 ndk.abiFilters 标签来指定他们:

    android { ... defaultConfig { ... externalNativeBuild { cmake {...} // or ndkBuild {...} } ndk { // Specifies the ABI configurations of your native // libraries Gradle should build and package with your APK. abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a' } } buildTypes {...} externalNativeBuild {...} }

    如果你想控制 Gradle 构建、依赖你希望的东西,你就需要在 defaultConfig.externalNativeBuild.cmake {} 代码块或 defaultConfig.externalNativeBuild.ndkBuild {} 代码块中,配置其他的 abiFilters 标签。Gradle 会构建这些 ABI 配置,但是只会将 defaultConfig.ndk {} 代码块中指定的东西打包到 APk 中。

    转载请注明原文地址: https://ju.6miu.com/read-3307.html

    最新回复(0)