01_JNI是什么,为什么使用,怎么用JNI,Cygwin环境变量配置,NDK案例(使用Java调用C代码),javah命令使用

简介: 1 什么是JNI JNI Java本地开发接口 JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(C/C++) 通过这个协议,java代码就可以调用外部的C/C++代码,外部的C/C++代码也可以调用Java代码。 2 为什么用JNI 1  JNI扩展了java虚拟机的能力,驱动开发(wifi-hotspot)2.

1 什么是JNI

JNI Java本地开发接口

JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(C/C++)

通过这个协议,java代码就可以调用外部的C/C++代码,外部的C/C++代码也可以调用Java代码。

2 为什么用JNI

1  JNI扩展了java虚拟机的能力,驱动开发(wifi-hotspot)2.3无线热点共享

2  Native code效率高,数学运算,实时渲染的游戏上,音视频处理(极品飞车),opengl,ffmpeg

3  复用代码(文件压缩,人脸识别)

4  特殊的业务场景

3 怎么用JNI

1 C/C++语言

2 掌握java ini流程

3 NDK(native develop kits)

5 配置cygwin64的环境变量的方式是编写\Cygwin\etc\profile,ndk的路径配置到path里面,截图如下:

打开Cygwin输入:Make –v,结果如下:

显示出来GNI Make的版本,说明我们的cygwin模拟的Linux编辑环境模拟成功。

输入ndk-build,出现以下结果:

显示出上面的效果,说明环境变量已经配置好了。

 

6 同样可以将这个变量配置到windows下的环境变量中:配置如下:

进入CMD命令行窗口中,如果出现以下结果,说明配置成功:

 

当配置了第6步之后,若cygwin没有配置成功时,也可以在window中的cmd命令行中使用ndk-build.

 

7 jni中的数据类型(后面是Java中的类型,左边是C语言中的类型):

#ifdef HAVE_INTTYPES_H

# include <inttypes.h>      /* C99 */

typedef uint8_t         jboolean;       /* unsigned 8 bits */

typedef int8_t          jbyte;          /* signed 8 bits */

typedef uint16_t        jchar;          /* unsigned 16 bits */

typedef int16_t         jshort;         /* signed 16 bits */

typedef int32_t         jint;           /* signed 32 bits */

typedef int64_t         jlong;          /* signed 64 bits */

typedef float           jfloat;         /* 32-bit IEEE 754 */

typedef double         jdouble;        /* 64-bit IEEE 754 */

#else

typedef unsigned char   jboolean;       /* unsigned 8 bits */

typedef signed char     jbyte;          /* signed 8 bits */

typedef unsigned short  jchar;          /* unsigned 16 bits */

typedef short          jshort;         /* signed 16 bits */

typedef int            jint;           /* signed 32 bits */

typedef long long      jlong;          /* signed 64 bits */

typedef float          jfloat;         /* 32-bit IEEE 754 */

typedef double        jdouble;        /* 64-bit IEEE 754 */

#endif

 

/* "cardinal indices and sizes" */

typedef jint            jsize;

8 案例效果(下面的土司是调用C语言代码显示的):

接下来编写案例,使用java代码调用C代码,创建项目helloworldformc,代码结构如下:

其中libs下的内容如下:

9 编写MainActivity,代码如下:

package com.example.helloworldformc;

 

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.widget.Toast;

 

public class MainActivity extends Activity {

         // 1 定义一个c方法的接口   相当于在java代码中定义了一个接口

         //接口的实现方法是C语言实现的

         public native String helloWorldFromC();

          
         // 变态命名
         public native String hello_world_from_c();


         // 5 步在java代码中 引入库函数

         static{

                   System.loadLibrary("hello");// 注意事项 去掉前面的lib 后面的.so

         }

        

         @Override

         protected void onCreate(Bundle savedInstanceState) {

                   super.onCreate(savedInstanceState);

                   setContentView(R.layout.activity_main);

         }

        

