使用JNI进行JAVA 与 C++ 的通讯(Qt JNI Messenger实例介绍)——安卓开发、Qt

前言

用Qt开发安卓免不了需要调用底层的代码,也就是调用java功能函数,这就用到了JNI了。

JNI基础知识点

关键词native

native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件(即只在此处声明),而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。

jobject、 jclass

通过看名字就可猜想到:jclass 为类本身,jobject为类实例,

总的来说:

  • 当Java中定义的native方法为静态方法时,则第二个参数为jclass,jclass代表native方法所属类的class本身
  •  当Java中定义的native方法为非静态方法时,则第二个参数为jobject,jobject代表native方法所属类的实例对象

具体可看下面文章了解:

JNI/NDK入门指南之jobject和jclass_jni jobject_IT先森的博客-CSDN博客

 JNIEnv

JNIEnv是提供JNI Native函数的基础环境,线程相关,不同线程的JNIEnv相互独立,并且JNIEnv是一个JNI接口指针,指向了本地方法的一个函数表,该函数表中的每一个成员指向了一个JNI函数,本地方法通过JNI函数来访问JVM中的数据结构。

具体可看下面文章了解:

JNI/NDK入门指南之JavaVM和JNIEnv_javavm jni_IT先森的博客-CSDN博客

JNINativeMethod

JNINativeMethod 该结构体用于描述需要注册的JNI native方法信息。 在注册函数表JNIEnv::RegisterNatives里传入。

    jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
        jint nMethods)

具体看下面文章,学习使用:

JNI 之 JNINativeMethod——安卓_十年之少的博客-CSDN博客

使用

pro文件

QT += androidextras

java调用C++

java代码中定义native方法

package org.qtproject.example.jnimessenger;

public class JniMessenger
{
    //用 native 声明的方法表示告知 JVM 调用,该方法在外部定义,一个native Method就是一个 Java 调用非 Java 代码的接口。
    private static native void callFromJava(String message);

    public JniMessenger() {}

    public static void printFromJava(String message)
    {
        System.out.println("This is printed from JAVA, message is: " + message);

       //这里调用了native方法(外部实现的)
        callFromJava("Hello from JAVA!");
    }
}

在c++中实现:这里是 调用了c++ JniMessenger 实例发射信号messageFromJava,入参value传入了信号。C++中定义的实现都是这种格式

 static 【return】 funcName (JNIEnv *env, jclass ,【arg1,arg2 ...】)  或者

【return】 funcName (JNIEnv *env, jobject,【arg1,arg2 ...】)

JniMessenger *JniMessenger::m_instance = nullptr;

static void callFromJava(JNIEnv *env, jclass /*thiz*/, jstring value)

{
    emit JniMessenger::instance()->messageFromJava(env->GetStringUTFChars(value, nullptr));
}

 jstring 转为 char* 

const char* GetStringUTFChars(jstring string, jboolean* isCopy) 

 上面是用C++实现了callFromJava,但是要想与java中的关联起来,还需要将此函数指针在JNIEnv中注册,上面基础知识中说过“JNIEnv是一个JNI接口指针,指向了本地方法的一个函数表,”,我们需要做的将此函数,注册到此函数表中

JniMessenger::JniMessenger(QObject *parent) : QObject(parent)
{
    m_instance = this;

   //c++ 本地定义的 jni native方法
    JNINativeMethod methods[] {{"callFromJava", "(Ljava/lang/String;)V", reinterpret_cast(callFromJava)}};

    QAndroidJniObject javaClass("org/qtproject/example/jnimessenger/JniMessenger");

   //注册
    QAndroidJniEnvironment env;
    jclass objectClass = env->GetObjectClass(javaClass.object());
    env->RegisterNatives(objectClass,
                         methods,
                         sizeof(methods) / sizeof(methods[0]));
    //释放内存
    env->DeleteLocalRef(objectClass);
}

 

C++调用java

c++ 调用java函数比较简单,如下

静态函数示例:

void JniMessenger::printFromJava(const QString &message)
{
    QAndroidJniObject javaMessage = QAndroidJniObject::fromString(message);
    QAndroidJniObject::callStaticMethod("org/qtproject/example/jnimessenger/JniMessenger", //类名
                                       "printFromJava",//函数名
                                       "(Ljava/lang/String;)V",//(参数类型)返回类型
                                        javaMessage.object());//传入参数
}

普通函数示例(假如java中定义的printFromJava是普通函数):

void JniMessenger::printFromJava(const QString &message)
{
    QAndroidJniObject javaMessage = QAndroidJniObject::fromString(message);

    QAndroidJniObject javaClass("org/qtproject/example/jnimessenger/JniMessenger");
    javaClass.callObjectMethod("printFromJava",
                               "(Ljava/lang/String;)V",
                                javaMessage.object());
}

 

结束语

这只是个开始,若是想玩转安卓,还是得学习或了解整套框架。

你可能感兴趣的:(Qt,For,Android,JNI)