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);
}
复制代码
不对之处,望多多指教
后面还会持续更新