在Android中使用Qt作为共享系统库

2023-11-07

Using Qt as shared system libraries in Android

在Android中使用Qt作为共享系统库

October 21, 2022 by Tinja Paavoseppä | Comments

2022年10月21日Tinja Paavoseppä|评论

In Android 7.0  namespaces for native libraries were introduced. What this means is that apps can only access the public libraries provided with the Android NDK and the ones in their own native library directory. This is why, by default, every Qt Android app deploys with its own set of Qt libraries which get extracted to the app's native library directory. Due to the aforementioned restrictions, these libraries can't be used by other apps. For most user apps, this is OK - the app can be installed on a number of devices, with no guarantees that the Qt libraries could be found there, or that they would be the correct version!

​在Android 7.0中,引入了本地库的命名空间。这意味着应用程序只能访问Android NDK提供的公共库以及它们自己的本地库目录中的公共库。这就是为什么默认情况下,每个Qt Android应用程序都会部署自己的一组Qt库,这些库会被提取到应用程序的本地库目录中。由于上述限制,这些库不能被其他应用程序使用。对于大多数用户应用程序来说,这没关系-该应用程序可以安装在许多设备上,但不保证Qt库可以在那里找到,或者它们是正确的版本!

However, if you are an OEM planning to use Qt to implement your IVI system on top of Android Automotive, this is not ideal. The thought of having to deploy the same libraries with each app may not sound appealing. The more Qt apps you have, the bigger the problem becomes, those multiple sets of libraries take up space.

然而,如果您是一个OEM,计划使用Qt在Android Automotive上实现您的IVI系统,这并不理想。必须为每个应用程序部署相同的库的想法听起来可能并不吸引人。你拥有的Qt应用程序越多,问题就越大,这些多组库占用了空间。

The good news is that system apps have looser restrictions placed on them - they can use all the native libraries under the system library directory. So in this blog post, we will have a look at how to build an Android image with Qt libraries installed as shared system libraries. We will also learn how to use the new Unbundled deployment, introduced in Qt 6.4.0, to help make it easier to build and deploy apps that will link to Qt libraries present on the target device instead of bundling all the libraries with the APK.

好消息是,系统应用程序对它们有更宽松的限制——它们可以使用系统库目录下的所有本地库。因此,在这篇博客文章中,我们将了解如何使用作为共享系统库安装的Qt库构建Android映像。我们还将学习如何使用Qt 6.4.0中引入的新的Unbundled部署,以帮助更轻松地构建和部署将链接到目标设备上的Qt库的应用程序,而不是将所有库与APK绑定。

Note that due to the restrictions placed by Android, these libraries will only be available to system apps installed on the system partition.

请注意,由于Android的限制,这些库将仅对安装在系统分区上的系统应用程序可用。

Adding the libraries

添加库

Since the apps do not come with their own set of libraries, we need to make sure the Qt libraries can be found on the device. To add them, we need to modify the AOSP build tree. If you would like a refresher on how to build an Android Automotive emulator image, take a look here! For this post, we build an Android Automotive 12 x86_64 image that can be run on an Android emulator as a virtual device, with the Qt libraries and an example app included.

​由于这些应用程序没有自己的库,我们需要确保Qt库可以在设备上找到。要添加它们,我们需要修改AOSP构建树。如果您想了解如何构建Android汽车仿真器映像,请查看此处!在本文中,我们构建了一个Android Automotive 12 x86_64映像,该映像可以作为虚拟设备在Android模拟器上运行,其中包括Qt库和示例应用程序。

After we have set up the AOSP build environment as described in the link above, we create a directory named "qt" under <aosp-root>/external. Here we will add the Qt libraries our app(s) use - you can copy them from under your Qt for Android installation. We need to also create an Android.mk or Android.bp file to let the AOSP build know what we want to include. Here, we use the former. Let's add the Android.mk file under the same folder. Now, our directory structure would look like this:

按照上面的链接所述设置AOSP构建环境后,我们在<AOSP-root>/external下创建一个名为“qt”的目录。在这里,我们将添加我们的应用程序使用的Qt库-您可以从Android安装的Qt下复制它们。我们还需要创建一个Android.mk或Android.bp文件,让AOSP构建知道我们想要包含什么。在这里,我们使用前者。让我们添加Android.mk文件位于同一文件夹下。现在,我们的目录结构如下所示:


