Android JNI/NDK 从入门到进阶

在这里插入图片描述
好久没发文章了,这篇文章是是10月底开始计划的,转眼到现在12月都快过一半了,我太难了……,不过好在终于完成了,今晚必须去吃宵夜。深圳北,往北两公里的**烧烤,有木有人过来?我请客,没有到时候我再来问一遍。

先看目录,各位觉得内容对你有用再继续往下看,毕竟显示有一万多个字呢,怕没用的话耽误大家宝贵的时间。

闲聊一下为什么写这篇文章?

之前写过一篇关于C代码生成和调试so库的文章。前段时间在继承一个音频检测库的时候出现了点问题,又复习了下JNI部分,顺便整理成文,分享给大家。

文章目标和期望

本文是一个 NDK/JNI 系列基础到进阶教程,目标是希望观看这篇文章的朋友们能对Android中使用C/C++代码,集成C/C++库有一个比较基本的了解,并且能巧妙的应用到项目中。

好了,说完目的,咱们一如既往,学JNI之前,先来个给自己提几个问题:

学前三问?

了解是什么?用来做什么?以及为什么?

什么是JNI/NDK?二者的区别是什么?

什么是JNI?

JNI,全名 Java Native Interface,是Java本地接口,JNI是Java调用Native 语言的一种特性,通过JNI可以使得Java与C/C++机型交互。简单点说就是JNI是Java中调用C/C++的统称。

什么是NDK?

NDK 全名Native Develop Kit,官方说法:Android NDK 是一套允许您使用 C 和 C++ 等语言,以原生代码实现部分应用的工具集。在开发某些类型的应用时,这有助于您重复使用以这些语言编写的代码库。

JNI和NDK都是调用C/C++代码库。所以总体来说,除了应用场景不一样,其他没有太大区别。细微的区别就是:JNI可以在Java和Android中同时使用,NDK只能在Android里面使用。

好了,讲了是什么之后,咱们来了解下JNI/NDK到底有什么用呢?

JNI/NDK用来做什么?

一句话,快速调用C/C++的动态库。除了调用C/C++之外别无它用。

就是这么简单好吧。知道做什么之后,咱们学这玩意有啥用呢?

学JNI/NDK能给我带来什么好处?

暂时能想到的两个点,一个是能让我在开发中愉快的使用C/C++库,第二个就是能在安全攻防这一块有更深入的了解。其实无论这两个点中的哪个点都能让我有足够动力学下去。所以,想啥呢,搞定他。

JNI/NDK如何使用?

如何配置JNI/NDK环境?

配置NDK的环境比较简单。我们可以通过简单三步来实现:

  • 第一步:下载NDK。可以在Google官方下载,也可以直接打开AS进行下载,建议选后者。这里可以将LLDB和CMake也下载上。
  • 第二步:配置NDK路径,可以直接在AS里面进行配置,方便快捷。
  • 第三步: 打开控制台,cd到NDK的指定目录下,验证NDK环境是否成功。

ok,验证如上图所示说明你NDK配置成功了。so easy。

HelloWorld一起进入C/C++的世界

现在开始,咱们一起进入HelloWorld的世界。我们一起来通过AS创建一个Native C++项目。主要步骤如下:

  • 第一步:File --> New --> New Project 滑动到选框底部,选中Native C++,点击下一步。
  • 第二步:选个名字,然后一直点Next,直到Finish完成。

简单通俗易懂有木有?好了,项目创建成功,运行,看界面,显示Hello World,项目创建成功。

如何在Android中调用C/C++代码?

从上面新建的项目中我们看到一个cpp目录,我们所写的C/C++代码就这这个目录下面。其中会发现有一个名为native-lib.cpp的文件,这就是用C/C++赋值Hello World的地方。

Android 中调用C/C++库的步骤:

  • 第一步:通过System.loadLibrary引入C代码库名。
  • 第二步:在cpp目录下的natice-lib.cpp中编写C/C++代码。
  • 第二步:调用C/C++文件中对应的实现方法即可。

Hello World Demo的代码:

Android代码:

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 = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    public native String stringFromJNI();
}

natice-lib.cpp代码:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_testndk_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

ok,我们现在调用是调用通了,但是我们要在JNI中生成对象实例,调用对应方法,操作对应属性,我们应该怎么做呢?OK,接下来要讲的内容将解答这些问题,咱们一起来学习下JNI/NDK中的API。

JNI/NDK的API

在C/C++本地代码中访问Java端的代码,一个常见的应用就是获取类的属性和调用类的方法,为了在C/C++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID,jmethodID类型来分别代表Java端的属性和方法。在访问或者设置Java属性的时候,首先就要先在本地代码取得代表该Java属性的jfeldID,然后才能在本地代码中进行Java属性操作,同样,需要调用Java端的方法时,也是需要取得代表该方法的jmethodID才能进行Java方法调用。

接下来,咱们来尝试下如何在native中调用Java中的方法。先看下两个常见的类型:

JNIEnv 类型和jobject类型

在上面的native-lib.cpp中,我们看到getCarName方法中有两个参数,分别是JNIEnv *env,一个是jobjet instance。简单介绍下这两个类型的作用。

JNIEnv 类型

JNIEnv类型实际上代表了Java环境,通过JNIEnv*指针就可以对Java端的代码进行操作。比如我们可以使用JNIEnv来创建Java类中的对象,调用Java对象的方法,获取Java对象中的属性等。

JNIEnv类中有很多函数可以用,如下所示:

  • NewObject: 创建Java类中的对象。
  • NewString: 创建Java类中的String对象。
  • NewArray: 创建类型为Type的数组对象。
  • GetField: 获取类型为Type的字段。
  • SetField: 设置类型为Type的字段的值。
  • GetStaticField: 获取类型为Type的static的字段。
  • SetStaticField: 设置类型为Type的static的字段的值。
  • CallMethod: 调用返回类型为Type的方法。
  • CallStaticMethod: 调用返回值类型为Type的static 方法。
    当然,除了这些常用的函数方法外,还有更多可以使用的函数,可以在jni.h文件中进行查看,或者参考https://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html链接去查询相关方法,上面都说得特别清楚。

好了,说完JNIEnv,接下来我们讲第二个 jobject。

jobject 类型

jobject可以看做是java中的类实例的引用。当然,情况不同,意义也不一样。

如果native方法不是static, obj 就代表native方法的类实例。

如果native方法是static, obj就代表native方法的类的class 对象实例(static 方法不需要类实例的,所以就代表这个类的class对象)。

举一个简单的例子:我们在TestJNIBean中创建一个静态方法testStaticCallMethod和非静态方法testCallMethod,我们看在cpp文件中该如何编写?

TestJNIBean的代码ÿ

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值