AndroidStudio中NDK开发环境配置和jni的简单使用(HelloWord)

一.概述,目的

首先,在之前使用Eclipse的时候写过一个如何搭建ndk开发环境的文章,现在都在使用AndroidStudio了所以再写一下。再者准备研究一下热更新技术,其中要用到jni和c相关的知识所以打算重新学习一下这部分的内容。后面也会将我的学习过程记录下来。

本文涉及的点

1.1 AndroidStudio中的ndk开发环境的配置

1.2 简单jni调用,ndk开发的开发流程(so文件生成的流程),这里写了一个“Hello Word”

1.3 so文件的使用和注意事项

1.4 为方便使用so文件,将开发工具打包为jar包,或者以工程依赖的方式使用。

二.AndroidStudio中的ndk环境的配置和so文件的生成

2.1 AndroidStudio中的ndk环境的配置

首先说明一下,在AndroidStudio中配置ndk和使用jni来编译生成so文件相比eclipse中都简单了好多。这也顺应了潮流,不简单怎么体现AndroidStudio的好呢。

2.1.1 ndk的下载

这里推荐直接下载ndk包,然后到AndroidStudio中配置,因为我发现在很多情况下通过AndroidStudio中的sdkManager或者Project Structure中下载的ndk-bundle在配置之后都不能正常使用,这里原因就不深究了,知道对的就按照对的做就好了。下载到自己确定的目录下面,预备下面安装使用

推荐的ndk下载链接

下载界面如图:我根据我的操作系统下载Win10的64位版本。

这里写图片描述

2.1.2 ndk的安装以及其中要注意的地方

先在AndroidStudio中创建一个项目。
安装步骤如下:
a.在AndroidStudio中打开File –>Project Structure –>Sdk Location打开如下图:

这里写图片描述

其中D:\as\myndk\android-ndk-r14b就是我解压完成的ndk包路径换成自己的就好了。

b.在工程的local.properties中会增加如下图中ndk.dir=D:\as\myndk\android-ndk-r14b说明你的ndk安装成功了。

这里写图片描述

c.在工程的gradle.properties中增加android.useDeprecatedNdk=true这一句,如下图。

这里写图片描述

上面就将ndk的开发环境配置完成了,这里不用去我们手动配置ndk的环境变量,AndroidStudio已经帮我们完成了。

2.2 利用搭建好的ndk环境写一个c程序,生成.so文件,完成一个jni的调用过程。

2.2.1 先创建一个调用本地方法的工具类JniUtil,如下图:

这里写图片描述

其中getData就是我们要调用的本地方法,如下
public static native String getData();
而如下的代码,就是静态代码块中加载so文件。(jnitest就是下面我们要编写的c文件的名称你可以自己取名字,而系统会在生成so文件的时候生成libjnitest.so的so文件,lib是系统为我们加上的不用管它)
static {
    System.loadLibrary("jnitest");
}

在module(app)中的build.gradle中加入下面的代码如图:

这里写图片描述

其中各行的作用在里面已经注释了。

2.2.2 根据2.2.1中的JniUtil生成“头文件”,如下

2.2.2.1 打开AndroidStudio中的Terminal控制台(为提供方便操作Windows系统中文件),如果没有的话就File—settings—plugins下面找到Termina,勾选上重启就可以了。
2.2.2.2 打开后如下进入到当前工程java目录中,调用如下命令生成头文件。其中javah -jni为命令,后面的com.jni.test.gong.JniUtil就是我们刚刚写的工具类JniUtil的完整路径(更换成你自己的就好了)。
javah -jni com.jni.test.gong.JniUtil
界面如下图,操作完成刷新工程会有com_jni_test_gong_JniUtil.h的头文件生成。它的作用就是为我们下面写c文件做“中间件”。

这里写图片描述

2.2.3根据头文件生成c文件

2.2.3.1在工程的main目录下面新建jni文件夹,如下图

这里写图片描述

2.2.3.2 将2.2.2中生成的头文件剪切到jni文件夹中
2.2.3.3创建c文件
这里有两种方法:
一种直接在jni目录下面新建jnitest.c或者jnitest.cpp,前者是c文件后者是c++文件。如下图,注意选择c文件和c++文件,因为里面的语法会有不同哦。

这里写图片描述

然后在jnitest.c中编写先关代码如下

这里写图片描述

