Necessitas: convenient solution for communication between Qt application and Java

转载 2013年10月20日 22:22:29

Necessitas: convenient solution for communication between Qt application and Java


This is my first article about Qt / Necessitas / Android / JNI, so if you will find some error or have some ideas, please, contact me. I didn't use these technologies before. Everything what I present, works with my software configuration: Qt 4.8.0, Necessitas 0.3.4, Android 3.2.

In this article I will present my solution for using Java in Necessitas projects. As far as most of you know, to use Java code in C++ applications and vice-versa, you need to use Java Native Interface (JNI). This technology is used in Necessitas projects and you can find it for example in file qtmain_android.cpp located in:necessitas/Android/Qt/{{VERSION_OF_QT}}/armeabi-v7a/src/android/cpp. In my case, {{VERSION_OF_QT}} is 480. This file is included to your projects during building process.

We can say that qtmain_android.cpp is the most important file for JNI in your project because it containsJNI_OnLoad(.). This function is the only one which is allowed to load any Java class, so this is the only place in your application where you can load these yours. Of course, it's possible to load Java classes in other functions, but you are limited to use only some of these from java.* package.

I found an article (little bit vague for me) which deliver some solution for this problem: How to use Java from Qt/C++ in Necessitas.

There is no code example but fortunately I found this: QT in Android -- Example for accessing the GPS Service.

In both cases, authors are changing qtmain_android.cpp file. This approach has two disadvantages:

  1. qtmain_android.cpp is common for all projects, so all your projects require all classes that you load there,
  2. you can use only one version of constructor of your class,
  3. qtmain_android.cpp is part of Necessitas and it will be probably changed in newer versions.

