涉及到一些算法或者底層驅動的時候,往往需要使用jni來開發。現在官方推薦使用CMake工具來開發jni。
使用CMake開發Jni其實挺簡單的,要求不高的話只需要簡單配置一下就可以使用了。
使用CMake進行Jni開發需要使用CMake插件、LLDB插件、NDK插件,這些都可以通過Android Studio很快地安裝。
打開SDK Manager,找到Android SDK->SDK Tool選項,安裝CMake、LLDB、NDK插件。
勾選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++」更新視圖。
更多詳細的說明可以參考官方文檔