Android JNI开发系列之配置

在老早以前就想要去接触了解这一块的知识了,奈何在工作中一直都没有机会去接触,就迟迟没有去学习这一块的知识。到现在终于开始去学习了,简单的搜索了一下,都没有太明确的博客去学习,都是很零碎的,而且在最新的版本中也有问题,到最后只能去看官方的文档,当然这才正确的选择,其实一开始就该去看的。废话不多说,这一个系列因为我才开始学习,不知道会有多长,但是会将常用的东西全部总结学习完。

首先来学习一下官方的配置。

一、必要的下载

这一条没啥说的,就是下载一些工具方便开发,当然是在Android Studio中。

对于ndk的开发,需要下载:

  • NDK(Native Development Kit):用来让你调用c或者c++代码的工具
  • cmake:方便在gradle中构建的,不再使用以前的ndk-build(比较麻烦)
  • LLDB:可以调试c或者c++代码的

这三个都可以直接在SDK Manager中去下载(当然也可以手动下载配置好)。目前我使用的版本对应分别是:

NDK : 17.1.4828580
cmake : 3.6.4111459
LLDB : 3.1.4508709

二、在项目中配置NDK

这一点分为两种情况:

  • 新建项目时配置
  • 在已有项目中配置

第一种情况没啥说的,就是在新建项目时,选中第一个界面的include C++ support这个选择框,之后一直默认next(最后finish)即可。

重点是第二种情况,因为大多数在在项目一开始时可能没有想着要使用ndk开发功能,后来需要了,那么就去配置即可。

1、创建cpp文件夹

在已有项目的main目录下创建cpp文件夹

2、创建一个c文件

在cpp文件夹下创建一个c文件,右键->new->c/c++ Source File,例如取名叫做Hello,后缀名为.c,不创建.h文件,点击ok。

注:内部暂时可以不用写代码。

3、创建CMakeLists.txt

在当前module中创建一个CMakeLists.txt文件,右键->new->File,取名叫做CMakeLists.txt,点击ok。加上以下代码:

cmake_minimum_required(VERSION 3.4.1)

add_library( # Specifies the name of the library.
             Hello

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/Hello.c )

add_library方法:

  • 第一个参数:Hello,就是lib的名称,之后在gradle中的ndk ModuleName一致
  • 第二个参数暂时不管
  • 第三个参数要与上文中创建的c文件路径和名字完全相同,后缀相同

4、使用cmake配置gradle关联

选择Android视图,在需要构建的module下,右键->Link C++ Project with Gradle->选择CMakeLists.txt的路径,就是上文中创建的CMakeLists.txt,点击ok。

构建完成,可以看到在当前module下的build.gradle文件中多了以下这段话:

externalNativeBuild {
    cmake {
        path 'CMakeLists.txt'
    }
}

这时候再在当前的build.gradle中,android模块,defaultConfig下,添加以下代码:

ndk{
    moduleName 'Hello'
}

这里的moduleName就是要与CMakeLists.txt中定义的libraryName一致,这里加入叫Hello吧。

到此基本配置就算是完成了。下面就开始写代码,先从java调用c开始。

三、Java调用C代码

1、定义Java方法

到这一步,终于回到熟悉的Java代码,我们在对应的包名中创建一个类,例如取名叫做Hello,加入一个简单的本地方法,只比普通抽象方法多了一个native关键字,如下:

public native String stringFromC();

2、定义C方法

这时候这个方法是找不到的,还需要在之前的Hello.c文件中写上对应的方法,如下:

#include

jstring Java_net_arvin_androidstudy_jni_Hello_stringFromC(JNIEnv *env, jobject instance) {
    return (*env)->NewStringUTF(env, "I am from c!");
}

代码不长,以此来解释,首先必须要引入的是jni.h,下边的JNIEnv和jstring,jobject等都是在这里边去定义的。

函数的申明部分,jstring表示在java中定义的String,这个位置也就是返回值,然后Java_net_arvin_androidstudy_jni_Hello_stringFromC这一部分看起来很长其实就是三个部分:Java_类的完全限定名_方法名,只是完全限定名中的点改为了下划线,后边的两个参数env和instance,env是一个环境,用它可以操作Java类,创建字符串之类的;instance就是当前调用这个代码的类的实例,这里就是Hello类的实例。

最后就是函数的实现内容,这里是返回一个字符串然后,看一看env这个变量的类型,JNIEnv的定义可以看到是一个typedef const struct JNINativeInterface* JNIEnv;。本身就是指针,然后在方法中的env又是指针,相当于二级指针,所以调用的时候使用的就是(*env)->函数。

3、Java代码与C代码关联

回到Hello类中,在类中加一段静态初始化的代码:

static {
    System.loadLibrary("Hello");
}

其中Hello是上文中在build.gradle中ndk下配置的moduleName。

到这里就可以在其他地方创建Hello类的实例,然后调用stringFromC的方法了。

例如:

Hello jni = new Hello();
System.out.println(jni.stringFromC());

就会在run tab下看到I am from c!这样一句话的输出。

至此Android JNI开发系列之配置就告一段落了。当然后边肯定还有进一步的配置学习,例如需要引入多个c文件,需要引用其他c++库等,肯定也是需要配置的,那些都会在之后的文章中讲到。

感谢

借鉴官方教程

你可能感兴趣的:(Android JNI开发系列之配置)