概览
本部分简要介绍了 NDK 的工作原理。Android NDK 是一组使您能将 C 或 C++(“原生代码”)嵌入到 Android 应用中的工具。能够在 Android 应用中使用原生代码对于想执行以下一项或多项操作的开发者特别有用:
- 在平台之间移植其应用。
- 重复使用现有库,或者提供其自己的库供重复使用。
- 在某些情况下提高性能,特别是像游戏这种计算密集型应用。
主要组件
在编译应用时,您应该已经了解以下组件:
-
原生共享库:NDK 从 C/C++ 源代码编译这些库或 .so 文件。
-
原生静态库:NDK 也可编译静态库或 .a 文件,而您可将静态库关联到其他库。
-
Java 原生接口 (JNI):JNI 是 Java 和 C++ 组件用以互相通信的接口。本指南假设您具备 JNI 知识;如需了解相关信息, Java 原生接口规范。
-
应用二进制接口 (ABI):ABI 可以非常精确地定义应用的机器代码在运行时应该如何与系统交互。- - NDK 根据这些定义编译 .so 文件。不同的 ABI 对应不同的架构:NDK 为 32 位 ARM、AArch64、x86 及 x86-64 提供 ABI 支持。有关详情,请参阅 ABI 管理。
-
清单:如果您编写的应用不包含 Java 组件,则必须在清单中声明 NativeActivity 类。原生 Activity 和应用的“使用 native_activity.h 接口”部分进一步详细介绍了如何执行此操作。
ndk-build 开发流程
概览
- 设计应用,确定要以 Java 实现的部分,以及要以原生代码形式实现的部分。
- 像创建任何其他 Android 项目一样创建一个 Android 应用项目。
- 如果要编写纯原生应用,请在
AndroidManifest.xml
中声明NativeActivity
类。有关详情,请参阅原生 Activity 和应用。 - 在“JNI”目录中创建一个描述原生库的
Android.mk
文件,包括名称、标记、关联库和要编译的源文件。 - 原生源代码放在项目的
jni
目录下。 - 使用 ndk-build 编译原生(
.so
、.a
)库。 - 编译 Java 组件,生成可执行
.dex
文件。 - 将所有内容封装到一个 APK 文件中,包括
.so
、.dex
以及应用运行所需的其他文件。
向您的项目添加 C 和 C++ 代码
您可以向 Android 项目添加 C 和 C++ 代码,只需将相应的代码添加到项目模块的 cpp 目录中即可。在您构建项目时,这些代码会编译到一个可由 Gradle 与您的 APK 打包在一起的原生库中。然后,Java 或 Kotlin 代码即可通过 Java 原生接口 (JNI) 调用原生库中的函数。要详细了解如何使用 JNI 框架,请参阅 Android JNI 提示。
Android Studio 支持适用于跨平台项目的 CMake,以及速度比 CMake 更快但仅支持 Android 的 ndk-build。目前不支持在同一模块中同时使用 CMake 和 ndk-build。
如果您想要将现有的 ndk-build 库导入到 Android Studio 项目,请了解如何将 Gradle 关联到原生库项目。
下载 NDK 和构建工具
要为您的应用编译和调试原生代码,您需要以下组件:
- Android 原生开发套件 (NDK):一个工具集,让您能够在 Android 应用中使用 C 和 C++ 代码;它提供了各种平台库,让您能够管理原生 Activity 并访问实际设备组件,例如传感器和轻触输入。
- CMake:一款外部构建工具,可与 Gradle 搭配使用来构建原生库。如果您只计划使用 ndk-build,则不需要此组件。
- LLDB:Android Studio 用于调试原生代码的调试程序。
如需了解如何安装这些组件,请参阅安装及配置 NDK、CMake 和 LLDB。
添加c 文件
-
您的应用的主源代码文件集内还没有
cpp/
目录,请按如下所示的方法创建一个:- IDE 的左侧打开 Project 窗格,然后从下拉菜单中选择 Project 视图。
- 转到 your-module > src,右键点击 main 目录,然后依次选择 New > Directory。
- 输入
cpp
作为目录名称,然后点击 OK。
-
右键点击 cpp/ 目录,然后依次选择 New > C/C++ Source File。
为您的源代码文件输入一个名称,例如 native-lib。 -
从 Type 下拉菜单中,为您的源代码文件选择文件扩展名,例如 .cpp。
您可以向此下拉菜单添加其他文件类型(例如 .cxx 或 .hxx),只需点击 Edit File Types 图标 即可。在弹出的 C/C++ 对话框中,从 Source Extension 和 Header Extension 下拉菜单中选择另一个 -
文件扩展名,然后点击 OK。
如果您还想要创建头文件,请选中 Create an associated header 复选框。 -
点击 OK。
在gradle设置ndk-build方式:
externalNativeBuild {
// cmake {
// path "src/main/cpp/CMakeLists.txt"
// version "3.10.2"
// }
ndkBuild {
path ("src/main/jni/Android.mk")
}
}
}
添加Android.mk文件到cpp文件夹下,规范可查看 Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_SRC_FILES := native-lib.cpp
include $(BUILD_SHARED_LIBRARY)
LOCAL_SRC_FILES :=$(call all-subdir-java-files)
然后就可以再java文件中引用库方法.下面是例子:
package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Example of a call to a native method
sample_text.text = stringFromJNI()
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
external fun stringFromJNI(): String
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}
}
CMake工程 编译C/C++
步骤
-
和上面添加C文件相同;
-
配置CMake:
- 在app模块的build.gradle中配置CMake版本(使用 CMake 3.6.0 或 3.10.2):SDK 管理器包含 CMake 的 3.6.0 派生版本和版本 3.10.2。未在
build.gradle
中设置特 定 CMake 版本的项目均使用 CMake 3.6.0 进行构建。要使用后来包含的版本,请在模块的build.gradle
文件中指定 CMake 版本 3.10.2:
- 在app模块的build.gradle中配置CMake版本(使用 CMake 3.6.0 或 3.10.2):SDK 管理器包含 CMake 的 3.6.0 派生版本和版本 3.10.2。未在
android {
...
externalNativeBuild {
cmake {
...
version "3.10.2"
}
}
}
-
添加
CMakeLists.txt
的文件:# 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.10.2) # 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 ) find_library(...) # Links your native library against one or more other native libraries. target_link_libraries( # Specifies the target library. native-lib # Links the log library to the target library. ${log-lib} )
-
关联Gradle:
- IDE 左侧打开 Project 窗格,然后选择 Android 视图。
- 右键点击您想要关联到原生库的模块(例如 app 模块),然后从菜单中选择 Link C++ - - Project with Gradle。您会看到一个类似于图 4 所示的对话框。
- 从下拉菜单中,选择 CMake 或 ndk-build。
- 如果您选择 CMake,请使用 Project Path 旁的字段为您的外部 CMake 项目指定 CMakeLists.txt 脚本文件。
- 如果您选择 ndk-build,请使用 Project Path 旁的字段为您的外部 ndk-build 项目 - 指定 Android.mk 脚本文件。如果 Application.mk 文件与您的 Android.mk 文件位于同一目录下,Android Studio 也会包含此文件。