You could also add a subdirectory for e.g. the target architecture (x86_64 in this case) and place the libraries there. Just make sure LOCAL_SRC_FILES points to the source file in relation to Android.mk file's location. Also note that the actual list of libraries you need to add will depend on your app, here we have added the libraries our example app for this post uses.

您还可以为目标体系结构(在本例中为x86_64)添加一个子目录,并将库放在那里。只需确保LOCAL_SRC_FILES指向与Android.mk文件位置相关的源文件。还请注意,您需要添加的库的实际列表将取决于您的应用程序,这里我们添加了本文示例应用程序使用的库。

In the Android.mk file, we first set the LOCAL_PATH to the current working directory. This needs to be done only once at the beginning of the file. Then, an entry is added for each library we want to install.

在Android.mk文件中,我们首先将LOCAL_PATH设置为当前工作目录。这只需要在文件开头执行一次。然后,为要安装的每个库添加一个条目。


LOCAL_PATH := $(call my-dir)

# One entry for each library
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
# The name should match the library name without the .so suffix
LOCAL_MODULE := libQt6Quick_x86_64
LOCAL_MODULE_SUFFIX := .so
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
# Path to the library, relative to LOCAL_PATH
LOCAL_SRC_FILES := $(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX)
# Relative path to install location -# this will result in the libraries being installed under system/lib(64)/qt/
LOCAL_MODULE_RELATIVE_PATH := qt
LOCAL_CHECK_ELF_FILES := false
include $(BUILD_PREBUILT)

# And the rest of the entries
 ...

In the example above, we say we want to add a module called libQt6Quick_x86_64, which is a prebuilt C++ shared library, and the prebuilt .so which has the same name as the module can be found in the same directory as the Android.mk file.

在上面的例子中,我们说我们想添加一个名为libQt6Quick_x86_64的模块,这是一个预构建的C++共享库,而与该模块同名的预构建.so可以在与Android.mk文件相同的目录中找到。

We use:

我们使用:

LOCAL_MODULE_RELATIVE_PATH:= qt

to tell we want the libraries installed under a subdirectory called "qt" under the system library directory. By default, the AOSP build will check ELF files to make sure all the library's dependencies have been listed appropriately in its LOCAL_SHARED_LIBRARIES entry. This can be disabled by adding a line inside the module declaration to tell it to skip the check:

告诉我们,我们希望这些库安装在systemlibrary目录下名为“qt”的子目录下。默认情况下,AOSP构建将检查ELF文件,以确保在其LOCAL_SHARED_LIBRARIES条目中正确列出了库的所有依赖项。这可以通过在模块声明中添加一行来禁用,以告诉它跳过检查:

LOCAL_CHECK_ELF_FILES := false

Notice that in this case, the AOSP build will not install the library's dependencies with it, as it does not know them. In this case, you will need to tell it explicitly to add each of them. This can be achieved by listing them all as installable modules under the product's make file. For example, we can modify the file <aosp-root>/packages/services/Car/car_product/build/car.mk and list all the libraries we want to install under PRODUCT_PACKAGES:

注意,在这种情况下,AOSP构建不会安装库的依赖项,因为它不知道它们。在这种情况下,您需要明确地告诉它添加其中的每一个。这可以通过将它们作为可安装模块列在产品的make文件下来实现。例如,我们可以修改文件<aosp root>/packages/services/Car/Car_product/build/Car.mk并在PRODUCT_PACKAGES下列出所有要安装的库:


# Append to existing packages, using the name you gave the library module
PRODUCT_PACKAGES += \
    ... \    
    libQt6Core_x86_64 \
    libQt6Quick_x86_64 \
    # The rest of the libraries...
    ...

After all the libraries have been added, we can move on to including the app!

添加完所有库后,我们可以继续添加应用程序!

Building the app

构建应用程序

Next, let's create a simple Qt app - the one created by Qt Creator when you choose "New project - Qt Quick Application" will work just fine for this purpose. Let's call it simply QtApp.
Now if we build it using a Qt for Android kit and the default deployment and take a look at the APK contents, we can see it has included all of its Qt dependencies inside it, under the "lib" directory.