Let's deal with first two disadvantages. It's hard to create special class which would be good for all possible applications ((-: ) so we need to find another solution. Let's make little changes in qtmain_android.cpp file.

Firstly, add this line before JNI_OnLoad(.) definition (of course outside bodies of functions!):

extern int JavaClassesLoader (JNIEnv* env);

Secondly, put this code into JNI_OnLoad(.) defintion:

    if (!JavaClassesLoader (m_env)){
        __android_log_print (ANDROID_LOG_FATAL, "Qt", "Couldn't register user defined classes!");
        return -1;
    }

Notice, that we use m_env variable so we need to put it below this line:

m_env = uenv.nativeEnvironment;

Thirdly, we need to remove static key-words at this two lines:

static JavaVM *m_javaVM = NULL;
static JNIEnv *m_env = NULL;

And that's all what we need to change in qtmain_android.cpp file.

Now, let's add file which will load our Java classes. In NecessitasQtCreator choose File -> New File or Project -> (Files and Classes) C++ -> C++ Source File -> Choose... Set a Name to JavaClassesLoader.cpp, click Continue and after Done. Fill your file with this code:

#include <jni.h>
#include <android/log.h>

jobject classPointer;

int JavaClassesLoader (JNIEnv* env){
    {
        const char* className = "pl/ekk/mkk/necessitas/YourClassName";
        jclass clazz=env->FindClass(className);
        if (!clazz)
        {
            __android_log_print(ANDROID_LOG_FATAL,"Qt", "Unable to find class '%s'", className);
            return JNI_FALSE;
        }
        jmethodID constr = env->GetMethodID(clazz, "<init>", "()V");
        if(!constr) {
            __android_log_print(ANDROID_LOG_FATAL,"Qt", "Unable to find a constructor for class '%s'", className);
            return JNI_FALSE;
        }
        jobject obj = env->NewObject(clazz, constr);
        classPointer = env->NewGlobalRef(obj);
    }
    return JNI_TRUE;
}

I guess that you already know that to use multiple Java classes in your project, you just need to create otherjobject classPointer, copy-paste code of JavaClassesLoader(.) function (without last line!) and change value of constant className.

To use different constructor than version without arguments, you need to set different method signatures (see more here). To set arguments values, just add them to NewObject (.) method.

But where should you place your Java file? In your project folder you have android/src/ branch. This is right localisation for your files. Notice, that your classes are inside packages, so you need to create folder trees corresponding to packages that you are using. After you copy your files you need to add them to Necessitas project (Add Existing Files).

Now we can use your Java classes in your project. Open your C++ filein which you want use JNI, put this four lines at its beginning:

#include <jni.h>
#include <qDebug>
extern JavaVM *m_javaVM;
extern jobject classPointer;

This will give us a way to use variables from previous files. To call JNI functions, you need to use this code:

JNIEnv* env;
if (m_javaVM -> AttachCurrentThread (&env, NULL) < 0){
    qCritical() << "AttachCurrentThread failed";
    return;
}

jclass applicationClass = env -> GetObjectClass (classPointer);

if (applicationClass){
    //Communication between C++ and JAVA!
}

m_javaVM -> DetachCurrentThread ();

That's all! Now you can use your Java classes in more customized way! (-:

I hope that I explained it quite clearly. If your C++ files cannot find variables from different files that we changed, please clean your project (Build -> Clean Project...).

If you still have some problem, I attach small example.

If you want, you can try to use #ifdef#define and #endif in qtmain_android.cpp to easily turn on and turn off usingJavaClassesLoader(.) in your projects.

But... still we have a third disadvantage... I have to admit that I didn't found a good solution for that. Here, I present an effect of my research, I hope that someone will find some good way to deal with it.

It is possible to access to Java Virtual Machine without changing qtmain_android.cpp file (so we don't need to do third step).

The biggest problem is how to use JavaClassesLoader(.) function outside qtmain_android.cpp file, or in another words, outside JNI_OnLoad(.) definition. You can find an explanation of this problem here: FindClass failed.

I tried to use this solutions: Using JNI from a Native Activity, but unfortunately FindClass method can't findjava.lang.ClassLoader, so it seems to be useless for us.

Well, for now, that's all. If anyone will find some solution for third disadvantage or want to discuss about my solution for first one, please contact me.

引用自:http://mkk.ekk.pl/?wpis=3

Android上运行QT项目Necessitas的基本原理

by 宋宝华 There is a project named Necessitas (by BogdanVatra)which implements a basic support of c...
  • 21cnbao
  • 21cnbao
  • 2012年01月18日 16:25
  • 5239

Codeforces Round #444 (Div. 2) C. Solution for Cube

C. Solution for CubeProblem Statement     During the breaks between competitions, top-model Izabel...
  • Effervescence
  • Effervescence
  • 2017年11月05日 16:07
  • 211

There is a circular dependency between XMPPFramework/Core and XMPPFramework/Authentication

执行"pod install" 或者 "pod update" , xmppframework 会出现循环依赖问题。 There is a circular dependency betwe...
  • CB1234CB
  • CB1234CB
  • 2015年06月29日 09:41
  • 893

android process communication between two application

实现两个application之间的进程通信,需要用到service,并且在client端根据是否需要多线程可以分成使用Messenger和AIDL两种方法来实现。当你的client端需要多个线程时,...
  • almo_omla
  • almo_omla
  • 2016年05月25日 11:23
  • 140

sharepoint 模板安装

  找了很久,也下载过,但是没有仔细看安装文档,使用上传模板的方法,在创建网站是根本看不到要选择的模板。 这次偷懒,直接从microsoft上copy的。亲自试过,very ez! 模板下载 http...
  • apensu
  • apensu
  • 2010年12月28日 14:49
  • 2786

SharePoint部署

最近在学习SharePoint,于是把自己学习的点滴记录写来,以备后来查阅。本文着重阐述WSS3.0的一些部署方法。(一):微软模板的安装我们首先需要下载微软的应用程序核心模板(Application...
  • Hardee
  • Hardee
  • 2007年11月30日 10:18
  • 145

Codeforces 887C - Solution for Cube 【魔方旋转】

Codeforces 887C - Solution for Cube 【魔方旋转】 During the breaks between competitions, top-model Izabell...
  • my_sunshine26
  • my_sunshine26
  • 2017年11月04日 11:28
  • 443

Qt运行一个实例进程-3种方式简介

一:使用QLocalSocket    方式:首先一个新的实例启动时,将尝试连接到同一个本地服务器,如果连接失败,则表示第一个实例进程,创建一个本地服务器。否则,进行退出。(.pro里加上QT += ...
  • taiyang1987912
  • taiyang1987912
  • 2015年07月21日 18:10
  • 4514

3-Transport Layer

Please indicate the source: http://blog.csdn.net/gaoxiangnumber1 Welcome to my github: https://gith...
  • gaoxiangnumber1
  • gaoxiangnumber1
  • 2016年07月18日 08:52
  • 2529

BCB 写服务的时候不能用 Application->ExeName

 [C++ Error] Unit2.cpp(74): E2015 Ambiguity between 'Application' and 'Svcmgr::Application' 写成: ...
  • cddchina
  • cddchina
  • 2015年05月22日 23:06
  • 696
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Necessitas: convenient solution for communication between Qt application and Java
举报原因:
原因补充:

(最多只允许输入30个字)