本文翻译:QT, THE BETTER ANDROID NDK点击打开链接
要点:怎么在Android Studio中调用qt编写的so库, 同时怎么去加载相关的qt动态库。
一.QT for Android编译so库
创建Qt Widgets Application ->构建套件选Android, 删除原来的Widget和main;(原文要求创建库工程,但是我最后测试和作者后面的的操作有冲突,需要创建app应用)
pro文件:
QT += core gui
QT += widgets
TARGET = untitled3
TEMPLATE = app
DEFINES += UNTITLED3_LIBRARY
SOURCES += untitled3.cpp
HEADERS += untitled3.h\
untitled3_global.h
unix {
target.path = /usr/lib
INSTALLS += target
}
untitled3_global.h:
#ifndef UNTITLED3_GLOBAL_H
#define UNTITLED3_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(UNTITLED3_LIBRARY)
# define UNTITLED3SHARED_EXPORT Q_DECL_EXPORT
#else
# define UNTITLED3SHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // UNTITLED3_GLOBAL_H
untiled3.h:
#ifndef UNTITLED3_H
#define UNTITLED3_H
#include "untitled3_global.h"
#include <jni.h>
class UNTITLED3SHARED_EXPORT Untitled3
{
public:
Untitled3();
};
#ifdef __cplusplus
extern "C"
{
#endif
JNIEXPORT void JNICALL Java_eu_microscopictopic_scratchclib_JavaNatives_sendIntToClib(JNIEnv * env, jobject thisObj, jint n);
#ifdef __cplusplus
}
#endif
#endif // UNTITLED3_H
untiled3.cpp:
#include "untitled3.h"
#include "jni.h"
#include "android/log.h"
Untitled3::Untitled3()
{
}
JNIEXPORT void JNICALL
Java_eu_microscopictopic_scratchclib_JavaNatives_sendIntToClib(JNIEnv * env, jobject thisObj, jint n)
{
__android_log_print(ANDROID_LOG_INFO, "Scratch_c_lib", "Are you kidding me? receiveToClib:%d", n);
}
二.构建Android Studio工程
按照Android Studio正常模式创建(为了和qt工程中jni接口保持一致,包名为:eu.microscopictopic.scratchclib),在app/src/目录下创建qtgen目录,第一步的qt工程构建目录设置为此目录。
App/build.gradle
Android中加入:
sourceSets { main { java.srcDirs = ['/src/main/java'] res.srcDirs = ['src/main/res','src/qtgen/android-build/res'] jniLibs.srcDirs = ['src/qtgen/android-build/libs'] } }
设置qt库目录和布局目录dependencies中加入:加入qt-builded jar编译compile files('src/qtgen/android-build/libs/QtAndroid-bundled.jar')
qt工程编译后,在qtgen/android-build/res/valuse/libs.xml文件中可知:<?xml version='1.0' encoding='utf-8'?> <resources> <array name="qt_sources"> <item>https://download.qt.io/ministro/android/qt5/qt-5.7</item> </array> <!-- The following is handled automatically by the deployment tool. It should not be edited manually. --> <array name="bundled_libs"> </array> <array name="qt_libs"> <item>gnustl_shared</item> <item>Qt5Core</item> <item>Qt5Gui</item> <item>Qt5Widgets</item> </array> <array name="bundled_in_lib"> <item>libplugins_platforms_android_libqtforandroid.so:plugins/platforms/android/libqtforandroid.so</item> <item>libplugins_platforms_libqminimal.so:plugins/platforms/libqminimal.so</item> <item>libplugins_platforms_libqoffscreen.so:plugins/platforms/libqoffscreen.so</item> <item>libplugins_generic_libqevdevkeyboardplugin.so:plugins/generic/libqevdevkeyboardplugin.so</item> <item>libplugins_generic_libqevdevmouseplugin.so:plugins/generic/libqevdevmouseplugin.so</item> <item>libplugins_generic_libqevdevtabletplugin.so:plugins/generic/libqevdevtabletplugin.so</item> <item>libplugins_generic_libqevdevtouchplugin.so:plugins/generic/libqevdevtouchplugin.so</item> <item>libplugins_imageformats_libqdds.so:plugins/imageformats/libqdds.so</item> <item>libplugins_imageformats_libqgif.so:plugins/imageformats/libqgif.so</item> <item>libplugins_imageformats_libqicns.so:plugins/imageformats/libqicns.so</item> <item>libplugins_imageformats_libqico.so:plugins/imageformats/libqico.so</item> <item>libplugins_imageformats_libqjpeg.so:plugins/imageformats/libqjpeg.so</item> <item>libplugins_imageformats_libqtga.so:plugins/imageformats/libqtga.so</item> <item>libplugins_imageformats_libqtiff.so:plugins/imageformats/libqtiff.so</item> <item>libplugins_imageformats_libqwbmp.so:plugins/imageformats/libqwbmp.so</item> <item>libplugins_imageformats_libqwebp.so:plugins/imageformats/libqwebp.so</item> </array> <array name="bundled_in_assets"> </array> </resources>
此处,qt生成的xml文件已经定义好了 要加载的库文件:平台库:libqtforandroid.so图片,Gui,Core,Widget等,在qtgen/android-build/libs目录下可以找到要加载的库我们知道了,现在在java中怎么去加载这些库文件:package eu.microscopictopic.scratchclib; import android.content.Context; import android.util.Log; public class JavaNatives { public static native void sendIntToClib(int n); public static void init(Context context) { load(context, R.array.bundled_in_assets); load(context, R.array.qt_libs); System.loadLibrary("untitled3"); //这一步虽然保报错了,但是senderIntToClib方法还是调用成功。 // W/linker: libuntitled3.so: unused DT entry: type 0x6ffffffe arg 0x3cc // W/linker: libuntitled3.so: unused DT entry: type 0x6fffffff arg 0x1 } static void load(Context context, int arrayResourceId) { String[] libsToLoad = context.getResources().getStringArray(arrayResourceId); for (String lib : libsToLoad) { if (lib.indexOf('/')>-1) { lib=lib.substring(lib.indexOf('/')); } if (lib.indexOf("lib")==0) { lib=lib.substring(3); } if (lib.endsWith(".so")) { lib=lib.substring(0, lib.length()-3); } Log.i(JavaNatives.class.getSimpleName(), "loading "+lib); try { System.loadLibrary(lib); } catch (Throwable e) { Log.i(JavaNatives.class.getSimpleName(), "failed to load "+lib+" "+e); e.printStackTrace(); } Log.i(JavaNatives.class.getSimpleName(), "Successfully loaded "+lib); } } }
在Activity中怎么使用?这里依赖QtAndroid-bundled.jar,我们右键-Add as library-app...:java目录:使用:package com.kdab.training; import android.os.Bundle; import org.qtproject.qt5.android.bindings.QtActivity; import eu.microscopictopic.scratchclib.JavaNatives; public class MyActivity extends QtActivity { public static MyActivity s_activity = null; @Override public void onCreate(Bundle savedInstanceState) { //JavaNatives.init(getApplicationContext()); JavaNatives.sendIntToClib(222); s_activity = this; super.onCreate(savedInstanceState); } @Override protected void onDestroy() { super.onDestroy(); s_activity = null; } }
这样就可以编写qt android动态库给Android Studio调用了,但是经过我测试,窗体类是无法使用的,具体用途没有实验。