意图系统UI和应用示例
三个应用和一个通过意图通信的系统UI。
注意:如果您想在Linux机器上构建示例,请阅读此内容。
简介
本示例展示了系统UI和应用程序如何发送和接收意图。与系统UI示例:“Hello World!”类似,为了专注于意图,窗口管理方面被降至最低:右侧的2x2网格将始终显示左上角的系统UI部分(灰色),而三个应用程序(红色、绿色和蓝色)将动态占据其他角落。您可以在左侧看到可用应用程序的名称和图标;点击它们各自的图标以启动和停止这些应用程序。
每个应用程序以及系统UI看起来都相似,并在UI中具有相同的功能:您可以在顶部的下拉框中选择一个可用的意图ID(标有“意图”),并可选地指定应处理所选请求的相应应用程序(标有“应用程序”)。点击“请求”/“广播”按钮将创建并发送相应的意图请求到应用程序管理器的IntentServer进行处理。
- “意图”和“应用程序”组合有效,并且目标应用程序能够处理请求;此请求的结果将作为JSON文本显示在标签为“请求”的下方输出字段中。
- “意图”和“应用程序”组合无效或目标应用程序无法正确处理请求;此请求的错误信息将显示为普通文本,标记为“请求”的下方输出字段中。
- 未指定“应用程序”,并且选择的“意图”可以由多个应用程序处理;在这种情况下,示例的系统UI将显示一个对话框,提示用户消除歧义。
文件和文件夹结构
本示例包含一个系统UI和三个示例应用程序(“红色意图”、“绿色意图”和“蓝色意图”),总共四个单独的QML应用程序。系统UI最终也是一个QML应用程序,尽管它是一个特殊的应用程序。
每个应用程序都放在以下所描述的单独目录中。由于所有应用程序和系统UI都使用基于QtQuickControls 2的UI,因此其组件生活在共享目录中。
am-config.yaml
system-ui.qml
apps
intents.blue
icon.png
info.yaml
main.qml
intents.red
icon.png
info.yaml
main.qml
intents.green
icon.png
info.yaml
main.qml
shared
IntentsApplicationWindow.qml
IntentsUIPage.qml
如上图所示,每个应用程序除了主QML文件外,还有一个图标和一个info.yaml
文件,该文件包含应用程序元数据,还包括该应用可以处理的目的定义。
运行示例
假设appman
可执行文件在您的路径中,您可以按照以下方式运行系统UI
examples/applicationmanager/intents$ appman -c am-config.yaml
这是您应该看到的
有关am-config.yaml
的内容和其他命令行选项的信息,您可以运行appman –help
或查看
应用程序实现
所有应用程序(红色、绿色和蓝色)都是相同的,它们的main.qml
只是实例化了共享的IntentsApplicationWindow
组件。
import "../../shared"
IntentsApplicationWindow { }
IntentsApplicationWindow组件实际上是一个顶级ApplicationManagerWindow,其UI内容是通过实例化共享的IntentsUIPage
组件来定义的。这个UI组件没有任何特定于意图的代码,所以实际的发送是在连接到IntentsUIPage请求和广播信号的处理程序中完成的
onRequest: (intentId, applicationId, parameters) => { let request = IntentClient.sendIntentRequest(intentId, applicationId, parameters) request.onReplyReceived.connect(function() { intentPage.setResult(request.requestId, request.succeeded, request.succeeded ? request.result : request.errorMessage) }) }
并且
onBroadcast: (intentId, parameters) => { IntentClient.broadcastIntentRequest(intentId, parameters) }
在通过具有在UI中选择参数的IntentClient::sendIntentRequest
调用后,示例代码将一个函数对象连接到请求的replyReceived信号。结果是放置在UI中的请求字段中。另一方面,广播不会生成回复。
此外,IntentsApplicationWindow定义了所有必要的IntentHandlers,例如
IntentHandler { intentIds: [ "rotate-window" ] onRequestReceived: (request) => { rotationAnimation.start() request.sendReply({ "done": true }) } }
这些intent处理程序并不复杂,每个只是触发一个在本文件中定义的基本动画,因此对于rotate-window
意图来说,这将是这样
RotationAnimation on rotation { id: rotationAnimation running: false duration: 500; from: 0; to: 360 }
在QML中,仅实现IntentHandlers是不够的,因为应用程序管理器需要有关哪些应用程序支持哪些意图的信息。在应用程序运行之前,必须将这些信息提供给应用程序管理器,以实现基于意图请求的自动启动应用程序。对于应用程序管理器中的其他所有应用程序配置,都是通过应用程序的清单文件info.yaml
来完成的
红色应用程序定义了三个可用的意图
intents: - id: rotate-window name: en: Rotate Red - id: scale-window name: en: Scale Red - id: broadcast/blink-window name: en: Blink Red
此外,红色应用程序获得了call-blue
功能,这是蓝色应用程序中某些意图所必需的。
capabilities: 'call-blue'
绿色应用程序只定义了两个可用的意图。请注意,即使这个应用程序通过共享的IntentsApplicationWindow组件对scale-window
意图有IntentHandler,但这个处理程序永远不会被调用,因为这个意图ID没有通过info.yaml
清单注册到系统中
intents: - id: rotate-window name: en: Rotate Green - id: broadcast/blink-window name: en: Blink Green handleOnlyWhenRunning: yes
除此之外,broadcast/blink-window
意图被标记为handleOnlyWhenRunning: yes
,这阻止了在特定意图的广播上自动启动绿色
应用程序。
蓝色应用程序有最复杂的意图定义。除了处理和红色应用程序相同的三个意图外,它还注册了一个具有属性visibility: private
的blue-window-private
意图。私有意图只能由注册它们的同一应用程序请求,所以在这个例子中,只有蓝色能够成功请求blue-window-private
意图。此外,rotate-window
意图只能由具有call-blue
能力的应用程序请求:在这里,红色应用程序带有所需的功能,而绿色
则不具备。
intents: - id: rotate-window name: en: Rotate Blue requiredCapabilities: [ 'call-blue' ] - id: scale-window name: en: Scale Blue - id: broadcast/blink-window name: en: Blink Blue - id: blue-window-private name: en: Blue Private Intent visibility: private
系统UI实现
除了处理应用程序启动和停止的左侧栏之外,System UI还具有两个特殊功能,用于处理意图机制
- 在系统UI中处理意图
- 意图请求去歧义
在系统UI中处理意图
意图不仅可以在应用程序中处理,也可以在系统UI中处理。由于系统UI始终运行,我们不需要依赖 info.yaml
清单文件来定义支持的任务,而是可以直接将所需元数据的声明直接作为 IntentServerHandler 组件的属性。实际的 IntentServerHandler 从 IntentHandler 继承而来,因此与它的应用程序端对应部分工作方式相同:它只添加了所需的属性来定义所有元数据(例如 names
、icon
等)。
IntentServerHandler { intentIds: [ "rotate-window" ] names: { "en": "Rotate System UI" } visibility: IntentObject.Public onRequestReceived: (request) => { rotationAnimation.start() request.sendReply({ "wasRequestedBy": request.requestingApplicationId }) } }
处理器的回调几乎与在应用程序中的一样。唯一值得注意的是,我们可以访问 requestingApplicationId 来识别请求的来源;出于安全原因,此数据对于应用程序中的意图处理器不可用。
意图请求去歧义
此示例实现了一个UI,允许用户选择如何去歧义传入的意图请求。在这里注册对IntentServer去歧义请求的登记。
Connections { target: IntentServer function onDisambiguationRequest(requestId, potentialIntents) { disambiguationDialog.add(requestId, potentialIntents) } }
由于我们希望对系统中并行意图请求的数量保持灵活性,我们只需将传入的请求添加到队列(allRequests
)。消耗该队列的 Dialog
是一个相当标准的 QtQuickControls 2 对话框,它为您提供了一个显示来自 IntentServer::disambiguationRequested() 信号的可能应用程序选择的优美UI。在按 确定 或 取消 后,对话框将通知 IntentServer 用户的决定。
onAccepted: { IntentServer.acknowledgeDisambiguationRequest(currentRequest.requestId, currentRequest.intents[handlingApplications.currentIndex]); showNext() } onRejected: { IntentServer.rejectDisambiguationRequest(currentRequest.requestId) showNext() }
© 2024 Qt公司有限公司。本文件中包含的文档贡献是各自所有者的版权。本文件提供的文档根据自由软件基金会发布的 GNU自由文档许可证版本1.3 的条款提供许可。Qt及其标志是芬兰以及/或其他国家/地区的 Qt公司有限公司的商标 。所有其他商标均为其各自所有者的财产。