JNI调用C语言

Posted 一杯清泉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI调用C语言相关的知识,希望对你有一定的参考价值。

一、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
)

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调用C语言的主要内容,如果未能解决你的问题,请参考以下文章

JNI和NDK

我的C/C++语言学习进阶之旅转载:实现一个在JNI中调用Java对象的工具类

我的C/C++语言学习进阶之旅转载:实现一个在JNI中调用Java对象的工具类

Android JNI编程—JNI基础

Android JNI之Java和C互相调用

Android JNI之Java和C互相调用