         public void click(View view){

                   // 弹出一个土司 土司的内容 c代码写出来       

                   // 6

                   Toast.makeText(getApplicationContext(), helloWorldFromC(), 0).show();

         }

}

10 在项目下创建一个jni目录(这个是必须的),开始编写Hello.c,代码如下:

#include <stdio.h>

#include <jni.h>

 

/*

 * 对应的是:public native String helloWorldFromC(){}

 * jstring:表示的是返回的是String类型的

 * 函数名称规则是:Java_包名_类名_方法名。

 *

 * 注意:包名之间的"."在下面要变成下划线

 */

jstring Java_com_example_helloworldformc_MainActivity_helloWorldFromC(JNIEnv* env,jobject obj) {

    //2  实现C代码

    //返回一个java String类型的字符串,使用一下函数

    //jstring     (*NewStringUTF)(JNIEnv*, const char*);

    //(*env) 相当于 JNINativeInterface* JNIEnv

    //*(*env)  相当于 JNINativeInterface

 

    //可以通过下面两种方式返回参数

    //return (**env).NewStringUTF(env,"helloworldfromc");

 

    return  (*env)->NewStringUTF(env,"helloworldfromc");

 

    //android.mk 告诉编译器  如何把C代码打包成函数库

    //3 生成.mk文件

    //4   C代码  打包成函数库

}


/*这里JNIEXPORT表示的是通过工具生成的,这时候也可以将JNIEXPORT去掉*/

JNIEXPORT jstring JNICALL Java_com_example_helloworldformc_MainActivity_hello_1world_1from_1c


 (JNIEnv * env, jobject obj){


}



注意:上面的这个源文件的类名也可以通过javah命令生成,生成过程如下:

(1)       如果JDK使用的是1.6,使用javah命令前要到达:项目目录\bin\classes目录下

(2)       如果JDK使用的是1.7,使用javah命令前要达到:项目目录\bin\src目录下:

例如(我使用的是JDK1.7)

在项目中生成.h


11 Android.mk文件的内容如下:

#一个Android.mk文件必须下面这个变量开头,它用于定位

#它用于定位你的源文件,my-dir这个宏是构件系统提供的,

#它用于返回当前目录的路径(这个目录包含Android.mk它自己)

LOCAL_PATH := $(call my-dir)

 

#CLEAR_VARS也是build system构件系统提供的,指定到一个指定的GNU Makefile文件

#这个Makefile文件帮你去清除一些LOCAL_XXX变量(比如:LOCAL_MODULE,LOCAL_SRC_FILES

#,LOCAL_STATIC_LIBRARIES.等等...),除了LOCAL_PATH.

include $(CLEAR_VARS)

 

#LOCAL_MODULE变量必须在你的Android.mk文件中定义。名称必须唯一

#并且不能包含一些空格,要注意的是构件系统会自动的添加适当的前缀和前缀

#换一句话说,一个命名为"foo"的共享库模块,会被生成"libfoo.so"文件。

#重要提示:如果你定义的模块名称是"libfoo",构建系统将不会添加"lib"前缀,

#并且也会生成"libfoo.so"文件。

LOCAL_MODULE    := hello

 

 

#LOCAL_SRC_FILES变量必须包含一个C或者C++的源文件集合,这些文件最终会被用于

#生成一个module,注意的是,这里不应该有头文件和包含文件,因为构件系统自动为您

#添加这些文件,只需要列出源文件就行了。

 

#注意:默认的C++源文件的后缀名是.cpp,同样你也可以通过LOCAL_CPP_EXTENSION来自定义

#CPP的后缀名(例如:".cxx"可以,"cxx"不可以)

LOCAL_SRC_FILES := Hello.c

 

include $(BUILD_SHARED_LIBRARY)

12 接下来使用cygwin,使用ndk-build来编译程序

1)、如想将c变成.so的库,需要使用ndk-build命令

2)、将路径路径切换到工程目录下。

3)、然后执行ndk-build这个操作(这个操作直接指定到项目路径下就可以了)

