包安装示例
学习如何实现动态包安装和卸载。
注意: 如果您想在一个Linux机器上构建此示例,请阅读此内容。
介绍
此示例演示了如何使用appman-package-server动态安装和卸载包。系统UI附带一个内置应用程序(Builtin
蓝色),但允许您动态安装尽可能多的应用程序。左下角的“包”按钮打开一个对话框,您可以在其中首先连接到包服务器,然后安装或卸载包。
您需要运行实际的包服务器来测试此示例。有关如何执行的详细说明,请参阅appman-package-server文档。
为了方便,此示例附带两个预包装的应用程序(从installable-apps文件夹中的hello-world.red
和hello-world.green>)。实际的打包在
CMakeLists.txt
中完成,使用qt6_am_create_installable_package
函数。请注意,此函数目前处于技术预览状态,将来可能更改。
此外,此示例还将打印出启动命令,以在这些包上运行包服务器,并在应用程序输出中显示该命令:您必须将其复制并粘贴到shell中,以运行服务器。
入门指南
基本UI
main.qml
文件包含一个非常基本的组合UI,正如在其他示例中所见:左边的图标列表(显示已安装的应用程序)和右边的窗口组合区域。
此外,它还创建并初始化一个PackageServerInterface
组件实例(以下将提供更多信息)。每当服务器提供的包列表更改时,packagesDialog
中的packageModel
将相应更新。
包服务器接口
appman-package-server是一个独立进程,通过HTTP REST接口与系统UI通信。我们使用QML的 XMLHttpRequest机制与服务器通信,但我们还使用一个单独的PackageServerInterface
组件来封装通信,以便更方便地使用。
此组件期望设置以下一些必需属性,以便连接到服务器实例
required property string url required property string projectId required property string architecture
为了与服务器通信,以下简单的QML API可用。实际上,该packages
属性是一个将填充服务器上可用的包描述的列表。
property string statusText property bool isCompatible property var packages function reload() { _serverHello() } function install(id) { let dlurl = url + "/package/download?id=" + id + "&architecture=" + architecture let taskId = PackageManager.startPackageInstallation(dlurl) return taskId } function remove(id) { let taskId = PackageManager.removePackage(id, true) return taskId }
包对话框
当用户在主窗口中点击 软件包 按钮时,将打开 packagesDialog
。它允许您设置软件包服务器的 URL 和 acknowledgeMode
(请参见下文中的确认对话框)。如果服务器 URL 有效且可以连接到 appman-package-server 实例,对话框的下半部分将显示服务器上的可用软件包列表。然后用户可以选择要安装或删除的软件包。
使用 PackageServerInterface
组件与服务器通信以及安装和删除软件包。
onClicked: { if (isInstalled) packageServerInterface.remove(id) else packageServerInterface.install(id) }
确认对话框
出于安全原因,应用程序管理器期望系统 UI 确认软件包安装。这是通过响应 taskRequestingInstallationAcknowledge 信号调用 acknowledgePackageInstallation 方法来实现的。
本例展示了三种不同的方法来处理与用户交互相关的此问题。
enum AcknowledgeMode { Always, // always ask the user Never, // never ask the user CapabilitiesOnly // only ask the user, if the package needs capabilities }
根据 acknowledgeMode
属性,组件将自动确认任何安装请求、始终询问用户确认,或者如果软件包请求 能力(有关更多信息,请参见 清单定义),则询问用户确认。作为一个额外的复杂性,一个软件包可以包含多个应用程序,它们可以请求不同的能力。本例将简单地收集所有能力到一个平列表中。
property int mode: AcknowledgeDialog.AcknowledgeMode.Always property Connections connections: Connections { target: PackageManager function onTaskRequestingInstallationAcknowledge(taskId, pkg, extraMetaData, extraSignedMetaData) { // reduce the capabilities of all applications down to a set of unique values let capsSet = new Set() pkg.applications.forEach((app) => app.capabilities.forEach((cap) => capsSet.add(cap))) let capabilities = Array.from(capsSet) if ((mode === AcknowledgeDialog.Never) || ((mode === AcknowledgeDialog.CapabilitiesOnly) && !capabilities.length)) { PackageManager.acknowledgePackageInstallation(taskId) } else if ((mode === AcknowledgeDialog.Always) || ((mode === AcknowledgeDialog.CapabilitiesOnly) && capabilities.length)) { let d = acknowledgeDialog.createObject(root.contentItem, { taskId: taskId, packageName: pkg.name, capabilities: capabilities }) d.open() } } }
实际对话框是一个标准的 MessageDialog
,它将被动态实例化。根据用户是否接受或拒绝对话框,相应地通知 PackageManager。
onAccepted: if (!acknowledged) PackageManager.acknowledgePackageInstallation(taskId) onRejected: if (!acknowledged) PackageManager.cancelTask(taskId)
© 2024 The Qt Company Ltd。此处包含的文档贡献是各自所有者的版权。此处提供的文档是根据自由软件基金会在 GNU 自由文档许可证 1.3 版本 的条款发布的。Qt 及相关的徽标是 The Qt Company Ltd. 在芬兰和/或其他国家和地区的商标。所有其他商标均为各自所有者的财产。