目录

  • 前言
  • 配置开发环境
  • 安装JDK1.8
  • 安装SDK
  • 安装NDK
  • Qt配置OpenCV
  • C++&Java混合编程
  • 结语


前言

由于要在手机上实现一些应用,例如部署目标检测模型、添加单目测距定位的功能等,需要编写一个示例APP。尽管安卓我并不陌生,在本科的时候自己写过一点APP,所以基本的东西还是懂的。但问题在于,我已经几年没碰过了。。现在Java编程几乎忘得差不多,主要的语言变成了Python和C/C++,要想立马自己编写一个Java的应用程序确实有点困难。在思考过后,我决定用Qt的安卓开发环境来写,这样就可以不用复习Java和安卓编程,并且使用熟悉的C++和Qt来完成开发。于是简单了解了下Qt的安卓开发环境搭建,也自己动手试了试。尽管想法不错,但测试后发现纯C++写的程序没法成功打开摄像头,可能是我用的小米手机不支持这部分API的原因,要想正常打开摄像头,还是得用Java编程,于是果断转向了Android Studio。虽然Qt也支持Java和C++混合编程,但如果已经逃不开Java的话,那当然还是选择Android Studio更为合适,毕竟Android Studio也支持NDK开发,同样可以混合编程,并且配置环境也更为简单。这篇文章主要记录下Qt配置Android开发环境的过程,包括OpenCV的配置,后面也会再写一篇Android配置OpenCV开发环境的文章。

配置开发环境

在Qt上开始编写安卓应用程序前,需要下载安装所需的环境依赖,包括:

如果没有安装Qt,那么还得先下载Qt5安装包,Qt5的版本没有特别要求,一般选最新的即可,但不同版本的环境依赖安装会有一些差别,具体可以参考Qt for Android,本文则以Windows环境下最新的5.14.2为例。在安装Qt时必须选中Android的选项,不然安装后无法配置Android相关的环境。Qt安装好后,点击工具->选项,在打开的窗口中选择设备->Android,即可看到如下所示的信息:

android qt 支持 qt能写android_android qt 支持


从上面可以看到要安装的环境依赖具体包括哪些,当没有安装好部分依赖时,详情里会进行相应的提示。对于环境依赖的安装,简单的方式是下载Android Studio用来安装SDK和NDK,当然,也可以根据上面的链接逐个下载安装。不过上面给出的SDK链接的版本较低,单独下载安装后Qt会提示版本问题,因而无法在Qt中配置Platform SDK的版本,这时可打开SDK Manager更新到最新版本。使用SDK Manager时可能找不到SDK Tools的选项,需要点击取消下方的Hide Obsolete Packages选项。

安装JDK1.8

先下载安装JDK1.8,接着配置Java环境变量:

  • 新建环境变量JAVA_HOME,变量值为JDK的安装目录,如C:\Program Files\Java\jdk1.8.0_231
  • 新建环境变量CLASSPATH,变量值为.;%JAVA_HOME%\bin;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar
  • 在Path中添加%JAVA_HOME%\bin%JAVA_HOME%\jre\bin两项

安装SDK

先下载SDK安装包点击运行,指定SDK的安装目录进行安装。安装好后打开SDK Manager安装Build-Tools、Platform-Tools和目标安卓版本的Platform SDK,接着添加安装目录下的platform-tools和build-tools\28.0.3目录路径到环境变量Path中,如D:\Android-sdk\sdk-windows\platform-toolsD:\Android-sdk\sdk-windows\build-tools\28.0.3,这里的28.0.3是build-tools的版本,根据实际版本修改。

安装NDK

先下载NDK安装包,接着解压到指定的安装目录,最后新建环境变量ANDROID_NDK_HOME,变量值为NDK的安装目录。如果需要下载最新的NDK版本,可在SDK Manager中进行更新。

在完成上面的步骤后,Qt的Android开发环境已经配置完备,接着可创建Qt工程进行测试,创建工程时选择Android工具包。测试时需要用USB连接安卓手机,如果是小米手机需要在开发者模式下打开调试选项。

Qt配置OpenCV

由于我是想用OpenCV的DNN模块加载目标检测模型,因此还需要在Qt上配置OpenCV库。首先到官网下载指定OpenCV版本的Android开发包,通常下载最新版本即可,下载好后解压到指定安装目录,注意目录不要有中文字符。在QT工程的.pro文件中添加如下内容:

unix {
OPENCV_ANDROID_SDK = D:/OpenCV/opencv-4.4.0-android/OpenCV-android-sdk/sdk/native
INCLUDEPATH += $$OPENCV_ANDROID_SDK/jni/include/
LIBS += $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_calib3d.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_core.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_dnn.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_features2d.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_flann.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_highgui.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_imgcodecs.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_imgproc.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_ml.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_objdetect.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_photo.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_stitching.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_video.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_videoio.a \
        $$OPENCV_ANDROID_SDK/staticlibs/armeabi-v7a/libopencv_gapi.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/libcpufeatures.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/libIlmImf.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/liblibjasper.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/liblibjpeg-turbo.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/liblibpng.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/liblibprotobuf.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/liblibtiff.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/liblibwebp.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/libquirc.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/libtbb.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/libtegra_hal.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/libittnotify.a \
        $$OPENCV_ANDROID_SDK/3rdparty/libs/armeabi-v7a/libade.a \
        $$OPENCV_ANDROID_SDK/libs/armeabi-v7a/libopencv_java4.so
}
ANDROID_EXTRA_LIBS = D:/OpenCV/opencv-4.4.0-android/OpenCV-android-sdk/sdk/native/libs/armeabi-v7a/libopencv_java4.so

上面的ANDROID_EXTRA_LIBS是Qt指定外部依赖库的配置项,会将指定的libopencv_java4.so文件打包到生成的APK中。

C++&Java混合编程

在Qt开发中C++可通过JNI,即Java Native Interface和Java进行交互,具体的配置包括,在Qt工程的.pro文件中添加如下:

QT += androidextras
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android-sources
OTHER_FILES += \
    android-sources/com/example/opencvdemo/OpenCVDemo.java \
    android-sources/AndroidManifest.xml

在Qt工程目录下创建android-sources文件夹,文件夹的名字可以相应更改,在android-sources文件夹下创建AndroidManifest.xmlcom/example/opencvdemo/OpenCVDemo.java文件。熟悉Android编程的知道,这里的AndroidManifest.xml为应用程序的配置文件,而OpenCVDemo.java则是对应的Java代码,文件的名字和路径均可相应更改。具体的应用可参考Qt的官方例程Qt Notifier

结语

尽管在Qt上没能实现功能,但使用Qt编写Android应用程序却是一个不错的选择,可以使用QML进行界面的设计,同时QML也可与C++进行交互。如果不是遇到Qt自带的API没法正常打开摄像头的情况,我应该会首选用C++编写APP。当然,在遇到这样的问题时,可以选择使用Java API打开摄像头,然后调用C++ API完成对帧的后续处理,这样即能方便C++用户,也能一定程度提升应用的实时性。总地说来,Qt正在不断壮大,相关的生态链也是越来越完善,同时随着NDK的不断发展,相信在数年后使用C++完成整个Android应用程序的编写将成为现实。