注意:在使用这个ndk-build功能之前,需要有Android.mk文件(告诉编译器,如何将C代码打包成函数库。具体的Android.mk怎么使用可以看ndk中的Android.html文档)

 


目录
相关文章
|
2天前
|
Oracle Java 关系型数据库
windows 下 win11 JDK17安装与环境变量的配置(配置简单详细,包含IJ中java文件如何使用命令运行)
本文介绍了Windows 11中安装JDK 17的步骤,包括从官方网站下载JDK、配置环境变量以及验证安装是否成功。首先,下载JDK 17的安装文件,如果没有Oracle账户,可以直接解压缩文件到指定目录。接着,配置系统环境变量,新建`JAVA_HOME`变量指向JDK安装路径,并在`Path`变量中添加。然后,通过命令行(cmd)验证安装,分别输入`java -version`和`javac -version`检查版本信息。最后,作者分享了如何在任意位置运行Java代码,包括在IntelliJ IDEA(IJ)中创建的Java文件,只需去掉包声明,就可以通过命令行直接运行。
17 0
|
4天前
|
Java
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
13 0
|
5天前
|
Java Spring
Java 效率编码 必备插件 Lombok 让代码更优雅
该内容是一个关于Lombok插件的教程摘要:介绍了Lombok用于减少Java开发中的模板代码,提升效率;讲解了如何在IntelliJ IDEA中安装Lombok插件,以及在pom.xml中添加依赖;并提到了@Data注解能自动生成getter/setter、equals、hashCode和toString方法,@Slf4j注解自动处理日志,@Builder用于构建对象,以及@AllArgsConstructor和@NoArgsConstructor注解生成构造函数。还鼓励探索更多Lombok的注解用法。
|
5天前
|
Java 关系型数据库 测试技术
Java代码一键生成数据库文档(案例详解)
Screw是一个自动化数据库文档生成工具,能根据数据库表结构快速生成简洁、多格式(HTML、Word、Markdown)的文档,支持MySQL、MariaDB等多数据库。它使用Freemarker模板,允许用户自定义样式。依赖包括HikariCP数据库连接池和对应JDBC驱动。通过在Java代码或Maven插件中配置,可方便生成文档。示例代码展示了如何在测试用例中使用Screw。文档效果依赖于数据库中的表和字段注释。
|
5天前
|
NoSQL Java API
java一行代码实现RESTFul接口
Spring Data REST是构建在Spring Data之上的库,可自动将repository转换为REST服务,支持JPA、MongoDB、Neo4j、GemFire和Cassandra。无需手动创建Service和Controller层。要开始,需配置JPA数据源,创建实体类和Repository接口。快速实现REST接口,只需引入spring-boot-starter-data-rest Maven依赖,并在Repository接口上添加@RepositoryRestResource注解。
|
6天前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
15 1
|
22小时前
|
Java
Java中的多线程编程:基础知识与实践
【5月更文挑战第5天】在现代软件开发中,多线程编程是一个重要的概念,尤其是在Java这样的多平台、高性能的编程语言中。通过多线程,我们可以实现并行处理,提高程序的运行效率。本文将介绍Java中多线程编程的基础知识,包括线程的概念、创建和控制方法,以及一些常见的多线程问题和解决方案。
|
4天前
|
存储 缓存 前端开发
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
15 3
|
4天前
|
Java
JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识
JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识。入坑JAVA因它的面向对象特性、平台无关性、强大的标准库和活跃的社区支持。
16 2
|
4天前
|
Java 调度 开发者
Java中的多线程编程:基础与实践
【5月更文挑战第2天】本文将深入探讨Java中的多线程编程,从基础概念到实际应用,为读者提供全面的理解和实践指导。我们将首先介绍线程的基本概念和重要性,然后详细解析Java中实现多线程的两种主要方式:继承Thread类和实现Runnable接口。接着,我们将探讨线程同步的问题,包括synchronized关键字和Lock接口的使用。最后,我们将通过一个实际的生产者-消费者模型来演示多线程编程的实践应用。