Android JNI调用概要

一、Java调C

  1. 编写Native方法。
  2. 使用javah命令生成.h头文件。
  3. 复制.h头文件到CPP工程中。
  4. 复制jni_md.h和jni.h到CPP工程中。
  5. 实现.h头文件中生成的。
  6. 生成dll文件。

C的函数名称:Java_包名_方法名称。

1、java:Test

public class Test {
    public static void main(String[] args) {
        System.out.println(Test.class.getName());
    }

    public static native  void getStringFormC();
}

2、javah:Test.h

命令:javah Test

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Test */

#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Test
 * Method:    getStringFormC
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Test_getStringFormC
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

3、c实现:Test.cpp

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class Test */

#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Test
 * Method:    getStringFormC
 * Signature: ()V
 */
JNIEXPORT jstring JNICALL Java_Test_getStringFormC(JNIEnv* env, jclass) {
  //将C的字符串转为JAVA的字符串
  return env -> NewStringUTF("C string");
}

#ifdef __cplusplus
}
#endif
#endif

二、Android JNI

1、Android Studio创建C++项目

2、app/src/main/cpp/CMakeLists.txt: 

# 版本号
cmake_minimum_required(VERSION 3.10.2)

# 项目名称,没有实际意义,可以选填
project("testc1")

# 添加写的cpp项目注意需要在追加在最后面,有先后顺序的
add_library(
		# 参数1:依赖库的名称,仅此一个,在System.loadLibrary("testc1")使用
        testc1

        # 参数2:
        SHARED

        # 参数3:生成的或者自己写的cpp需要加在后面,不能插入到前两个参数中
        native-lib.cpp)


find_library( 
        log-lib

        log)

target_link_libraries( 
        testc1
)

关于CMake 使用:https://mp.weixin.qq.com/s/XFwHkg89qifyUqlSOSJUdw

3、app/src/main/cpp/native-lib.cpp

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_simple_testc1_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {
	// 将C的字符串转为JAVA的字符串
    char* hello = "Hello from C++666";
    return env->NewStringUTF(hello);
}

4、app/src/main/java/com/simple/testc1/MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Example of a call to a native method
        binding.sampleText.text = stringFromJNI()
    }

    /**
     * A native method that is implemented by the 'testc1' native library,
     * which is packaged with this application.
     */
    private external fun stringFromJNI(): String

    companion object {
        // Used to load the 'testc1' library on application startup.
        init {
            System.loadLibrary("testc1")
        }
    }
}

效果图:

三、JNIEnv调用分析

  • 在C++中JNIEnv是一个结构体_JNIEnv
  • 在C语言中JNIEnv是一个结构体指针JNINativeInterface*
struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;

#if defined(__cplusplus)
//在C++中JNIEnv是一个结构体_JNIEnv
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
//在C语言中JNIEnv是一个结构体指针JNINativeInterface*
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif

env->NewStringUTF(hello):

C++:

struct _JNIEnv {
   const struct JNINativeInterface* functions;
#if defined(__cplusplus)

jstring NewStringUTF(const char* bytes){ 
  //参数this,表示上下文环境即:env 
  return functions->NewStringUTF(this, bytes); 
}

#endif

调用functions的NewStringUTF,即调用C语言中的NINativeInterface*

C语言:

struct JNINativeInterface {
  //参数1:JNIEnv指针,参数2:字符串
  jstring   (*NewStringUTF)(JNIEnv*, const char*);
}

关于JNIEnv详细解析参考: Android JNI 之 JNIEnv 解析

四、JNI引用变量

引用类型:局部引用和全局引用。

1、局部引用

  • 访问一个很大的JAVA对象,使用完成之后进行复杂的耗时操作。
  • 创建了大量的局部引用,占用的内存太多,而这些局部操作和后面的引用没有关联性。

通过DeleteLocalRef手动释放。

env -> DeleteLocalRef(obj)

2、全局引用

全局共享:创建,获得,释放。三步走,共享可以跨线程,在任意地方调用。

env -> DeleteGlobalRef(obj)

源码:

void DeleteGlobalRef(jobject gref) {
    functions->DeleteGlobalRef(this,gref);
}
void DeleteLocalRef(jobject obj) {
    functions->DeleteLocalRef(this, obj);
}

3、弱全局引用

  • 节省内存,在内存不足的时候释放所引用的对象。
  • 可以引用一个不常用的对象,如果内NULL,临时创建。

源码:

jweak NewWeakGlobalRef(jobject obj) {
    return functions->NewWeakGlobalRef(this,obj);
}
void DeleteWeakGlobalRef(jweak ref) {
    functions->DeleteWeakGlobalRef(this,ref);
}

五、JNI异常处理

  • 保证java可以运行。
  • 保证后面的C代码可以继续运行。

示例:

jthrowable exception = env->ExceptionOccurred();
if (exception != NULL) {
    //可以让java代码继续运行,请空异常信息
    env->ExceptionClear();
}

源码:

jthrowable ExceptionOccurred() {
    return functions->ExceptionOccurred(this);
}
void ExceptionDescribe() {
    functions->ExceptionDescribe(this);
}
void ExceptionClear() {
    functions->ExceptionClear(this);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值