Android Studio 3.0 JNI開發入門
本入門教程使用的作業系統為ubuntu18.04
開發環境準備
在AS中新建一個專案,開啟專案的File–>Settings–>Android SDK–>SDK Tool,下載安裝CMake、LLDB、NDK。
建立一個支援C/C++的Android專案
開啟專案的File–>New–>New Object…
建立過程一直Next下去,直到最後一步
專案建立成功後,專案自動建立了src/main/cpp目錄和一個native-lib.cpp原始檔,並在app/目錄裡生成CMakeLists.txt檔案: 並且在Module:app的gradle裡配置好了相關資訊,如下圖所示:
android { compileSdkVersion 28 defaultConfig { applicationId "com.wong.testjni" minSdkVersion 19 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "-std=c++11" //配置C++標準 } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } // 配置CMakeLists.txt路徑 externalNativeBuild { cmake { path "CMakeLists.txt" // 設定所要編寫的c原始碼位置,以及編譯後so檔案的名字 } } } dependencies { ...... }
CMakeLists.txt檔案的內容如下:
#設定CMake的最低版本構建本機所需庫 cmake_minimum_required(VERSION 3.4.1) # 建立並命名庫,將其設定為靜態的 # 或共享,並提供其原始碼的相對路徑。 # 你可以定義多個library庫,並使用CMake來構建。 # Gradle會自動將包共享庫關聯到你的apk程式。 add_library( #設定so檔名稱 native-lib # 設定這個so檔案為共享 SHARED # 設定 c檔案原始碼位置 src/main/cpp/native-lib.cpp ) # 搜尋指定預先構建的庫和儲存路徑變數。因為CMake包括系統庫搜尋路徑中預設情況下,只需要指定想新增公共NDK庫的名稱,在CMake驗證庫之前存在完成構建 find_library( # 設定path變數的名稱 log-lib # Specifies the name of the NDK library that # 在CMake定位前指定的NDK庫名稱 log ) # 指定庫CMake應該連結到目標庫中,可以連結多個庫,比如定義庫,構建指令碼,預先構建的第三方庫或者系統庫 target_link_libraries( # 制定目標庫 native-lib # 目標庫到日誌庫的連結 包含在NDK # included in the NDK. ${log-lib} )
建立一個方法測試一下NDK環境
- 在MainActivity.java中增加一個native方法
public native String sayHelloJNI();
你會發現sayHelloJNI( )方法是紅色的。但是,按Alt+Enter快捷鍵後,系統會自動在之前.cpp檔案中建立一個sayHelloJNI( )的C++程式碼,如下所示:
extern "C"
JNIEXPORT jstring JNICALL
Java_com_wong_testjni_MainActivity_sayHelloJNI(JNIEnv *env, jobject instance) {
// TODO
return env->NewStringUTF("Hello android ,welcome to JNI world...");
}
可以看到,sayHelloJNI()方法在C++程式碼的方法名是所在的類的完整包名加上方法名組成的。
- 使用native方法,要先將so庫引入,引入的方法,只須在要使用native方法的類里加入如下程式碼:
static {
System.loadLibrary("native-lib");
}
注:native-lib是在CMakeLists.txt檔案裡指定的。
- 在MainActivity.java中呼叫sayHelloJNI()方法:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(sayHelloJNI());
}
private native String sayHelloJNI();
}
至此,如果tv可以顯示出"Hello android ,welcome to JNI world…",則說明NDK環境配置成功了。
其實在AS 3.0進行NDK開發已經很方便的了。只需要建立支援C/C++開發的專案就可以完成NDK 的環境搭建了。
定義一個包含native方法的類
package com.wong.testjni;
public class TestJNI {
public static native int init(Object obj);
public static native int deInit(int index);
}
-
在AS的Terminal中通過命令列的指令生成.h檔案:
-
生成的.h檔案在app/src/main/java下,將.h檔案移到app/src/main/cpp目錄下。
-
在app/src/main/cpp中新建一個.cpp的C/C++原始檔,該檔案中的方法名對應生成的.h檔案中宣告的 方法名,java層通過呼叫該檔案中的方法達到呼叫C/C++中方法的目的,如.cpp原始檔是TestJNI.cpp,如下所示:
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jint JNICALL
Java_com_wong_testjni_TestJNI_init(JNIEnv *env, jclass type, jobject cb) {
return 10;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_wong_testjni_TestJNI_deInit(JNIEnv *env, jclass type, jint index) {
return index;
}
- 在CMakeLists.txt檔案裡設定 TestJNI.cpp檔案原始碼位置
cmake_minimum_required(VERSION 3.4.1)
add_library( # # 設定so檔名稱.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/TestJNI.cpp #設定 TestJNI.cpp檔案原始碼位置
src/main/cpp/native-lib.cpp )
find_library( # Sets the name of the path variable.
log-lib
log )
target_link_libraries( # Specifies the target library.
native-lib
${log-lib} )
- 在MainActivity呼叫
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(TestJNI.deInit(18)+"");
}
}
謝謝觀賞!