接下来,让我们创建一个简单的Qt应用程序-当您选择“新项目-Qt Quick应用程序”时,由Qt Creator创建的应用程序将非常适合此目的。让我们简单地称之为QtApp。
现在,如果我们使用Qt for Android工具包和默认部署构建它,并查看APK内容,我们可以看到它在“lib”目录下包含了所有Qt依赖项。

Since we will be providing the libraries as system libraries, we do not need this. So, to take advantage of Unbundled deployment, we set a couple of Qt CMake properties in the app's CMakeLists.txt:

由于我们将以系统库的形式提供这些库,所以我们不需要这样做。因此,为了利用Unbundled部署,我们在应用程序的CMakeLists.txt中设置了几个Qt CMake属性:


set_target_properties(${target_name} PROPERTIES
    QT_ANDROID_NO_DEPLOY_QT_LIBS True
    QT_ANDROID_SYSTEM_LIBS_PREFIX /system/lib64/qt/
)

Setting QT_ANDROID_NO_DEPLOY_QT_LIBS to true tells the deployment tool not to package the C++ libraries into the APK; and we use  QT_ANDROID_SYSTEM_LIBS_PREFIX to tell the app where to search for them on the device, instead. Here, we set the path to point to /system/lib64/qt/, as the image we are building is a 64-bit one. If you are targeting a 64-bit architecture like arm64 or x86_64 this is the default directory for the libraries. If building a 32-bit image, x86 or armv7, swap it for /system/lib/qt/ instead.


将QT_ANDROID_NO_DEPLOY_QT_LIBS设置为true告知部署工具不要将C++库打包到APK中;我们使用QT_ANDROID_SYSTEM_LIBS_PREFIX来告诉应用程序在设备上的何处搜索它们。这里,我们将路径设置为指向/system/lib64/qt/,因为我们正在构建的映像是64位映像。如果您的目标是像arm64或x86_64这样的64位体系结构,这是库的默认目录。如果构建32位映像x86或armv7,请将其替换为/system/lib/qt/。

If we do a fresh build after setting the properties, you may notice straight away the APK size is much smaller than a usual Qt Android app - for this simple app the size drops from over 12 MB to just over 100 kB! If you take a peek inside the APK, you will notice the lib folder is missing. 

如果我们在设置属性后重新构建,您可能会立即注意到APK的大小比通常的Qt Android应用程序小得多-对于这个简单的应用程序,大小从超过12 MB降至刚刚超过100 kB!如果你在APK里面看一眼,你会发现lib文件夹不见了。

Next, it's time to include the app in the image. As mentioned in the beginning, only apps installed under the system partition can use the libraries we are installing, so we need to add the app we just built as a system app. So again, we create a folder under the AOSP tree - let's call it QtApp and place it under <aosp-root>/packages/apps/Car/.

接下来,是时候将应用程序包含在图像中了。如前所述,只有安装在系统分区下的应用程序才能使用我们正在安装的库,因此我们需要将我们刚刚构建的应用程序添加为系统应用程序。因此,我们再次在AOSP树下创建一个文件夹-让我们将其命名为QtApp,并将其放置在<AOSP root>/packages/apps/Car/下。

Under the folder we created, we then copy the APK we just built and its own library. The library can be found under the app's build directory and will by default be called libapp<app-name>_<target-arch>.so. So if our app would be called QtApp, we would copy the library libappQtApp_x86_64.so. Again, we also create an Android.mk file. This time the contents look a bit different:

在我们创建的文件夹下,我们复制刚刚构建的APK及其自己的库。该库可以在应用程序的构建目录下找到,默认情况下称为libapp<app name>_<target arch>.so。因此,如果我们的应用程序被称为QtApp,我们将复制库libappQtApp_x86_64.so。同样,我们也创建了一个Android.mk文件。这次的内容看起来有点不同:


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
# Module name should match apk name to be installed (without the .apk extension)
LOCAL_MODULE := QtApp
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
# Adds listed files under app's native library dir
LOCAL_PREBUILT_JNI_LIBS := \
    # Replace with the name of your app's library
    libQtApp_x86_64.so \

LOCAL_CERTIFICATE := platform
include $(BUILD_PREBUILT)

