NDK开发学习(一)

一、CmakeLists.txt配置

Android Studio 应该是在3.2的版本之前对Camke支持都不太好,没有提示,但最新的好像3.4的可以了;NDK学习,至于这里创建NDK项目以及Android Studio NDK配置就不讲了;网上很多教程;

Cmake语法:

1、配置Cmake版本:

  • cmake_minimum_required(VERSION 3.4.1)
  • 参数:最低版本 VERSION 3.4.1 (这里配置的最低版本是3.4.1版本)

2、添加库:

                add_library( <name>  
                                [STATIC | SHARED | MODULE]     
                                [source1] [source2] [...])  

   //例子:  
               add_library(native-lib   
                               SHARED   
                               src/main/cpp/native-lib.cpp)    
                               
复制代码
  • 参数一:表示库文件的名字,该库文件会根据命令里列出的源文件来创建
  • 参数二: STATIC、SHARED和MODULE的作用是指定生成的库文件的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接(动态链接库),在运行时会被加载。MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数
  • 参数三: [source1] [source2]指的是源文件的路径

3、查找一个库文件

        find_library(<VAR> 
                     name1)
例子:

        find_library(log-lib
                    log)

复制代码
  • 参数一:创建名为的缓存条目以存储此命令的结果。如果找到库,则结果存储在变量中,除非清除变量,否则不会重复搜索。
  • 参数二:库名

4、将目标文件与库文件进行链接:

        target_link_libraries(<target> [item1] [item2] [...]
                      [[debug|optimized|general] <item>] ...)

例子:

        target_link_libraries(native-lib
                            ${log-lib})

复制代码
  • 参数一:目标文件
  • 参数二:库文件

Camke语法还是挺多的,比如还有设置项目路径,还有当我们导入OpenCV库设置OpenCV库路径。还有一些其他我暂时也没用到。这些是我在学习NDK开发时感觉最常用的一些语法(可能学的还是比较浅,暂时直接出到这些)

二、NDK开发中的函数调用

这里讲一些最基础的,主要是用C调用Java类中的属性以及方法。这里分为调用静态和非静态的属性及方法来讲。因为他们的调用方法略有不同

/**
 * 创建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、C调用Java类中的属性:

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;
}

复制代码

这里来解释以下这段代码:

  • 首先说Java_com_example_roger_ndkdemo_MainActivity_getField()这一段字母,“com_example_roger_ndkdemo_MainActivity”是包名+MainActivity, 而getField()即是MainActivity中的native方法-->public native String getField();所有的jni方法前面都加一个Java;因此这样就能与我们MainActivity中的getField()方法对应起来了,当我们调用getField()方法时NDK就会给我们执行这段C代码;JNIEXPORT jstring JNICALL 中的jstring就是我们方法getField()返回值String类型

参数说明:

  • 参数一、JNIEnv *env --->是指向JNI环境的指针
  • 参数二、jobject instance --->这是一个类的对象,在java中Object就对应了jobject。instance 指的应该就是MainActivity对象(这里是我的猜测,因为这个getField()方法时在MainActivity中)
  • 注:另外参数二是根据MainActivity中getField()是否是静态来确定的,如果方法是非静态的则为(jobject instance) ;如果方法是静态的则为(jclass class);他俩区别在于jobject instance是类对象(严格说不能是对象,C中是没有对象的,其实它是类的一个引用)而jclass class就是指类

1、FindClass("com/example/roger/ndkdemo/JavaClass")方法说明: 返回类型是jclass clazz

  • 看字面意思FindClass是寻找类,其实就是通过反射找到java类,而com/example/roger/ndkdemo/JavaClass是包名,这里包名的“.”改为“/”。

2、GetMethodID(clazz,"<init>","()V")方法说明:这个方法是用来获取非静态函数ID ,返回类型是jmethodID constrocMID

  • 参数一:clazz 是要调用的方法所在的类
  • 参数二:是方法名,而这里是<init>\指的是类JavaClass的构造函数
  • 参数三:是方法描述符,在java中即是方法签名,这里我理解为是java方法中的返回值类型,因为JavaClass的构造函数是没有返回值得所以用“()V”表示。比如:返回值是String 则为 “()Ljava/lang/String;”

3、NewObject(clazz,constrocMID)方法说明:用来new一个对象实例; 返回类型是jobject obj(在个引用类型)

  • 参数一:clazz 是要调用的方法所在的类
  • 参数二:构造函数ID
    这里new一个对象实例的原因是为了我们调JavaClass中的非静态属性;

4、GetFieldID(clazz,"nameStr","Ljava/lang/String;")方法说明:获取非静态属性的ID ,返回类型是jfieldID instance_field_id;

  • 参数一:clazz 是要调用的方法所在的类
  • 参数二:是属性名
  • 参数三:java中的域描述符;

5、GetObjectField(obj,instance_field_id)方法说明:获取属性值,返回类型为jobject;

  • 参数一:obj 是要调用的方法所在的类的引用(java中就是类对象)
  • 参数二:属性ID

最后我们看到把jobject强转为jstring,jstring也是引用类型对应于java中的String;

2.2、C调用Java类中的方法:

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);
}

复制代码

不对之处,望多多指教
后面还会持续更新

源码

转载于:https://juejin.im/post/5ce4de64f265da1bc853ff19

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值