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!