Android Jni開發-基礎配置篇(CMake)

簡介:

涉及到一些算法或者底層驅動的時候,往往需要使用jni來開發。現在官方推薦使用CMake工具來開發jni。

使用CMake開發Jni其實挺簡單的,要求不高的話只需要簡單配置一下就可以使用了。

配置環境

使用CMake進行Jni開發需要使用CMake插件、LLDB插件、NDK插件,這些都可以通過Android Studio很快地安裝。
打開SDK Manager,找到Android SDK->SDK Tool選項,安裝CMake、LLDB、NDK插件。
在這裏插入圖片描述

創建支持C++代碼的工程

勾選Include C++ support選項,勾選後Android Studio可以更好地支持及幫助我們檢查jni代碼,之後一路next即可。
在這裏插入圖片描述
創建完成後會發現Android Studio會自動爲我們生成一個Jni調用示例。我們把工各切換至project視圖,來看一看目錄結構。
在這裏插入圖片描述
看目錄可以知道,相比普通工程,AndroidStudio主動爲我們生成了一個cpp的目錄,該目錄主要存放調用的c++頭文件,源代碼及jni代碼,還有一個CMakeLists.txt的文件,cpp目錄下面包含一個native-lib.cpp文件,這裏需要關注的主要文件有3個,native-llib.cpp、MainActivity和CMakeList.txt。下面重點講解一下這幾個文件的作用。

native-lib.cpp文件
該文件是之前勾選支持c++後Android Studio主動爲我們生成的一個示例調用文件,裏面包含了jni代碼。

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring

JNICALL
Java_mhwang_com_jnidemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

MainActivity.java文件

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

這裏的代碼主要注意2點,一是

static {
        System.loadLibrary("native-lib");
    }

這裏主要加載native-lib庫。
二是public native String stringFromJNI(),方法,主要提供java本地jni接口,java就是通過調用這個接口來通過jni調用C++函數的。

CMakeLists.txt文件
這個文件的作用是通過配置將C++代碼編譯到共享對象庫中,具體功能項直接通過註釋來說明吧。

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.
# 設置CMake構造本地庫所需要的最低版本

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 創建並命名庫,可以將庫的類型設置爲靜態
# 或共享,並提供該庫源代碼的相對路徑。
# 你可以定義多個library庫,並使用CMake來構建。
# Gradle會自動打包庫集成到apk中。

add_library( # Sets 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 )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
# NDK提供了一套實用的原生API和庫,可以使用find_library搜索NDK中存在的庫,只需要加入所需要使用庫的名稱即可,如下面的日誌庫log-lib。
# 更多的庫可參考https://developer.android.com/ndk/guides/stable_apis
find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
# 指定CMake連接到目標庫中,可以鏈接多個庫,如上面的native-lib庫以及NDK中自帶的log-lib庫
target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       #
                       ${log-lib} )

截至目前爲止,我們什麼也沒有添加,但是這已經是一個完整的jni開發的Android 應用了,我們來運行看一下效果。
在這裏插入圖片描述
可以看到,app已經能調用jni代碼中的Hello from C++了。
雖然看着簡單,但是在編譯運行時,Android Studio爲我們做了大量的工作。
1、首先Gradle調用了工程中的CMakeLists.txt文件
2、CMake按照期裏面的命令將C++源文件native-lib.cpp編譯到共享對象庫中,並命名爲libnative-lib.so,之後由Gradle將其打包到APK中。
3、運行時,由於System.loadLibrary()是靜態方法,會在應用MainActivity中的onCreate()調用之前加載原生庫。實際運行結果也是先執行loadLibrary()

在這裏插入圖片描述
4、之後再由onCreate()中調用stringFromJNI(),並將返回的「Hello from C++」更新視圖。

更多詳細的說明可以參考官方文檔