前面已经介绍了在 Windows 上快速的搭建 JNI 开发环境本节将会实现一个简单的 hello world 版的程序,目的是掌握 JNI 开发的流程,具体的实现细节会在后续进行介绍。
JNI 开发流程梳理:
- 在 java 文件,这里的 java 文件我们以 HelloJNI.java 举例。在其中定义 native 方法
- 使用 javah HelloJNI 命令生成 HelloJNI.h 头文件(注意该命令后只跟文件名,不要带.java 后缀)
- 使用 codeblocks 创建动态链接库工程,并将 HelloJNI.h 添加到该工程
- 实现 HelloJNI.h 中声明的方法
- 使用 codeblocks build 该工程,得到 HelloJNI.dll 动态链接库
- 将 HelloJNI.dll 拷贝到 java 工程中,直接使用即可。
接下来对每一个步骤进行详细介绍。
定义 native 方法
首先我们创建一个 Java 工程,并创建一个 java 文件
1 | public class HelloJNI { |
此时只需定义方法即可,和普通方法类似,只不过前面多了一个 native 的关键字。可以看到我们定义了两个方法,一个非静态方法,一个静态方法,二者都是从 c 代码中获取一个字符串。
生成 HelloJNI.h 头文件
进入命令行,定位到 HelloJNI.java 所在的路径,使用javah HelloJNI
命令生成 HelloJNI.h 头文件(注意该命令后只跟文件名,不要带.java 后缀)
其实这个 javah 命令会读取目标文件,这里就是 HelloJNI.java,然后扫名里面的 native 方法,拿到 native 方法的签名,而对于其它非 native 的方法,javah 则不关心。
使用 codeblocks 创建动态链接库工程
打开 codeblocks,创建工程,选择工程类型为:Dynamic Link Library,然后起一个工程名,这个名字随意,但是最后生成的 dll 文件的名字是和工程名是一样的。
新创建的工程会默认有一个 main.cpp 和 main.h 文件,但我们用不到,忽略它或者删除它。
然后把上一步得到的 HelloJNI.h 文件拷贝到当前工程下,不过只拷贝当前工程的目录下,当前工程也不能识别,我们还需要在当前工程右键,add files,选择我们刚刚复制过来的 HelloJNI.h 文件,这样才会被 codeblocks 纳入到当前工程。
但是此时还要再做一步,注意看生成的 HelloJNI.h 文件的内容是:
1 | /* DO NOT EDIT THIS FILE - it is machine generated */ |
可以看到其首先就包含了jni.h
文件,如果我们不做任何配置的话,codeblocks 在编译代码时是找不到这个头文件的。那么这个jni.h
文件在哪里呢?
首先明确一点:你的 windows 上安装了 JDK,因为jni.h
就在 JDK 的安装路径的 include 目录下,eg:我的电脑上的路径为:D:\Program Files\Java\jdk1.8.0_20\include\
,同时jni.h
文件中还引入了 jni_md.h
文件,所以还要找到 jni_md.h
文件,其位于本机 jdk 的 include\win32
文件夹下:D:\Program Files\Java\jdk1.8.0_20\include\win32\
明确了要准备的两个 h 文件的路径,接下来就要让 codeblocks 在编译时能找到对应的头文件。
我们将这两个头文件都拷贝到当前动态链接库工程的代码文件夹下,同样的,使用 add files,将这两个文件添加到工程中。同时要注意,此时要将 HelloJNI.h 中的#include <jni.h>
改为#include "jni.h"
实现 native 方法
接下来就要真正用 c 来实现之前定义的方法了,实现如下,现在可以先不用管具体的语法,只要有一个感性的认识即可。
1 |
|
生成 dll 文件
在 codeblocks 左侧列表,鼠标当前 project 右键 选择 build,生成对应的 dll 文件,其路径为当前 project 路径下的:bin\debug
中。
在 Java 工程中使用 dll
将上一步生成的 dll 文件拷贝到目标 java 工程的根路径,不需其它配置,在 java 文件的静态代码块中加载对应的动态链接库,不需要 dll 后缀。然后运行该 java 程序,即可看到对应结果。
1 | public class HelloJNI { |
优化
在上一步中,直接把 dll 拷贝到 java 工程目录下了,但是这样有一个问题,那就是你每改动一点 c 的代码,都要重新生成 dll,然后在把该 dll 拷贝到 java 工程目录下,这样是很麻烦的。
这里的 java 代码所用的 ide 是 idea,我们可以在 idea 中为当前工程设置一个环境变量, 让该变量直接定位到 codeblocks 工程生成 dll 的路径,这样就免去了不断拷贝 dll 文件的麻烦。具体做法是:在 idea 中点击Run > Edit Configurations
,将需要加载dll文件的Java文件的 在VM options
选项中加入java.library.path
,即 dll(或so)文件所在的目录,比如本文中 dll 放在 codeblocks 项目目录中的 E:\Csrc\HelloJNI\bin\Debug
中,
同时注意到:按照如图的配置,只能是为AccessMethod.java
文件配置了路径,也就是说在其它文件要使用 dll 文件时,依然找不到 dll。所以要为每一个需要使用 dll 的 java 文件都配置VM options
,虽然还是有些麻烦,但是已经比我们修改 c 代码后,不断的拷贝 dll 文件方便多了。我们的目的还是说快速的了解 JNI 的开发,真正使用 Android Studio 进行 NDK 开发时,就不需要老配置环境了。