Qt on Android:使用JNI与集成jar包

很多朋友在论坛和QQ群里问到这个,今天有时间写了个简单的示例。

功能很简单,允许你输入一个web页面地址,使用Java的下载类库下载后用QTextEdit显示出来。

版权所有:foruok。转载请注明出处:http://blog.csdn.net/foruok

效果展示

初始效果如图1所示:

图1 useJar示例初始效果

图2为点击"GET"按钮后下载到对应页面的效果:

图2 下载页面成功

下载部分,为了显示如何使用jar包,我用了asynchttpclient,参考我的博文:Android开源框架AsyncHttpClient (android-async-http)使用

项目创建

参考《Qt on Android:图文详解Hello World全过程》吧,没什么特别可说的。

pro文件内添加“QT += androidextras”。

创建一个AndroidManifest,package命名为an.qt.useJar。

版权所有:foruok。转载请注明出处:http://blog.csdn.net/foruok

添加Java源码

你可以任意的文本编辑器中编辑java源码,然后通过Qt Creator项目视图加到项目里,在其它文件那里鼠标右键点击,选择添加现有文件即可。参考下面几张图吧。

图3 添加Java源码之右键菜单

图4 添加Java源文件之选择Java源文件

图5 添加Java源文件OK

修改AndroidManifest,把activity标签的android:name属性值修改为an.qt.useJar.ExtendsQtWithJava。这是必须的,因为我们的ExtendsQtWithJava.java实现的Activity就是这个名字。

好了,Java代码添加结束。

添加第三方jar包

这个没什么好说的,放在android/libs目录下即可。看图:

图6 放jar包

只要放好位置,Qt Creator编译项目时就会把这个jar包打包到APK里。

Java源码使用jar包

这是java编程的内容了,import包名,然后使用即可。

源码分析

咱先看Java侧的代码吧。

Java代码

ExtendsQtWithJava.java:

package an.qt.useJar;
import java.lang.String;
import android.content.Context;
import android.content.Intent;
import android.app.PendingIntent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.location.Criteria;
import android.provider.Settings;
import android.os.Bundle;
import android.os.Environment;
import java.io.File;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;

public class ExtendsQtWithJava extends org.qtproject.qt5.android.bindings.QtActivity
{
    private static ExtendsQtWithJava m_instance;
    private final static String TAG = "extendsQt";
    private static String m_pageUri = null;
    private static Handler m_handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 1:
                if(m_pageUri == null){
                    m_pageUri = (String)msg.obj;
                    m_instance.downloadText(m_pageUri);
                }else{
                    m_instance.notifyQt(0, (String)msg.obj, "Downloader is Busy now!");
                }
                break;
            };
        }
    };

    public ExtendsQtWithJava(){
        m_instance = this;
    }

    public static int networkState(){
        ConnectivityManager conMan = (ConnectivityManager) m_instance.getSystemService(Context.CONNECTIVITY_SERVICE);
        return conMan.getActiveNetworkInfo() == null ? 0 : 1;
    }

    public static AsyncHttpClient m_httpc = new AsyncHttpClient();
    public static ExtendsQtNative m_nativeNotify = null;

    public void downloadText(String uri){
        Log.d(TAG, "start downloadText");
        m_httpc.get(uri, null, new AsyncHttpResponseHandler(){
            @Override
            public void onSuccess(String data){
                notifyQt(1, m_pageUri, data);
                m_pageUri = null;
            }
            @Override
            public void onFailure(Throwable e, String data){
                notifyQt(-1, m_pageUri, data);
                m_pageUri = null;
            }
        });
    }

    public static void downloadWebPage(String uri){
        Log.d(TAG, "downloadWebPage");
        m_handler.sendMessage(m_handler.obtainMessage(1, uri));
    }

    private void notifyQt(int result, String uri, String data){
        if(m_nativeNotify == null){
            m_nativeNotify = new ExtendsQtNative();
        }
        m_nativeNotify.OnDownloaded(result, uri, data);
    }
}

ExtendsQtNative.java:

package an.qt.useJar;
import java.lang.String;

public class ExtendsQtNative
{
    public native void OnDownloaded(int result, String url, String content);
}

基本思路是酱紫的:

Qt调用java的downloadWebPage,Java代码使用asynchttpclient下载一个网页,然后调用ExtendsQtNative通知Qt C++代码。

C++代码

分两部分,一部分是实现JNI方法。另一部分是调用Java类的方法。

实现JNI方法并注册

