Windows下用QtCreator和C++写Android程序-下

来源:互联网 发布:淘宝卖家用什么app 编辑:程序博客网 时间:2024/06/05 17:37

在上面的文章中,工程基本能编译了。但是在上面的情况下,C++的代码还不能起作用。要用到C++,必须用NDK中的JNI。JNI是Java和C++的接口层,用于在两种语言之间互相调用的。对于Java端,需要调用C++应该怎么办呢?这点我们不用操心,Google已经为我们做好了;我们是C++程序员,那么要调用到其他模块的功能,我们知道,首先一定要include某个头文件才行。所以,要用JNI去访问Java提供的功能,先加上一个

#include <jni.h>

由于我们先前已经配置过Android的SDK和NDK的路径,所以这里直接加上include就应该能找到这个头文件,如果找不到说明配置的不对,需要仔细检查一下上面的配置。
加上头文件后,基本就可以写C++的功能代码了。但是在写代码之前,我们要稍微了解一下Android系统程序的工作机制。我们知道在Windows系统上或Linux系统上,C++编写的程序都有一个入口函数main,操作系统调用我们的程序是从main函数开始的。那么在Android上,怎么使我们的C++功能代码被Android调用呢?有一点我们首先要知道,在Android系统上运行的每一个程序,都是在一个独立的java虚拟机上执行的,那么如果我们的C++代码要加入到这个程序的执行过程中,首先要得到Java虚拟机的执行环境。在NDK的框架下,Google给我们准备了两个对象处理这方面的工作

struct _JNIEnv;struct _JavaVM;

它们的具体实现我们暂且不用关心,只要得到它们的指针,我们就可以在C++里调用Java的功能函数了。JNIEnv是从属于JavaVM的,只要得到JavaVM,我们就可以得到JNIEnv,然后通过JNIEnv去调用Java功能函数。那么怎么得到JavaVM对象指针呢?这里就用到JNI_OnLoad函数。这个函数是Android上运行的Java程序调用我们C++代码时寻找的函数,它会在这个函数中把JavaVM的指针通过这个函数传进来:

JavaVM* g_vm=NULL;/** isoftstone XiangjianChen* Returns the JNI version on success, -1 on failure.*/JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){    jint result = -1;    g_vm=vm;    result = JNI_VERSION_1_4;    return result;}

得到了JavaVM,再获取JNIEnv的指针:

JavaVM* javavm=g_vm;JNIEnv* jni_env=NULL;if((*javavm).AttachCurrentThread(&jni_env, NULL) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本{    return;}

得到了JNIEnv的指针,我们就可以开始调用Java的功能代码了。要在C++中调用Java的功能函数稍微有点麻烦,总共分3步:
1. 获取某个对象实例或某个类;
2. 通过这个类获取类中某个方法的ID;
3. 通过这个类和获取的方法ID调用这个方法。

//1.获取context对象实例jobject context = getGlobalContext(jni_env);if(context==0){    QMessageBox::warning(this, "Failed", "FindClass failed");    return;}//2.获得getSystemService方法jmethodID method_getSystemService = jni_env->GetMethodID(jni_env->GetObjectClass(context), "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");if(method_getSystemService==0){    QMessageBox::warning(this, "Failed", "GetMethodID getSystemService failed");    return;}//3.获得getSystemService方法jstring arg = jni_env->NewStringUTF("location");jobject location_manager = jni_env->CallObjectMethod(context, method_getSystemService, arg);if(location_manager==0){    QMessageBox::warning(this, "Failed", "CallStaticObjectMethod getSystemService failed");    return;}

上面的代码涉及到较多的JNI的内容,具体使用方法会在其他文章中介绍。这部分代码的主要功能只是调用Android系统的getSystemService方法获取系统的位置服务,这个工作在Java里只需一行代码就搞定了,在我们C++里看上去是那么复杂。但是其实我们可以把这3个步骤封装到一个函数中,这样就可以简化我们的代码。
用Java写过Android程序的同学可能会发现,我们没有为这个程序提供任何Activity,没有设计过界面,那么我们的App跑起来是什么样?我们是否还记得在上面的步骤中,在创建工程的时候,我们选择了使用Qt的界面文件,也就是后缀是.ui的文件,那么在工程中我们就有至少一个mainwindow.ui的文件,这个实现的就是我们的MainActivity了,我们在这个界面上设计的内容,会最终显示在我们的App中。
通过上面的介绍,我们就可以实现用QtCreator和C++写Android程序了。细心的同学会发现,在这个程序中我们没有写一行Java的代码,我们为这个工程只做了3个方面的工作:
1. 配置Gradle使C++和Java能混合编译并部署
2. 写C++调用Java的代码(或者如果不需要Java功能就可以只写C++的功能代码)
3. 用Qt提供的ui文件设计App的界面
完成这个工程后总结了一下,其实用C++和Qt配合写Android程序并不是很复杂,大部分时间都花在了环境的搭建和调用Java的过程上,其实如果只用C++和ui文件,写一个小的app也是跟桌面开发比较类型的。
第一次纯手工写这种文章,没有一个字复制过来的。观点和内容肯定会有不对和难于理解的地方,希望读者能给出批评指正,一起学习进步。

Created by 陈祥俭
这里写图片描述

原创粉丝点击