Note: Pre-built libraries refer to native libraries that have been pre-built.
CMake Common command
The command | meaning |
---|---|
cmake_minimum_required | Specify the minimum version of CMAKE required |
include_directories | Specifies the header file path for native code or so libraries |
add_library | Add source files or libraries |
set_target_properties | Specify the path to import the library |
find_library | Add the NDK apis |
target_link_libraries | Associate pre-built libraries with native libraries |
- CMake Common command
- Add C C code to the Android project
- Download the NDK and build tools
- Create a new project that supports CC
- Build and run the sample application
- Add CC code to an existing project
- Create a new source file
- Create the CMake build script
- Add apis in NDK
- Add existing libraries to other pre-built libraries
- Associate Gradle with the native library
- Manually configure Gradle
- Specify optional configuration
- Specify the ABI
Add C \C++ code to the Android project
Using Android Studio 2.2 or later, with the Android Plugin for Gradle 2.2.0 or later, you can compile C \ C++ code into native libraries using Gradle. This code is then packaged into your application, and the Java code can then call functions in your native library through the Java Native Interface (JNI).
Android Studio’s default tool for building native libraries is CMake. Since many existing projects use build kits to compile their native code, Android Studio also supports NdK-Build. However, if we are creating a new native library, we should use CMake.
This article can help you use the build tools to set up Android Studio, create or configure projects to support native code on Android, and build and run applications.
Download the NDK and build tools
To enable your application to compile and debug native code, you need the following components:
- Android Native Development Kit (NDK) : This set of tools allows you to develop Android code using C and C++ and provides numerous platform libraries that allow you to manage native activities and access physical device components, such as sensors and touch input.
- CMake: An external build tool that can be used with Gradle to build native libraries. This component is not required if you only plan to use the NdK-build.
- LLDB: A debugger that Android Studio uses to debug native code.
You can install these components using the SDK Manager:
- From the open project, choose Tools > Android > SDK Manager from the menu bar.
- Click the SDK Tools TAB.
-
Select the LLDB, CMake, and NDK check boxes, as shown in the following figure.
-
Click Apply, and then OK in the pop-up dialog box.
- When the installation is complete, click Finish and then OK
Create a new project that supports C/C++
Creating a project that supports native code is similar to creating any other Android Studio project, although a project that supports native code requires a few additional steps:
- In the Configure your new project section of the wizard, select the Include C++ Support check box.
- Click Next.
- Fill in all other fields as normal and complete the next sections of the wizard.
-
In the Customize C++ Support section of the wizard, you can Customize your project with the following options:
- C++ Standard: use the drop-down list to select which C++ Standard you want to use. Selecting Toolchain Default uses the Default CMake setting.
- Exceptions Support: check this box if you want to enable Support for C++ exception handling. If this check box is enabled, Android Studio adds the -FExceptions flag to cppFlags in the module-level build.gradle file, which Gradle passes to CMake.
- Runtime Type Information Support: Select this check box if you wish to Support RTTI. If this check box is enabled, Android Studio adds the -frtti flag to cppFlags in the module-level build.gradle file, which Gradle passes to CMake.
- Click Finish.
After Android Studio completes the creation of the new Project, open the Project pane from the left side of the IDE and select Android View. Android Studio will add CPP and External Build Files groups as shown below:
- In the CPP group, you can find all the original source files, header files, and pre-built libraries that belong to your project. For new projects, Android Studio creates a sample C++ source file, native-lib. CPP, and places it in the SRC /main/ CPP/directory of the application module. This sample code provides a simple C++ function, stringFromJNI(), that returns the string “Hello from C++”.
- In the External Build Files group, you can find Build scripts for CMake or NdK-Build. Just as the build.gradle file instructs Gradle how to build your application, CMake and NdK-Build require a build script to understand how to build your native libraries. For new projects, Android Studio creates a CMake build script, cmakelists.txt, and places it in the module’s root directory.
Build and run the sample application
After creating the project, click the Run button, and Android Studio will install and launch an application that displays the text “Hello from C++” on your Android device. Here’s what happens when you build and run the sample application:
- Gradle calls your external build script, cmakelists.txt.
- CMake compiles the C++ source file native-lib. CPP into a shared object library named libnative-lib.so. Gradle then packages it into APK.
- At runtime, the application’s MainActivity loads the native library using system.loadLibrary (). Applications can now call the library’s native function, stringFromJNI().
- Mainactivity.oncreate () calls stringFromJNI(), which returns “Hello from C++” and updates the TextView with those words.
Note: Instant Run is not compatible with projects that use native code. Android Studio automatically disables this feature.
If you want to verify that Gradle has packaged native libraries into APK, you can use APK profiler:
- Select Build > Analyze APK.
- Select APK from the app/build/outputs/ APk/directory and click OK.
- As shown in Figure 3, you will be in the APK analyzer windowlib//See underlibnative-lib.so.
Tip: If you want to experiment with other Android applications using native code, go to File > New > Import Sample and select the Sample project from the Ndk list.
Add C/C++ code to an existing project
If you want to add native code to an existing project, follow these steps:
-
Create a new source file and add it to your Android Studio project.
If you already have native code or want to import a pre-built native library, you can skip this step.
-
Create a CMake build script to build your native source code into the library. You also need this build script if you import and associate a prebuilt or platform library.
Skip this step if your existing native library already has a cmakelists.txt build script or uses an NdK-build and includes an Android.mk build script.
-
Provide a path to your CMake or NdK-build script file to associate Gradle with your native library. Gradle uses build scripts to import the source code into your Android Studio project and package the native libraries (SO files) into APK.
After configuring your project, you can use the JNI framework to access your native functions from Java code. To build and Run the application, simply click Run to Run the application from the menu bar. Gradle adds your external native build process in the form of dependencies that compile, build, and package native libraries with APK.
Create a new source file
To create a CPP/directory containing native Code source files in the source code of the AndroidStudio project module, follow these steps:
- Open from the left side of the IDEProjectPane and select the Project view from the drop-down menu.
- Navigate to your module (component) > SRC, right-click the main Directory, and choose New > Directory.
- Enter a name for the directory (for example, CPP) and click OK.
- Right click on the directory you just created and select New > C/C++ Source File.
- Enter a name for your source file, such as native-lib.
-
From the Type drop-down menu, select a file extension for your source file, such as.cpp.
Click on theEdit File Types, you can add other file types, such as.cxx or.hxx, from the drop-down menu. In the C/C++ dialog box that pops up, clickSource Extension 和 Header ExtensionSelect another file extension from the drop-down menu and clickOK.
-
If you also want to Create a header for this file, select the Create an Associated Header check box.
- Click OK.
Create the CMake build script
If your original source file (referring to C\C++ files) does not already have a CMake build script, you will need to create one yourself and include the appropriate CMake command. The CMake build script is a plain text file that you must name cmakelists.txt. This section describes some basic commands included in the build script to indicate which source files CMake should use when creating the native library.
Note: If your project uses ndK-build, there is no need to create a CMake build script. You should provide a path to your Android.mk file to associate Gradle with your native library.
To create a plain text file that can be used as a CMake build script, follow these steps:
- Open the Project pane from the left side of the IDE and select the Project view from the drop-down menu.
-
Right-click the root directory of your module (component) and select New > File.
Note: You can create build scripts anywhere you want. However, when configuring the build script, the path of the source files and libraries will be relative to the location of the build script (meaning that the path of the source files and libraries is relative to the path of the build script).
-
Enter “cmakelists.txt” as the file name and click OK.
Now you can configure your build script by adding the CMake command. To instruct CMake to create a native library from native source, add the cmake_minimum_required() and add_library() commands to your build script:
# set the minimum version of CMake required to build the native library
# This ensures that your build can use some of CMake's specific features;
cmake_minimum_required(VERSION 3.41.)
# specify the name of the native library, specify whether the library is STATIC or SHARED, and specify the relative path of the source code (relative to cmakelists.txt);
# You can define multiple libraries by adding multiple add_library() commands, and CMake will build them for you;
When you build your APP, Gradle automatically packages shared libraries into your APK.
add_library( Specify the name of the library.
native-lib
Set native-lib to shared library.
SHARED
# Specify the relative path of the source code (relative to the path of cmakelists.txt).
src/main/cpp/native-lib.cpp )Copy the code
When you add a source file or library to your CMake build script using add_library(), Android Studio also displays the associated header file in the Project view after you synchronize your Project. However, to ensure that CMake can locate your header file at compile time, you need to add the include_directories() command to the CMake build script and specify the path to the header file:
add_library(.)
# specify header path (relative path) for native code or so library.
include_directories(src/main/cpp/include/)Copy the code
CMake uses the following specification to name library files:
Lib library name.so
For example, if you specify “native-lib” as the name of the share library (call it either a shared library or a dynamic library) in your build script, CMake will create a file named libnative-lib.so. However, when loading this library in Java code, use the name you specified in your CMake build script:
static{System. LoadLibrary ("native- lib "); }Copy the code
Note: If you rename or remove a library in a CMake build script, you need to Clean the Project before Gradle applies the changes or removes the older version of the library from APK. To Clean the Project, select Build > Clean Project from the menu bar.
Android Studio automatically adds source and header files to the CPP group in the Project pane. Using multiple add_library() commands, you can define more libraries for CMake to build from other source files.
Add apis in NDK
The Android NDK provides a useful set of native apis and libraries. You can use any of these apis by including the NDK library in your project’s cmakelists.txt script file.
The pre-built NDK library already exists on the Android platform, so you don’t need to build or package it into APK. Since NDK libraries are already part of CMake’s search path, you don’t even need to specify the location of the library in your local NDK installation, just provide CMake with the name of the library you want to use and associate it with your own native library.
Add the find_library() command to your CMake build script to locate the NDK library and save its path as a variable. You can use this variable to reference the NDK library in other parts of the build script. The following example can locate an Android specific logging support library and store its path in log-lib:
Find_library (# define the name of the path variable and use this variable to store the location of the NDK library. Log-lib # specify the name of NDK library that CMake needs to locate log)Copy the code
To ensure that your native library can call the functions in the log library, you need to use CMake to build the target_link_libraries() command associated library in the script:
find_library(...) # Link one or more other local libraries to your local library. Target_link_libraries (native-lib is a native library we created ourselves).native${log-lib})Copy the code
The NDK also includes libraries in the form of source code that you need to use when building and associating your native libraries. You can compile the source code into the native library using the add_library() command in the CMake build script. To provide a path to your local NDK library, you can use the ANDROID_NDK path variable, which Is automatically defined for you by Android Studio.
The following command instructs CMake to build Android_native_app_glgles.c, which places NativeActivity lifecycle events and touch inputs into static libraries and associates the static libraries with native lib:
Add_library (app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/ android_native_app_glues STATIC libraries are linked to SHARED local libraries. Target_link_librariesnative-lib
app-glue
${log-lib} )Copy the code
Adding additional prebuilt libraries (existing libraries)
Adding a prebuilt library is similar to specifying for CMake that you want to build a native library. However, since the library is already pre-built, you need to use the IMPORTED flag to tell CMake that you only want to import the library into the project:
Add_library (# select imported library. Imported -lib # set imported library type (static or dynamic) to shared library.Copy the code
You then need to specify the path to import the library using the set_target_properties() command, as shown below:
Some libraries provide packages for a specific CPU architecture (or application binary interface (ABI)) and place them in a separate directory. This approach helps the library take full advantage of a particular CPU architecture while allowing you to use only the version of the library you need. To add multiple ABI versions of a library to a CMake build script without having to write multiple commands for each version of the library, you can use the ANDROID_ABI path variable. This variable makes the default set of ABIs supported by the NDK, or the filtered set of ABis that Gradle is manually configured to use. Such as:
add_library(...) IMPORTED_LOCATION set_target_properties(# imported_lib # IMPORTED_LOCATION) IMPORTED_LOCATION imported-lib/src/${ANDROID_ABI}/libimported-lib.so )Copy the code
To ensure that CMake can locate your header file at compile time, you need to use the include_directories() command and include the path to the header file:
include_directories( imported-lib/include/ )Copy the code
Note: If you want to package a prebuilt library that is not a build-time dependency (such as when adding a prebuilt library that is part of an imported-lib dependency), you do not need to perform the following instructions to associate the libraries.
To associate a prebuilt library with your own native library, add it to the target_link_libraries() command of the CMake build script:
Target_link_libraries (# specifies three libraries, respectivelynative-lib, imported-lib, and log-lib.native${log-lib} ${log-lib} ${log-lib}Copy the code
Gradle automatically packages the imported libraries into APK when you build your application. You can use the APK analyzer to verify which libraries Gradle packages into your APK.
Associate Gradle with the native library
To associate Gradle with your native library, you need to provide a path to a CMake or nk-build script file. When you build your application, Gradle runs CMake or NdK-build as dependencies and packages the shared library into your APK. Gradle also uses build scripts to know which files to add to your Android Studio Project so that you can access them from the Project window. If your original source file does not have a build script, you will need to create a CMake build script (cmakelists.txt) before continuing.
After you associate Gradle with your native Project, Android Studio updates the Project pane to show your source Files and native libraries in the CPP group and your External Build scripts in the External Build Files group.
Note: When changing Gradle configuration, be sure to make the changes take effect by clicking Sync Project in the toolbar. In addition, if you make changes to a CMake or nk-build script file after associating it with Gradle, you should select build > Refresh Linked C++ Projects from the menu bar, Sync Android Studio with your changes.
Manually configure Gradle
To manually configure Gradle to associate it with your native library, you need to add the externalNativeBuild {} block to the module (component) level build. Gradle file and configure it using cmake {} or ndkBuild {} :
android { ... defaultConfig {... } buildTypes {... }// Encapsulate your external local build configuration.
externalNativeBuild {
// Encapsulate your CMake build configuration.
cmake {
// Provide a relative path to the CMake build script (this relative path is relative to the current build.gradle path).
path "CMakeLists.txt"}}}Copy the code
Note: If you want to associate Gradle with an existing NdK-build project, use the ndkBuild {} block instead of cmake {} and provide a relative path to the Android.mk file. If the application. mk file is in the same directory as your Android.mk file, Gradle also includes this file.
Specify optional configuration
You can configure another externalNativeBuild {} block in the defaultConfig {} block of the module (component) level build.gradle file, specifying optional parameters and flags for CMake or Nk-Build. Like the other properties in the defaultConfig {} block, you can rewrite these properties for each productFlavors in the build configuration.
For example, if your CMake or ndk-build project defines multiple native libraries, you can use the targets attribute to build and package only a portion of those libraries for a given productFlavors. The following code examples illustrate some of the properties you can configure:
android {
...
defaultConfig {
...
// This code block is different from the one you associate with Gradle's CMake or NDK build scripts.
externalNativeBuild {
// For ndk-build, instead use ndkBuild {}
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_ARM_NEON=TRUE"."-DANDROID_TOOLCHAIN=clang"
// Set optional flags for the C compiler.
cFlags "-D_EXAMPLE_C_FLAG1"."-D_EXAMPLE_C_FLAG2"
// sets a flag to enable the C++ compiler's format macro constant.
cppFlags "-D__STDC_FORMAT_MACROS"} } } buildTypes {... } productFlavors { ... demo { ... externalNativeBuild { cmake { ...// Specify a local library to build and package for the product flavor. If you do not configure this property,
// Gradle builds and packages all shared object libraries that you define in a CMake or nk-build project
targets "native-lib-demo"
}
}
}
pad {
...
externalNativeBuild {
cmake {
...
targets "native-lib-pad"}}}}// Use the following code block to link Gradle to your CMake or Dk-build scriptsexternalNativeBuild { cmake {... }// or ndkBuild {... }}}Copy the code
Specify the ABI
By default, Gradle builds your native libraries into a separate.so file for the NDK-supported ABI and packages them all into your APK. If you want Gradle to only build and package specific ABI configurations for native libraries, you can specify these configurations using the ndk.abiFilters flag in the module-level build. Gradle file, as shown below:
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 {... }}Copy the code
In most cases, you only need to specify abiFilters (as shown above) in the NDK {} block, because it instructs Gradle to build and package these versions of the native library. However, if you want to control the configuration that Gradle should build, independent of the configuration that you want packaged into APK, Please in defaultConfig. ExternalNativeBuild. Cmake {} block (or defaultConfig. ExternalNativeBuild. NdkBuild {} block) configuration another abiFilters logo. Gradle builds these ABI configurations, but only packages the configurations you specify in the defaultConfig.ndk{} block.
To further reduce the size of APK, consider configuring ABI APK split. Instead of creating a large APK that contains all versions of the native library, Gradle creates a separate APK for each ABI you want to support and packages only the files needed for each ABI. If you configure ABI splitting and do not specify the abiFilters flag as in the code example above, Gradle builds all supported ABI versions of the native library, but only packages the versions you specify in the ABI splitting configuration. To avoid building a version of the native library that you don’t want, provide the same ABI list for the abiFilters flag and ABI split configuration.