Android-JNI调用

JNI的概念

JNI的全称是Java Native Interface。他提供了一种让运行在JVM中的Java代码与C/C++代码交互的方式。应用层和JVM厂商都遵从JNI的规范,这样应用层只需要写一套调用Native层的代码,不需要修改代码兼容不同的JVM实现或版本。Java代码通常是用UTF-16编码的,C/C++的通常采用UTF-8,这种编码方式的转换JNI已经为我们实现了。

JNI的用法

普通java调用
  1. 在Java类已中声明native接口函数,例如:在Hello.java中添加native函数声明public native static void helloNative();
  2. 用 javac 命令将.java源文件编译成.class字节码文件
  3. 用 javah 命令,根据class字节码文件生成.h头文件
  4. 创建C/C++文件,实现.h文件中的接口
  5. 用gcc命令将C/C++文件编译成.so文件
  6. 在Hello.java中调用System.loadLibrary("name")加载动态库文件
Android调用

由于使用javah命令得到的.h文件里函数的规则是固定的,即:Java_类全路径_方法名,因此我们可以不通过javah命令生成头文件。

  1. 在AndroidStudio里下载配置好NDK
  2. 创建一个Android项目,在需要调用的native方法的类中声明所需的native方法。
  3. 在外部(非Android项目目录)新建一个jni目录,新建test.h、test.cpp、Android.mk、Application.mk目录。其中test.h就是按照javah生成的头文件形式创建的。例如:
//test.h
#ifndef __TEST__
#define __TEST__

#include <jni.h>

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_com_hl_TestHello_helloJNI(JNIEnv *env, jobject thiz);

#ifdef __cplusplus
}
#endif

#endif 
  1. 在test.cpp中include test.h文件,实现native接口。
  2. 在Android.mk中配置好编译项
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := test-jni

LOCAL_SRC_FILES := test.cpp

LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog

#LOCAL_LDFLAGS += -ljnigraphics
include $(BUILD_SHARED_LIBRARY)
  1. 在Application.mk中配置编译的目标平台
APP_ABI := all
APP_STL :=c++_shared
  1. 在从终端进入jni目录下,执行ndk-build命令。编译成功后,相应的SO文件在与jni同级目录下的libs文件夹下面。
  2. 将SO文件拷贝到安卓项目中main/jniLibs下
  3. 在调用native方法的Java类中,加载so库:System.loadLibrary("test-jni");

JNI调试

AndroidStudio为开发者提供了一套调试C/C++的工具。这套工具非常强大,能让我们修改完native层的代码之后,立刻编译成SO运行起来。官方教程https://developer.android.com/studio/debug/?hl=zh-cn

JNI使用注意

  1. 什么时候要主动调用Release方法释放资源?
    答:释放的资源主要包括引用和变量。
    引用资源释放:JNI 规范中定义了三种引用:局部引用(Local Reference)、全局引用(Global Reference)、弱全局引用(Weak Global Reference)。局部引用:通过 NewLocalRef 和各种 JNI 接口创建(FindClass、NewObject、GetObjectClass和NewCharArray等)。会阻止 GC 回收所引用的对象,不在本地函数中跨函数使用,不能跨线前使用。函数返回后局部引用所引用的对象会被JVM 自动释放,或调用 DeleteLocalRef 释放。全局引用:调用 NewGlobalRef 基于局部引用创建,会阻 GC 回收所引用的对象。可以跨方法、跨线程使用。JVM 不会自动释放,必须调用 DeleteGlobalRef 手动释放。弱全局引用:调用 NewWeakGlobalRef 基于局部引用或全局引用创建,不会阻止 GC 回收所引用的对象,可以跨方法、跨线程使用。引用不会自动释放,在 JVM 认为应该回收它的时候(比如内存紧张的时候)进行回收而被释放。或调用DeleteWeakGlobalRef 手动释放。
    变量释放:(1)通过(*env)->GetStringUTFChars获取的,要通过(*env)->ReleaseStringUTFChars释放。
    (2)通过调用GetIntArrayElements等获取数组的方法的,需要调用对应的释放函数释放资源。

  2. 什么时候需要注意检测处理异常?
    答:使用JNIEnv调用其函数,比如FindClass、GetFiledID等方法时,都会有可以返回为NULL,导致接下来的程序出现异常,因此在这些地方我们都需要进行异常检测处理。

参考文章

Oracle JNI Guide
使用 Java Native Interface 的最佳实践
Google AndroidDeveloper JNI Tips

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android JNI是一种可用于在Java代码中调用C/C++代码的技术,驱动ko则是指内核模块文件,通常用于实现与硬件设备的交互。在Android应用中,我们可以使用JNI调用驱动ko,实现与底层硬件的交互。 要在Android应用中调用驱动ko,首先需要在应用中使用JNI技术编写C/C++代码,实现与驱动ko的交互逻辑。在C/C++代码中,我们可以通过使用Linux系统提供的API来访问并且控制驱动ko。通过JNI,我们可以将C/C++代码嵌入到Java代码中,并在Android应用中调用这些代码。 具体来说,调用驱动ko的过程如下: 1. 在JNI层编写与驱动ko交互的C/C++代码。这些代码可以使用Linux系统提供的ioctl函数等API来与驱动ko进行通信,并发送相应的指令和数据。 2. 在Java层编写对应的JNI接口和方法。这些方法将与JNI层的C/C++代码进行绑定,以便在Java代码中调用这些方法来间接调用驱动ko。 3. 在Java代码中加载JNI库,并调用JNI接口方法。加载JNI库可以使用System.loadLibrary方法,然后在Java代码中就可以调用JNI接口方法,进而间接调用驱动ko。 通过这种方式,我们可以在Android应用中通过JNI技术调用驱动ko,实现与底层硬件的交互。注意,使用JNI调用驱动ko需要确保设备具备相应的权限,否则可能会出现权限不足的错误。同时,也需要确保驱动ko文件存在于系统中,并且可以被应用访问到。 总之,使用Android JNI可以实现在应用中调用驱动ko文件的功能,通过编写C/C++代码并与Java代码进行绑定,实现与底层硬件交互的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值