另一种是简单的快捷方法,在JniUtil中的方法getData方法是红色的,此时光标定位上面按Alt + Enter快捷键,出现如下的对话框,点击第一个即可。会在jni文件夹中自动生成jnitest.c文件(可能里面格式会是凌乱的自己整理一下即可)。

这里写图片描述

2.2.4 解释一下头文件和c文件内容
首先里面提示的“添加;”的错误不要管他,正常。
首先头文件中
...代码省略...
/*自己理解头文件作用,相当于java中的import,必须要有的(jni.h中定义了一些变量等)*/
#include <jni.h>
/* Header for class com_jni_test_gong_JniUtil */

...代码省略...
extern "C" {
    #endif
    ...代码省略...
    /*JNIEXPORT jstring JNICALL 是固定格式,后面的Java_com_jni_test_gong_JniUtil_getData也可以看出是调用java中的“完整的方法”*/
    JNIEXPORT jstring JNICALL Java_com_jni_test_gong_JniUtil_getData
      (JNIEnv *, jclass);

    ...代码省略...
}
...代码省略...
c文件中的内容
很简单,一个头文件导入,再有就是具体的方法实现了。
#include <jni.h>

JNIEXPORT jstring JNICALL Java_com_jni_test_gong_JniUtil_getData(JNIEnv *env, jclass type){

    return (*env)->NewStringUTF(env, "Hello Word From Jni");
}
2.2.5生成so文件
点击Build中的Make Project,在如下的目录中就会生成我们要的so文件。如下图,我们可以将他们拷出来备用。

这里写图片描述

三. so文件的使用

可以在打包so文件的工程中使用我们的so文件,也可以在其他的工程中使用我们打包好的so文件。但是要注意使用时候的工具类的名称,方法名称,工具类所在的包路径,方法名称要和2.2.1中的完全相同。(所以为了方便,我们实际应用中可以打包成jar包或者作为module依赖的方式,以提高我们so文件的通用性)

3.1使用例子

3.1.1 新建一个工程这里我起名为JniUse,包名为com.jni.use,我们在里面新建一个包,名为com.jni.test.gong,再在里面新建JniUtil类并在里面写getData函数(为了和so文件中的方法名称中的包名,方法名都相同),最方便的方法就是将2.2.1中的JniUtil类拷过来。
3.1.2 将刚刚生成的so文件都拷贝过来放在libs包中
3.1.3 在build.gradle中添加如下代码(注意位置在下面3.1.4截图中),用以标明so文件的存放目录。
sourceSets {
    main {
        jniLibs.srcDirs = ['libs']
    }
}
3.1.4 这里用log进行打印
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String str = JniUtil.getData();
        Log.e("JniUtil",str);
    }
}
所有配置截图如下

这里写图片描述

3.1.5运行一下工程log如下:
01-08 10:21:46.379 25920-25920/com.jni.use E/JniUtil: Hello Word From Jni
通过上面的配置我们的Hello word就算是完成了。jni的简单使用比较简单,c/c++的文件编写是重点。

四 为方便so文件的使用,将工具类等打包为jar包或者以库依赖的方式引用

4.1 库依赖的方式

这里我们新建工程,为了熟悉一下上面so的打包流程(其实内容是一样的)

4.1.1 新建工程,在里面新建一个Android Library作为依赖库,在这个module中依照上面的操作制作so文件,我的如图:

这里写图片描述

4.1.2 将4.1.1中创建的library作为依赖库,然后使用里面写好的工具类,如下面的代码很简单。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String str = JniUtil.getData();
        Log.e("JniUtil",str);
    }
}
运行一下log如下,说明很成功。
01-08 14:23:24.569 16298-16298/com.jni.use.lib E/JniUtil: Hello Word From Jni

4.2 以jar包的方式

由于我使用的同一个app工程,这里先将上面4.1中的依赖关系去掉。

4.2.1 将4.1中生成的so文件全部复制到app下面的lib目录下。

4.2.2 在build.gradle中添加如下的代码

sourceSets {
    main {
        jniLibs.srcDirs = ['libs']
    }
}
和buildTypes,defaultConfig同级括号中(重要)

4.2.3 重点来了,最简单的做法是从build\intermediates\bundles\debug的目录中直接取出classes.jar,这个就可以作为我们使用的jar包,当然名称也可以手动更改,我这里拷贝出classes.jar将其改为jnilib.jar放入app中的libs目录下添加为依赖。这时候就能使用了,测试代码和4.1.2中的一样,log也是一样的。当然也可以指定jar包的名称和位置在生成jar包的时候,由于这不是本文重点在这里不做赘述。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值