原文出处:http://www.ccbu.cc/index.php/android/android-jni-dev-env.html

工欲善其事,必先利其器

1. 开发环境准备

搭建开发环境是我们进行开发前首先要完成的任务,进行Android jni开发,依赖的基本开发环境包括:

  1. Android sdk
  2. android ndk
  3. cmake
  4. android studio

Android studio的sdk manager已经包括了上面所说的sdk,ndk,cmake等工具的安装,所以一般只用下载android studio,然后再使用sdk manager工具下载这些工具就可以了。

Android JNI开发工具篇(1)-开发环境搭建_第1张图片

默认情况下,Android studio使用的编译工具是cmake,但很多沿用的项目都是使用NDK的ndk-build工具来编译的,所以android studio也支持ndk-build。

2. 使用android studio创建本地C++工程

1.新建工程, 在向导的 Choose your project 部分中,选择Natvie C++ 项目类型 。

Android JNI开发工具篇(1)-开发环境搭建_第2张图片

2.在设置工程名,包名,保存路径和语言,此处我们选择Java语言。

Android JNI开发工具篇(1)-开发环境搭建_第3张图片

3.在向导的 Customize C++ Support 部分中,可以选则C++ Toolchain,一般情况下,选择默认就可以,如果开发中需要用到C++11,或者c++14等一些较高级的C++标准的特性时,可以选择对应的Toolchain

Android JNI开发工具篇(1)-开发环境搭建_第4张图片

4.点击finish,开始构建工程,工程构建完成以后,整个项目及其gradle配置文件如下:

Android JNI开发工具篇(1)-开发环境搭建_第5张图片

默认情况下,Android studio使用cmake编译链工具,通过gradle脚本进行配置,默认cmake配置如下:

externalNativeBuild {    cmake {        path "src/main/cpp/CMakeLists.txt"        version "3.10.2"    }}

cmake文件和c++源代码都在src/main/cpp/目录下。

Android studio也支持ndk-buid,根据实际需求,我们也可以配置为ndk-build,当然,这需要我们先写好对应的Android.mkAppplication.mk(可选)配置文件,然后通过修改gradle配置中的externalNativeBuild配置项来进行更改。配置为nkd-build编译工具,则其配置文件如下:

externalNativeBuild {ndkBuild {path file('src/main/cpp/Android.mk')}}

3. 使用现有android studio工程链接C++工程

当一个普通的不带C++本地库支持的项目需要引入一个现有的c++本地库时,可以使用android studio的Link C++ Psroject with Gradle功能来导入一个本地C++库,导入的库需要提供可用的cmake配置文件或Android.mk配置文件,导入工作是通过加载这些本地库编译配置文件来完成的。

Android JNI开发工具篇(1)-开发环境搭建_第6张图片

Android JNI开发工具篇(1)-开发环境搭建_第7张图片

4.在android studio配置javah工具

在Settings->Tools->External Tools下创建NDK group,在NDK group下创建javah工具。

Android JNI开发工具篇(1)-开发环境搭建_第8张图片

详细的配置参数如下:

配置项 参数
Programe $JDKPath$\bin\javah.exe
Arguments -classpath $ModuleFileDir$\src\main\java -jni -d $ModuleFileDir$\src\main\cpp $FileClass$
Working directory $FileDir$

使用时,只需要在定义了native方法的java类上右键选择NDK->javah即可生成对应的c++本地函数定义的头文件。

Android JNI开发工具篇(1)-开发环境搭建_第9张图片

截图中例子中,TestJni.java定义了本地函数add

package com.android.jnitest;public class TestJni {    public native int add(int a, int b);}

使用javah生成的对应本地c++头文件com_android_jnitest_TestJni.h内容如下:

#include /* Header for class com_android_jnitest_TestJni */#ifndef _Included_com_android_jnitest_TestJni#define _Included_com_android_jnitest_TestJni#ifdef __cplusplusextern "C" {#endif/* * Class:     com_android_jnitest_TestJni * Method:    add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_android_jnitest_TestJni_add  (JNIEnv *, jobject, jint, jint);#ifdef __cplusplus}#endif#endif