先看与ExtendsQtNative对应的JNI实现,在main.cpp中,都列出吧:

#include "widget.h"
#include <QApplication>
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>
#include <jni.h>
#include "../simpleCustomEvent.h"
#include <QDebug>

QObject *g_listener = 0;

// result: -1 failed; 1 success; 0 busy;
static void onDownloaded(JNIEnv *env, jobject thiz,int result, jstring uri, jstring data)
{
    QString qstrData;
    const char *nativeString = env->GetStringUTFChars(data, 0);
    qstrData = nativeString;
    env->ReleaseStringUTFChars(data, nativeString);
    QCoreApplication::postEvent(g_listener, new SimpleCustomEvent(result, qstrData));
}

bool registerNativeMethods()
{
    JNINativeMethod methods[] {
        {"OnDownloaded", "(ILjava/lang/String;Ljava/lang/String;)V", (void*)onDownloaded}
    };

    const char *classname = "an/qt/useJar/ExtendsQtNative";
    jclass clazz;
    QAndroidJniEnvironment env;

    QAndroidJniObject javaClass(classname);
    clazz = env->GetObjectClass(javaClass.object<jobject>());
    qDebug() << "find ExtendsQtNative - " << clazz;
    bool result = false;
    if(clazz)
    {
        jint ret = env->RegisterNatives(clazz,
                                        methods,
                                        sizeof(methods) / sizeof(methods[0]));
        env->DeleteLocalRef(clazz);
        qDebug() << "RegisterNatives return - " << ret;
        result = ret >= 0;
    }
    if(env->ExceptionCheck()) env->ExceptionClear();
    return result;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    SimpleCustomEvent::eventType();
    registerNativeMethods();

    Widget w;
    g_listener = qobject_cast<QObject*>(&w);
    w.show();

    return a.exec();
}

注册JNI方法,设置一个全局的对象接收通知。具体的,参考Qt帮助来理解。

调用Java方法

对Java方法的调用在Widget.cpp中。直接看代码吧。

widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLineEdit>
#include <QTextEdit>
#include <QLabel>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

    bool event(QEvent *e);

public slots:
    void onGet();

private:
    QLineEdit * m_urlEdit;
    QTextEdit * m_resultView;
    QLabel * m_stateLabel;
};

#endif // WIDGET_H

都是界面相关的,没什么好说的。看widget.cpp:

#include "widget.h"
#include <QVBoxLayout>
#include <QPushButton>
#include "../simpleCustomEvent.h"
#include <QAndroidJniObject>
#include <QAndroidJniEnvironment>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QVBoxLayout *layout = new QVBoxLayout(this);
    QHBoxLayout *getLayout = new QHBoxLayout();
    layout->addLayout(getLayout);
    m_urlEdit = new QLineEdit("http://blog.csdn.net/foruok");
    getLayout->addWidget(m_urlEdit, 1);
    QPushButton *getButton = new QPushButton("GET");
    getLayout->addWidget(getButton);
    connect(getButton, SIGNAL(clicked()), this, SLOT(onGet()));

    m_resultView = new QTextEdit();
    m_resultView->setReadOnly(true);
    layout->addWidget(m_resultView, 1);
    m_stateLabel = new QLabel();
    layout->addWidget(m_stateLabel);
}

Widget::~Widget()
{

}

bool Widget::event(QEvent *e)
{
    if(e->type() == SimpleCustomEvent::eventType())
    {
        e->accept();
        SimpleCustomEvent *sce = (SimpleCustomEvent*)e;
        switch(sce->m_arg1)
        {
        case 1:
            m_resultView->setText(sce->m_arg2);
            m_stateLabel->setText("Success!");
            break;
        case 0:
            m_resultView->setText(sce->m_arg2);
            m_stateLabel->setText("Failed!");
            break;
        case -1:
            m_stateLabel->setText(sce->m_arg2);
            break;
        }
        return true;
    }
    return QWidget::event(e);
}

void Widget::onGet()
{
#ifdef WIN32
    m_resultView->setText("Sorry, Just for Android!");
#elif defined(ANDROID)
    QString url = m_urlEdit->text();
    QAndroidJniObject javaAction = QAndroidJniObject::fromString(url);
    QAndroidJniObject::callStaticMethod<void>("an/qt/useJar/ExtendsQtWithJava",
                                       "downloadWebPage",
                                       "(Ljava/lang/String;)V",
                                       javaAction.object<jstring>());
    m_stateLabel->setText("Downloading...");
#endif
}