This time we let the build know we want to add a prebuilt app.
We also list the libraries we are providing with the app, and want to be installed under the app's own native library directory - here the app's own library, libappQtApp_x86_64.so:

这一次,我们让构建知道我们想要添加一个预构建的应用程序。
我们还列出了我们随应用程序提供的库,并希望安装在应用程序自己的本地库目录下-这里是应用程序自己库libappQtApp_x86_64.so:


LOCAL_PREBUILT_JNI_LIBS := \
    # Replace with the name of your app's library
    libappQtApp_x86_64.so \

The prebuilt JNI libraries for the app do not need to be declared as modules before including them. Instead, we provide the path to the library, suffix included, in relation to the Android.mk file.

应用程序的预构建JNI库不需要在包含它们之前声明为模块。相反,我们提供了与Android.mk文件相关的库路径,包括后缀。

Now that both the libraries and app have been added to the AOSP tree, we can build our image! For that, we follow the directions listed here.

​现在,库和应用程序都已添加到AOSP树中,我们可以构建我们的图像了!为此,我们遵循此处列出的说明。

Once we've created an Android Virtual Device based on the image we built, we can launch it on the emulator and have a look. We can see there is a folder /system/app/QtApp, the contents of which will look like this:

一旦我们根据我们构建的图像创建了一个Android虚拟设备,我们就可以在模拟器上启动它并进行查看。我们可以看到有一个文件夹/system/app/QtApp,其内容如下:



So the app's own library is now the only one found from under the app's own directory. Meanwhile, all the other Qt libraries are now installed under /system/lib64/qt/.

因此,应用程序自己的库现在是从应用程序自己目录下找到的唯一库。同时,所有其他Qt库现在都安装在/system/lib64/Qt/下。

Now QtApp, and all the other Qt system apps installed on the device can use that single set of shared libraries - no need for each app to bring its own!

现在,QtApp和设备上安装的所有其他Qt系统应用程序都可以使用同一组共享库-无需每个应用程序都自带!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在Android中使用Qt作为共享系统库 的相关文章

