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

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

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

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

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

下载 NDK 和构建工具

title

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

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

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

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

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

  3. 将你的 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 中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值