5. 工程配置

5.1 可选参数配置

可以在模块级 build.gradle 文件的 defaultConfig 块中配置另一个 externalNativeBuild 块,为 CMake 或 ndk-build 指定可选参数和标记 。

android {    ...    defaultConfig {        ...        // This block is different from the one you use to link Gradle        // to your CMake or ndk-build script.        externalNativeBuild {          // For ndk-build, instead use the ndkBuild block.          cmake {            // Passes optional arguments to CMake.            arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"            // Sets a flag to enable format macro constants for the C compiler.            cFlags "-D__STDC_FORMAT_MACROS"            // Sets optional flags for the C++ compiler.            cppFlags "-fexceptions", "-frtti"          }        }    }    ...}

通过上面的配置,可用对cmake的编译选项及C和C++编译选项做一些配置。

5.2 指定 ABI

默认情况下,Gradle 会针对 NDK 支持的应用二进制接口 (ABI) 将您的原生库编译到单独的 .so 文件中,并将这些文件全部打包到您的 APK 中。如果您希望 Gradle 仅编译和打包原生库的部分 ABI 配置,您可以在模块级文件 build.gradle 中使用 ndk.abiFilters 标记指定这些配置,如下所示:

android {    ...    defaultConfig {        ...        externalNativeBuild {        cmake {...}        // or ndkBuild {...}        }        // Similar to other properties in the defaultConfig block,        // you can configure the ndk block for each product flavor        // in your build configuration.        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 {...}}

6. 原生库支持

Android NDK 会提供一组随着新的 Android API 级别的后续发布而逐渐添加的原生标头和共享库文件。 请执行以下两个基本步骤的操作,以便让您的应用使用 NDK 提供的库:

  1. 在您的代码中添加与您想使用的库关联的标头。

  2. 通知编译系统您的原生模块需要在加载时链接库。

    • 如果您使用的是 ndk-build:将原生库添加到您 Android.mk 文件中的 LOCAL_LDLIBS 变量中。例如,要链接 /system/lib/libfoo.so,请添加以下这行代码:
    LOCAL_LDLIBS := -lfoo  

    要列出多个库,请使用空格作为分隔符。

    • 如果您使用的是 CMake,向 CMake 编译脚本添加 find_library() 命令以找到 NDK 库并将其路径存储为一个变量。

      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 )

      然后再 CMake 脚本中的 target_link_libraries() 命令来关联库:

      target_link_libraries( # Specifies the target library.                           native-lib                           # Links the log library to the target library.                           ${log-lib} )

常用的android原生库包括以下一些:

API级别 库名 链接代码 说明
3 C 库 系统自动添加,无需配置
3 动态链接器库 LOCAL_LDLIBS := -ldl 动态链接器的 dlopen(3) 和 dlsym(3) 功能
3 Android日志库 LOCAL_LDLIBS := -llog 原生代码向 logcat 发送日志消息
3 ZLib 压缩库 LOCAL_LDLIBS := -lz
4 OpenGL ES 1.x LOCAL_LDLIBS := -lGLESv1_CM
5 OpenGL ES 2.0 LOCAL_LDLIBS := -lGLESv2
8 jnigraphics LOCAL_LDLIBS += -ljnigraphics
9 EGL LOCAL_LDLIBS += -lEGL 分配和管理 OpenGLES 表面的原生平台接口
9 OpenSL ES LOCAL_LDLIBS += -lOpenSLES 原生音频处理库
9 Android 原生应用api LOCAL_LDLIBS += -landroid 使用原生代码编写整个 Android 应用
14 OpenMAX AL LOCAL_LDLIBS += -lOpenMAXAL 原生多媒体处理库
14 OpenSL ES LOCAL_LDLIBS += -lOpenSLES 增加了 PCM 支持
18 OpenGL ES 3.0 LOCAL_LDLIBS := -lGLESv3
21 OpenGL ES 3.1 LOCAL_LDLIBS := -lGLESv3
24 OpenGL ES 3.2 LOCAL_LDLIBS := -lGLESv3

7. C++ 库支持

7.1 C++ 运行时库

NDK 支持多种 C++ 运行时库。

名称 库文件 功能
libc++ 共享库为 libc++_shared.so
静态库为 libc++_static.a
C++17 支持。
system /system/lib/libstdc++.so newdelete。(在 r18 中已弃用。)
none 无头文件,有限 C++。

libc++

libc++ 同时提供静态库和共享库 。LLVM 的 libc++ 是 C++ 标准库,自 Lollipop 以来 Android 操作系统便一直使用该库,并且从 NDK r18 开始成为 NDK 中唯一可用的 STL。libc++ 的共享库为 libc++_shared.so,静态库为 libc++_static.a。

system

系统运行时指的是 /system/lib/libstdc++.so。请勿将该库与 GNU 的全功能 libstdc++ 混淆。在 Android 系统中,libstdc++ 只是 newdelete。对于全功能 C++ 标准库,请使用 libc++。

none

不包括STL。在这种情况下,没有关联或授权要求。不提供 C++ 标准头文件。

7.2 配置C++ 运行时

如果您要使用 CMake,则可使用模块级 build.gradle 文件中的 ANDROID_STL 变量,指定表表格中的一个运行时 。如果您要使用 ndk-build,则可使用 Application.mk 文件中的 APP_STL 变量指定表 1 中的一个运行时。

APP_STL := c++_shared

只能为应用选择一个运行时,并且只能在 Application.mk 中进行选择。

7.3 共享运行时

如果应用包括多个共享库,则应使用 libc++_shared.so

在 Android 系统中,NDK 使用的 libc++ 不是操作系统的一部分。这使得 NDK 用户能够获得最新的 libc++ 功能和问题修复程序,即使应用以旧版 Android 为目标。需要权衡的是,如果使用 libc++_shared.so,则必须将其纳入 APK 中。如果使用 Gradle 编译应用,则此步骤会自动完成。

7.4 C++ 异常

C++ 异常受 libc++ 支持,但其在 ndk-build 中默认为停用状态。这是因为之前 NDK 并不支持 C++ 异常。CMake 和独立工具链默认启用 C++ 异常。

要在 ndk-build 中针对整个应用启用异常,请将下面这一行代码添加至 Application.mk 文件:

APP_CPPFLAGS := -fexceptions

要针对单一 ndk-build 模块启用异常,请将下面这一行代码添加至相应模块的Android.mk中:

LOCAL_CPP_FEATURES := exceptions

或者,您可以使用:

LOCAL_CPPFLAGS := -fexceptions

7.4 RTTI

与异常一样,RTTI 也受 libc++ 支持,但在 ndk-build 中默认为停用状态。CMake 和独立工具链默认启用 RTTI。

要在 ndk-build 中针对整个应用启用 RTTI,请将下面这一行代码添加至 Application.mk文件:

APP_CPPFLAGS := -frtti    

要针对单一 ndk-build 模块启用 RTTI,请将下面这行代码添加至相应模块的 Android.mk中:

LOCAL_CPP_FEATURES := rtti    

或者,您可以使用:

LOCAL_CPPFLAGS := -frtti

参考:

将 Gradle 关联到您的原生库

向您的项目添加 C 和 C++ 代码

Android NDK 原生 API

更多相关文章

  1. 1、android源代码下载与跟踪
  2. Android环境变量作用--命令行操作(ADB、AVD等)
  3. ReactNative调用原生封装的代码和控件
  4. Android开发人员不得不收集的代码(持续更新中)
  5. android 根据res文件夹下(如res/raw)文件名获取其id
  6. [Android Pro] android 混淆文件project.properties和proguard-p
  7. Android清除本地数据缓存代码
  8. android开发环境搭建和部署

随机推荐

  1. 加速 Android(安卓)依赖下载
  2. android 按钮倒计时读秒
  3. Android(安卓)Studio 本地化配置gradle的
  4. android中处理json最佳方法
  5. AIDL笔记
  6. React Native常用组件轮子(适配Android优
  7. Android(安卓)ListView 效果美化
  8. android shape
  9. Android(安卓)浅谈相机研发
  10. Android(安卓)Handle解析