随机推荐

  • 使用OpenSSL做RSA签名验证 支付宝移动快捷支付 的服务器异步通知

    由于业务需要 我们需要使用支付宝移动快捷支付做收款 支付宝给了我们 移动快捷支付应用集成接入包支付接口 见支付宝包 WS SECURE PAY SDK 支付宝给的服务器demo只有Java C PHP三种 而我们服务器端使用的是C 这其中就
  • 建立ftp文件服务器群,2.1.6FTP文件服务器搭建.docx

    文件服务器 FTP 配置说明 FTP安装及基本配置 FileZillaServer软件安装 FileZilla Server的安装相对简单 一路按照默认安装即可 如图1 1至图1 8所示 图1 1 点击 I Agree 图1 2 点击Nex
  • echarts在vue中使用不报错,但是不显示

    没有设置div标签的宽和高 div class charts div charts width 900px height 500px
  • 一些神奇好用的网站

    文章目录 1 ilovepdf 2 Google Scholar 镜像 3 LetPub 4 Connected Papers 5 Overleaf 1 ilovepdf 网址 https www ilovepdf com 功能 PDF文件
  • Mysql如何定位慢查询(面试题)

    Mysql如何定位慢查询 面试题 相关概念 慢查询分析 慢查询工具定位 Arthas Prometheus Skywalking Mysql慢查询日志 相关概念 分析MySQL语句查询性能的方法除了使用 EXPLAIN 输出执行计划 还可以
  • 宝尊+艺康 面经

    baozun 研发岗 线下专场面试 宣讲之后现场笔试 笔试都是选择题 不难 38道题 30小题基础知识 比较广 8道推理题 数学推理和图形推理 图形难度大 笔试完之后等叫名字就去和面试官谈话 估计是根据笔试成绩 成绩高的先被叫去 每次面试基
  • TVS的典型应用(图文详解)

    TVS瞬态电压抑制二极管 是一种采用半导体工艺制成的单个PN 结或多个PN结集成的高效型电路保护器件 TVS内部芯片为半导体硅材料 具有很高的可靠性 响应速度快 低动态内阻 低钳位电压 电压精度高 击穿电压一般为 5 的偏差 封装多样化 贴
  • oracle字符集总结

    字符集总结author skatetime 2007 12 4 最近公司的数据库要迁移 所以就此机会总结下字符集的知识 以便自己对字符集更全面 更深入的认识 用了 一小天的时间 我是边测试边写 1 什么是oracle字符集 Oracle字符
  • 分布式事务概述

    1 基础概念 1 1 什么是事务 事务可以看做是一次大的活动 它由不同的小活动组成 这些活动要么全部成功 要么全部失败 1 2 本地事务 在计算机系统中 更多的是通过关系型数据库来控制事务 这是利用数据库本身的事务特性来实现的 因此叫数据库
  • 2022年大厂java高频面试题附带答案解析

    本篇分享的面试题内容主要包括 Java SpringMVC Spring Spring Boot Spring Cloud MyBatis ZooKeeper Dubbo Elasticsearch Redis MySQL RabbitMQ
  • 和枚举类相关的Map类——EnumMap

    1 EnumMap类的简介 EnumMap是一个与枚举类一起使用的Map实现 EnumMap中所有key都必须是单个枚举类的枚举值 创建EnumMap时必须显式或隐式指定它对应的枚举类 EnumMap在内部以数组形式保存 所以这种实现形式非
  • EFFECTIVE C++ (万字详解)(一)

    前言 effective C 是一本经典之作 其翻译较为贴合原著 但读起来未免有些僵硬而让人摸不着头脑 所以 我会以更为贴近中国人的理解 对此书进行一些阐释 条款01 把 C 看成一个语言联邦 C 由几个重要的次语言构成 C语言 区块 语句
  • js获取指定日期所在月份的第一天和最后一天,并遍历

    1 获取月份的第一天和最后一天 获取指定日期所在月份的第一天和最后一天 function getfirstDateAndlastDate dateStr let date new Date dateStr let year date get
  • npm-cli----Cannot find module 'D:\node\nodejs\node_module\bin\npm-cli.js'

    我输入 npm init 报这个错 输入 npm v 想查看npm的版本也是这个错 自己试着全局安装npm cli 还是这个错 反正只要和npm有关的命令通通是这个错 之后就开始我的百度之旅 发现根本就没一个帖子有用 该错还是错 我来说下我
  • 配置虚拟机桥接网络的步骤

    一 先打开虚拟机 然后点击左上角的编辑选项 然后点击虚拟网络编辑器 二 设置成桥接模式 并选择自动模式 然后点击确定 三 然后点击虚拟机内右上角的三个方块的图标 如图所示 四 点击有线连接下的齿轮图标 五 需要手动配置IPv4和IPv6网络
  • 二极管的工作原理,什么是二极管?

    二极管是一种电子器件 具有两不对称电导的电极 故名 二极 只允许电流由单一方向流过 所以最常应用其整流功能 二极管的工作原理 什么是二极管 二极管具有阳极和阴极两个端子 电流只能往单一方向流动 也就是说 电流可以从阳极流向阴极 而不能从阴极
  • 使用php语言开Excel的导入功能

    使用 PHP 语言开发 Excel 导入功能 你需要使用 PHPExcel 库 首先 你需要在你的 PHP 项目中安装 PHPExcel 库 你可以使用 Composer 来安装 如下所示 composer require phpoffic
  • C语言航空订票系统课程设计

    目录 1 设计目的 2总体设计和功能 3 菜单设计 4 各功能代码详解 闲话少扯 4 1 C语言文件的操作 4 2 读取航班信息 C语言知识回顾 4 3 打印航班信息 5 根据要求查找航班 航班号 起点站 终点站 6 订票功能 链表操作 前
  • STM32 HAL库:FreeRTOS系统 (带推荐使用除了Systick以外的时钟源问题及解决)

    1 简介 FreeRTOS是一个实时操作系统内核 作为一个轻量级的操作系统 功能包括 任务管理 时间管理 信号量 消息队列 内存管理 记录功能 软件定时器 协程等 可基本满足较小系统的需要 任务调度机制 优先级高的任务一旦就绪就能剥夺优先级
  • 在Android中使用Qt作为共享系统库

    Using Qt as shared system libraries in Android 在Android中使用Qt作为共享系统库 October 21 2022 by Tinja Paavosepp Comments 2022年10月