Android Studio 應該是在3.2的版本以前對Camke支持都不太好,沒有提示,但最新的好像3.4的能夠了;NDK學習,至於這裏建立NDK項目以及Android Studio NDK配置就不講了;網上不少教程;java
一、配置Cmake版本:git
二、添加庫:github
add_library( <name>
[STATIC | SHARED | MODULE]
[source1] [source2] [...])
//例子:
add_library(native-lib
SHARED
src/main/cpp/native-lib.cpp)
複製代碼
三、查找一個庫文件緩存
find_library(<VAR>
name1)
例子:
find_library(log-lib
log)
複製代碼
四、將目標文件與庫文件進行連接:bash
target_link_libraries(<target> [item1] [item2] [...]
[[debug|optimized|general] <item>] ...)
例子:
target_link_libraries(native-lib
${log-lib})
複製代碼
Camke語法仍是挺多的,好比還有設置項目路徑,還有當咱們導入OpenCV庫設置OpenCV庫路徑。還有一些其餘我暫時也沒用到。這些是我在學習NDK開發時感受最經常使用的一些語法(可能學的仍是比較淺,暫時直接出到這些)app
這裏講一些最基礎的,主要是用C調用Java類中的屬性以及方法。這裏分爲調用靜態和非靜態的屬性及方法來說。由於他們的調用方法略有不一樣ide
/**
* 建立MainActivity
* 裏面定義了四個按鈕,以及四個native方法
*
*/
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.sample_text);
}
//調用類JavaClass中的非靜態方法;
public native String javaMethod();
//調用類JavaClass中的靜態方法
public static native String staticJavaMethod();
//調用類JavaClass 中非靜態屬性
public native String getField();
//調用類JavaClass 中靜態屬性
public native String getStaticField();
//四個按鈕的點擊事件
public void onClickBtn(View view) {
switch (view.getId()) {
case R.id.btn1:
String javaMethod = javaMethod();
tv.setText(javaMethod);
Log.i("KBein", "onCreate: javaMethod() == "+javaMethod);
break;
case R.id.btn2:
String field = getField();
tv.setText(field);
Log.i("KBein", "onCreate: getField() == "+field);
break;
case R.id.btn3:
String staticField = getStaticField();
tv.setText(staticField);
Log.i("KBein", "onCreate: getStaticField() == "+ staticField);
break;
case R.id.btn4:
String staticJavaMethod = staticJavaMethod();
tv.setText(staticJavaMethod);
Log.i("KBein", "onClickBtn: staticJavaMethod() == "+staticJavaMethod);
break;
}
}
}
/**
* 建立一個Java類
* 類中定義靜態屬性和方法,以及非靜態屬性和方法
*
*/
public class JavaClass {
public String nameStr = "instance Field";
public static String staticField = "static Field";
public JavaClass(){
}
private String methodJava(){
String str = "這是java的方法methodJava()-->經過native String javaMethod()調用";
return str;
}
private static String staticMethod(){
return "這是JavaClass類中的靜態方法-->經過static native String staticJavaMethod()調用";
}
}
複製代碼
注:如下用到的均是此Java類和MainActivity,統一在此貼出函數
2.1.1 C調用Java類中的非靜態屬性(上C代碼):學習
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_roger_ndkdemo_MainActivity_getField(JNIEnv *env, jobject instance) {
jclass clazz;
jobject obj;
jfieldID instance_field_id;
jstring instance_field;
//FindClass是用反射找到這個Java類,參數時JavaClass完成包名,
clazz = env->FindClass("com/example/roger/ndkdemo/JavaClass");
jmethodID constrocMID = env->GetMethodID(clazz,"<init>","()V");
obj = env->NewObject(clazz,constrocMID);
instance_field_id = env->GetFieldID(clazz,"nameStr","Ljava/lang/String;");
instance_field = (jstring)env->GetObjectField(obj,instance_field_id);
return instance_field;
}
複製代碼
這裏來解釋如下這段代碼:ui
參數說明:
一、FindClass("com/example/roger/ndkdemo/JavaClass")方法說明: 返回類型是jclass clazz
二、GetMethodID(clazz,"<init>","()V")方法說明:這個方法是用來獲取非靜態函數ID ,返回類型是jmethodID constrocMID
三、NewObject(clazz,constrocMID)方法說明:用來new一個對象實例; 返回類型是jobject obj(在個引用類型)
四、GetFieldID(clazz,"nameStr","Ljava/lang/String;")方法說明:獲取非靜態屬性的ID ,返回類型是jfieldID instance_field_id;
五、GetObjectField(obj,instance_field_id)方法說明:獲取屬性值,返回類型爲jobject;
最後咱們看到把jobject強轉爲jstring,jstring也是引用類型對應於java中的String;
2.2.1 C調用Java類中的非靜態方法(上C代碼):
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_roger_ndkdemo_MainActivity_javaMethod(JNIEnv *env, jobject instance) {
jclass clazz;
jobject obj;
jmethodID constrocMID;
jmethodID methodId;
//獲取JavaClass類
clazz = env->FindClass("com/example/roger/ndkdemo/JavaClass");
//AllocObject()是指爲clazz開闢一個新的對象,不調用此Class的構造方法
//obj = env->AllocObject(clazz);
//獲取JavaClass 無參構造函數的jmethodID
constrocMID = env->GetMethodID(clazz,"<init>","()V");
//根據clazz和constrocMID new一個新的JavaClass對象
obj = env->NewObject(clazz,constrocMID);
/**
* 第一個參數:是指定要調用的方法是在那個類
* 第二個參數:是指定要調用的方法名字(UTF-8)
* 第三個參數:是表明要調用方法的java方法簽名(這邊狹義的理解爲返回值類型)
*/
methodId = env->GetMethodID(clazz,"methodJava","()Ljava/lang/String;");
return (jstring)env->CallObjectMethod(obj,methodId);
}
複製代碼
這個就很少解釋了,註釋都有,下面我把native-lib.cpp文件全部代碼都貼出來,裏面還有調用靜態屬性和靜態方法,這個和調用非靜態的還存在略微的不一樣
#include <jni.h>
/**
* 建立的cpp文件
* MainActivity中的native方法便是調用一下一下方法
*/
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_roger_ndkdemo_MainActivity_javaMethod(JNIEnv *env, jobject instance) {
jclass clazz;
jobject obj;
jmethodID constrocMID;
jmethodID methodId;
//獲取JavaClass類
clazz = env->FindClass("com/example/roger/ndkdemo/JavaClass");
//AllocObject()是指爲clazz開闢一個新的對象,不調用此Class的構造方法
//obj = env->AllocObject(clazz);
//獲取JavaClass 無參構造函數的jmethodID
constrocMID = env->GetMethodID(clazz,"<init>","()V");
//根據clazz和constrocMID new一個新的JavaClass對象
obj = env->NewObject(clazz,constrocMID);
/**
* 第一個參數:是指定要調用的方法是在那個類
* 第二個參數:是指定要調用的方法名字(UTF-8)
* 第三個參數:是表明要調用方法的java方法簽名(這邊狹義的理解爲返回值類型)
*/
methodId = env->GetMethodID(clazz,"methodJava","()Ljava/lang/String;");
return (jstring)env->CallObjectMethod(obj,methodId);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_roger_ndkdemo_MainActivity_getField(JNIEnv *env, jobject instance) {
jclass clazz;
jobject obj;
jfieldID instance_field_id;
jstring instance_field;
clazz = env->FindClass("com/example/roger/ndkdemo/JavaClass");
jmethodID constrocMID = env->GetMethodID(clazz,"<init>","()V");
obj = env->NewObject(clazz,constrocMID);
instance_field_id = env->GetFieldID(clazz,"nameStr","Ljava/lang/String;");
instance_field = (jstring)env->GetObjectField(obj,instance_field_id);
return instance_field;
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_roger_ndkdemo_MainActivity_getStaticField(JNIEnv *env, jobject instance) {
jclass clazz;
jfieldID static_field_id;
jstring static_field;
clazz = env->FindClass("com/example/roger/ndkdemo/JavaClass");
static_field_id = env->GetStaticFieldID(clazz,"staticField","Ljava/lang/String;");
static_field = (jstring)env->GetStaticObjectField(clazz,static_field_id);
return static_field;
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_roger_ndkdemo_MainActivity_staticJavaMethod(JNIEnv *env, jclass type) {
jclass clazz;
jmethodID static_method_id;
clazz = env->FindClass("com/example/roger/ndkdemo/JavaClass");
static_method_id = env->GetStaticMethodID(clazz,"staticMethod","()Ljava/lang/String;");
return (jstring)env->CallStaticObjectMethod(clazz,static_method_id);
}
複製代碼
不對之處,望多多指教
後面還會持續更新