JNI是什么

  JNI是java平台的一个特性(与Android无关)

  英文参考文档中的介绍如下:

  The Java™ Native Interface (JNI) is a powerful feature of the Java platform.

  Applications that use the JNI can incorporate native code written in programming

  languages such as C and C++, as well as code written in the Java programming

  language. The JNI allows programmers to take advantage of the power of the Java

  platform, without having to abandon their investments in legacy code. Because the

  JNI is a part of the Java platform, programmers can address interoperability issues

  once, and expect their solution to work with all implementations of the Java plat-

  form.

  JDK环境搭建

  想要使用jni,需要搭建好jdk环境。

  jdk-8u211-linux-x64.tar.gz 的下载地址:

  https://download.oracle.com/otn/java/jdk/8u211-b12/478a62b7d4e34b78b671c754eaaf38ab/jdk-8u211-linux-x64.tar.gz?AuthParam=1559785898_96645c696d32befddea78681f9c1926f

  把jdk-8u211-linux-x64.tar.gz解压到/usr/local/jdk目录下,然后修改~/.bashrc文件,在该文件最后面,添加如下内容:

  #JDK

  export PATH=/usr/local/jdk/jdk1.8.0_211/bin/:$PATH

  然后使用 source ~/.bashrc命令更新环境变量。

  判断环境是否配置成功:

  root@ubuntu:/usr/local/jdk# java -version

  java version "1.8.0_211"

  Java(TM) SE Runtime Environment (build 1.8.0_211-b12)

  Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

  root@ubuntu:/usr/local/jdk#

  如所示,jdk环境搭建完成。

  使用流程:

  JNI测试

  下面介绍jni的测试过程。

  HelloWorld.java 文件

  新建 HelloWorld.java文件,并填充代码如下。

  class HelloWorld {

  private native void print();

  public static void main(String[] args) {

  new HelloWorld().print();

  }

  static {

  System.loadLibrary("HelloWorld");

  }

  }

  使用如下命令编译,生成 HelloWorld.class文件:

  root@ubuntu:~/ken/jni# javac HelloWorld.java

  root@ubuntu:~/ken/jni# ls

  HelloWorld.class HelloWorld.java

  root@ubuntu:~/ken/jni#

  HelloWorld.h 文件

  使用如下命令编译,生成HelloWorld.h文件。之后根据该.h文件,编写jni的.c文件。

  root@ubuntu:~/ken/jni# ls

  HelloWorld.class HelloWorld.java

  root@ubuntu:~/ken/jni# javah -jni HelloWorld

  root@ubuntu:~/ken/jni# ls

  HelloWorld.class HelloWorld.h HelloWorld.java

  root@ubuntu:~/ken/jni#

  打开HelloWorld.h文件,内容如下:

  /* DO NOT EDIT THIS FILE - it is machine generated */

  #include

  /* Header for class HelloWorld */

  #ifndef _Included_HelloWorld

  #define _Included_HelloWorld

  #ifdef __cplusplus

  extern "C" {

  #endif

  /*

  * Class: HelloWorld

  * Method:print

  * Signature: ()V

  */

  JNIEXPORT void JNICALL Java_HelloWorld_print

  (JNIEnv *, jobject);

  #ifdef __cplusplus

  }

  #endif

  #endif

  HelloWorld.c 文件

  则我们编写HelloWorld.c文件如下:

  #include

  #include

  #include "HelloWorld.h"

  JNIEXPORT void JNICALL

  Java_HelloWorld_print(JNIEnv *env, jobject obj)

  {

  printf("Hello World!\n");

  return;

  }

  libHelloWorld.so 动态库文件

  接下来,把HelloWorld.c文件编译成动态库:libHelloWorld.so即可。

  PS:

  1、此处编译出的动态库的名称,是HelloWorld.java文件中定义了的。

  System.loadLibrary(“HelloWorld”);

  上面这条程序的作用就是加载libHelloWorld.so库文件。

  2、在HelloWorld.h文件中函数声明是:

  JNIEXPORT void JNICALL Java_HelloWorld_print

  (JNIEnv *, jobject);

  在HelloWorld.c文件中函数定义为:

  JNIEXPORT void JNICALL

  Java_HelloWorld_print(JNIEnv *env, jobject obj)

  如果函数参数中没有定义*env和obj,则会在编译库时报错:

  HelloWorld.c: In function ‘Java_HelloWorld_print’:

  HelloWorld.c:6:1: error: parameter name omitted

  Java_HelloWorld_print(JNIEnv, jobject)

  ^

  HelloWorld.c:6:1: error: parameter name omitted

  3、笔者这边是在linux环境下测试的。如果是windwows的话,编译出.dll文件。

  接下来,编译出动态库:

  root@ubuntu:~/ken/jni# gcc -shared -fPIC -Wall HelloWorld.c -o libHelloWorld.so

  HelloWorld.c:1:17: fatal error: jni.h: No such file or directory

  #include

  ^

  compilation terminated.

  root@ubuntu:~/ken/jni#

  如上,报错显示找不到动态库。

  此时就和之前的jdk环境搭建有关系了。

  root@ubuntu:~/ken/jni# ls /usr/local/jdk/jdk1.8.0_211/include/

  classfile_constants.h jawt.h jdwpTransport.h jni.h jvmticmlr.h jvmti.h linux

  root@ubuntu:~/ken/jni#无锡人流多少钱 http://www.bhnfkyy.com/

  我们发现,在jdk中有我们需要的jni.h文件。

  现在我们有两种方式可以解决这个报错。

  第一种是把#include 改为#include "jni.h",然后把jdk中的jni.h文件拷贝到当前目录下。

  第二种是在编译时通过“-I加头文件路径”,让编译器找到jni.h文件。

  我们使用第二种。

  继续编译动态库。

  root@ubuntu:~/ken/jni# gcc -shared -fPIC -Wall -I/usr/local/jdk/jdk1.8.0_211/include HelloWorld.c -o libHelloWorld.so

  In file included from HelloWorld.c:1:0:

  /usr/local/jdk/jdk1.8.0_211/include/jni.h:45:20: fatal error: jni_md.h: No such file or directory

  #include "jni_md.h"

  ^ 

  compilation terminated.

  root@ubuntu:~/ken/jni#

  报错找不到jni_md.h文件。如果查看jni.h文件的话,会发现里面有包含jni_md.h文件。

  jni_md.h文件在:(使用grep命令,在jdk目录下搜索)

  root@ubuntu:~/ken/jni# ls /usr/local/jdk/jdk1.8.0_211/include/linux/

  jawt_md.h jni_md.h

  root@ubuntu:~/ken/jni#

  把该路径添加到-I参数,继续编译动态库。

  root@ubuntu:~/ken/jni# gcc -shared -fPIC -Wall -I/usr/local/jdk/jdk1.8.0_211/include -I/usr/local/jdk/jdk1.8.0_211/include/linux HelloWorld.c -o libHelloWorld.so

  root@ubuntu:~/ken/jni# ls

  HelloWorld.c HelloWorld.class HelloWorld.h HelloWorld.java jni.h libHelloWorld.so

  root@ubuntu:~/ken/jni#

  成功编译出libHelloWorld.so动态库。

  测试JNI程序

  root@ubuntu:~/ken/jni# ls

  HelloWorld.c HelloWorld.class HelloWorld.h HelloWorld.java jni.h libHelloWorld.so

  root@ubuntu:~/ken/jni# java HelloWorld

  Hello World!

  root@ubuntu:~/ken/jni#

  成功运行C代码中函数。

  ————————————————————————————————

  上面只是简单的jni调用,了解jni的大致调用流程。

  关于JNI还有很多需要了解的,比如参数类型、函数传参等。

  —————————————————————————————————

  需要强调的是,虽然jni和ndk经常一起使用。但是jni是jni,ndk是ndk,是两码事。

  什么时候需要ndk呢?用到Android时,就需要ndk了。

  上面编译动态库的过程也不是通过gcc编译了,而是使用ndk提供的ndk-build工具,编译出动态库,给apk调用。


更多相关文章

  1. Android文件递归遍历
  2. android 不使用布局文件,完全由代码控制布局实例
  3. Android 动态布局
  4. Android 删除SD卡文件和文件及创建文件夹和文件
  5. android 读写文件数据
  6. android源代码下载——android环境配置
  7. android 通过资源文件名称获取资源文件id
  8. 迈向Android的第一步 - 搭建Android开发环境
  9. Android 文件读写 + sdcard + 文件的属性

随机推荐

  1. Android(安卓)客户端起HttpServer NanoHt
  2. [Android] (Android 视频悬浮窗)
  3. Android sdk下载找不到support library
  4. Android设置Settings:PreferenceFragment
  5. Android 响应System UI状态,焦点改变,手势
  6. android 自定义 permission 权限
  7. Ogre3D 1.8.1 Android移植
  8. Android EventBus源码分析
  9. Android M5 新特性
  10. [置顶] Android(安卓)Launcher全面剖析