The first article of 2018 covers some of the concepts of JNI, NDK and how to use the CMake build tool for NDK development in AS 3.0.
1. Know some concepts
-
JNI (Java Native Interface)
The Java native interface is the bridge between Java and other native coding languages such as C and C++.
-
NDK (Native Development Kit)
The native development toolset is a set of tools that allow you to implement program functionality in native coding languages such as C and C++.
-
ABI:
Application binary interfaces, different cpus support different instruction sets, and each combination of the CPU and instruction set has its own application binary interface (or ABI), which defines very precisely how the application’s machine code interacts with the system at run time.
Supported ABI: Armeabi, Armeabi-v7A, ARM64-V8A, x86, X86_64, MIPS, and MIPS64
-
CMake:
NDK build tool recommended for Android, supported since AS 2.2 (including 2.2).
2. Environment construction
Install the tools required for NDK development
Install the following components in the SDK Tools:
-
Cmake: NDK build tool
-
LLDB: NDK debugging tool
-
NDK: NDK development tool set
Create the NDK project
When creating a project, check the Include C++ support option and go all the way to the Customize C++ support Settings page:
You can see three options:
-
C++ Standard: C++ Standard. Selecting Toolchain Default will use the Default CMake configuration.
-
Exceptions Support: C++ exception handling is supported. The flag is -fexceptions.
-
Runtime Type Information Support: Runtime Type recognition, marked -FRTTI, enables programs to use Pointers or references to base classes to check the actual derived Type of the object to which these Pointers or references refer.
Here we use the default C++ standard, uncheck the following two options and click Finish to proceed to the next step.
3. The NDK project
Take a look at the project catalog:
The differences between NDK projects and common projects are marked in red boxes in the figure above. Here are some of them:
Let’s start with the build.gradle configuration:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.yl.ndkdemo"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"}} name = "name"Copy the code
The build.gradle configuration contains two additional externalNativeBuild configuration items:
-
DefaultConfig:
Cmake command parameters are mainly configured. For example, when creating a project, if [Exceptions Support] and [Runtime Type Information Support] are checked, it is configured like this:
externalNativeBuild {
cmake {
cppFlags "-fexceptions -frtti"}}Copy the code
-
DefaultConfig outside:
The main definition of CMake build script cmakelists.txt path.
CMake build script cmakelists.txt
Cmakelists. TXT is a build script for CMake, which is equivalent to android. mk in ndk-build.
Set the minimum version of CmakeCmake_minimum_required (VERSION 3.4.1 track)# compiler library
add_library( Set the library name
native-lib
Set library mode
# SHARED compiles so files, STATIC does not
SHARED
# set native code path
src/main/cpp/native-lib.cpp )
# locate library
find_library( # the name of the library
log-lib
Store the library path as a variable that can be used elsewhere to reference the NDK library
# Set the variable name here
log )
# associated library
target_link_libraries( # Associated Library
native-lib
Connect native lib with log-lib
${log-lib} )
Copy the code
This is a basic CMake build script, please refer to the CMake manual – Chinese version for more script configuration.
Native-lib.cpp
Android provides a simple JNI interactive Demo that returns a string to the Java layer with a method name named Java_ package name _ class name _ method name:
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_yl_ndkdemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
Copy the code
See how to call:
Public class MainActivity extends AppCompatActivity {public class MainActivity extends AppCompatActivity {// load native-lib without the lib prefix static {system.loadLibrary ("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); TextView TV = (TextView) findViewById(R.ids.sample_text); tv.setText(stringFromJNI()); } /** * public native String stringFromJNI(); }Copy the code
Call method is very simple, the code has written a comment, look at the effect:
Generate so file
Set the compile mode of library to SHARED mode in cmakelists. TXT, click the compile button of AS, In the app > Build > intermediates > cmake > debug > obj directory, so files corresponding to different CPU architectures are generated:
The generated SO file can also be used in other projects. Create the jniLibs folder under the app > SRC > main directory of the project, copy the generated SO file (with the CPU architecture directory) to the jniLibs folder, and use it as described above.
App.build. gradle abiFilters = build.gradle abiFilters = build.gradle
defaultConfig {
...
ndk {
abiFilters "armeabi"."armeabi-v7a"."arm64-v8a"."x86"."x86_64"."mips"."mips64"}}Copy the code
4. Write at the end
Stay tuned for more NDK development articles to follow!