调用Java的代码在onGet()槽中,很简单,不解释了。有疑问看Qt帮助手册有关QAndroidJniObject类的说明。

OK,到此结束。

版权所有:foruok。转载请注明出处:http://blog.csdn.net/foruok

我的Qt on Android系列文章:

时间: 2024-08-25 10:42:12

Qt on Android:使用JNI与集成jar包的相关文章

Qt on Android:使用JNI与第三方jar包

很多朋友在论坛和QQ群里问到这个,今天有时间写了个简单的示例. 功能很简单,允许你输入一个web页面地址,使用Java的下载类库下载后用QTextEdit显示出来. 版权所有:foruok.转载请注明出处:http://blog.csdn.net/foruok. 效果展示 初始效果如图1所示: 图1 useJar示例初始效果 图2为点击"GET"按钮后下载到对应页面的效果: 图2 下载页面成功 下载部分,为了显示如何使用jar包,我用了asynchttpclient,参考我的博文:An

11.Cocos2dx2.2下使用JNI技术调用jar包里面的一些方法遇到的一些问题及解决方案。

<span style="font-family: Arial, Helvetica, sans-serif;">步骤一:导入JniHelper.h头文件.</span> #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "JniHelper.h" #endif: 此时会遇到JniHelper.h头文件无法找到的问题,需要添加附加包含目录即可解决问题.具体操作步骤如下:右击项目-

android studio 使用gradle 导出jar包,并打包assets目录

最近项目在做一个sdk,供别的开发者使用,所以要求导出jar包. 与eclipse不同,android studio 1.0 没提供导出jar包的图形界面.需要结合gradle来生成jar包. 首先 需要设置module应用的gradle插件为 library 代码长这样: ? 1 <code class="hljs">apply plugin: 'com.android.library'</code> 这样,build的时候,android studio 1.

解决Android工程中引入codec.jar包报错问题

在Android项目中使用到了org.apache.commons.codec.jar包下的Hex.encodeHexString(byte[] input)方法进行加密.结果编译通过,运行时总是报java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString([B)Ljava/lang/String;错误. 原因:Google Android内部也有一个包名一样的工程,而且类名也相同,关键一点是没

关于如何正确地在android项目中添加第三方jar包

1.下载第三方jar包 2.在android项目下创建一个libs目录(名称并不固定,你完全可以取其他名称) 3.在eclipse中右键点击libs目录,依次选择Import -> General -> File System,选中jar包所在目录, 然后选中这个目录下的jar包 注:到这一步为止你就成功地把jar包添加到项目中(但是还没有被android的虚拟机识别,因此如果这时你使用jar包中的类,编译都无法通过) 4.右键点击项目名,依次选择Build Path -> Config

Android项目将生成的jar包混淆

又是一个不眠夜 问题来了,我们写个android项目部分代码想生成jar包,并且将jar包做混淆,不被别人切! 首先讲要代码生成jar包,这个就不多说了.然后找到找到SDK里的proguardgui.jar(目录:sdk\tools\proguard\lib\)并打开. 然后会看到proguard的页面 第一次点击Next,然后看下面页面,点击Addinput...添加你要混淆的jar包,点击Add output...是选择混淆后的jar包保存目录.底下的Add...是你jar包所依赖的jar.

android studio 引入第三方类库jar包

第三方类库jar包 这就简单多了,直接将jar包拷贝到app/libs下,然后在app下的build.gradle中添加此jar的依赖.如下: dependencies { compile 'com.android.support:support-v4:19.1.0' compile files('libs/libammsdk.jar') compile files('libs/universal-image-loader-1.8.6-with-sources.jar') compile fil

android studio中导入第三方jar包和第三方库文件的方法

一.导入第三方jar包的方法 其实较为简单,以下步骤: 1>在工程的libs下面放置需要导入的jar包 2>在导入的jar包右键,选择"add as library" 3>这时候就能够在app下面的build.gradle中发现多了如下说明:"compile XXXX",说明导入jar文件成功了. 二.导入第三方类库文件 相对而言,其实就是将之前的Eclipse的project或者module转化成android studio下的可执行的proje

解决Android Studio加载第三方jar包,出现包重复加载的问题:

通过Maven中央库添加第三方jar包的时候,出现了重复加载jar包的问题,解决办法很简单去掉一个不让它去加载就OK了 一.错误 Error:Execution failed for task ':app:dexDebug'. > com.android.ide.common.internal.LoggedErrorException: Failed to run command: F:\zsl\sdk\build-tools\21.1.2\dx.bat --dex --output F:\zs