欢迎光临
我们一直在努力

鸿蒙开发入坑篇(十六):元服务与万能卡片 (Atomic Services & Cards)

可以体验下鸿蒙Ai:CodeArts Doer代码智能体

🔗 项目地址:https://github.com/briefness/HarmonyDemo

更新说明:本文将介绍卡片的 渲染分离机制 及开发约束。

一、理论基础:渲染分离 (Snapshot Rendering)

1.1 为什么卡片的交互受限?

万能卡片(Form)不是一个迷你 App,而是由 SystemUI 进程 渲染的界面。

#mermaid-svg-Tv26OV3Ck4tTh0iF{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Tv26OV3Ck4tTh0iF .error-icon{fill:#552222;}#mermaid-svg-Tv26OV3Ck4tTh0iF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Tv26OV3Ck4tTh0iF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .marker.cross{stroke:#333333;}#mermaid-svg-Tv26OV3Ck4tTh0iF svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Tv26OV3Ck4tTh0iF p{margin:0;}#mermaid-svg-Tv26OV3Ck4tTh0iF .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .cluster-label text{fill:#333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .cluster-label span{color:#333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .cluster-label span p{background-color:transparent;}#mermaid-svg-Tv26OV3Ck4tTh0iF .label text,#mermaid-svg-Tv26OV3Ck4tTh0iF span{fill:#333;color:#333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .node rect,#mermaid-svg-Tv26OV3Ck4tTh0iF .node circle,#mermaid-svg-Tv26OV3Ck4tTh0iF .node ellipse,#mermaid-svg-Tv26OV3Ck4tTh0iF .node polygon,#mermaid-svg-Tv26OV3Ck4tTh0iF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Tv26OV3Ck4tTh0iF .rough-node .label text,#mermaid-svg-Tv26OV3Ck4tTh0iF .node .label text,#mermaid-svg-Tv26OV3Ck4tTh0iF .image-shape .label,#mermaid-svg-Tv26OV3Ck4tTh0iF .icon-shape .label{text-anchor:middle;}#mermaid-svg-Tv26OV3Ck4tTh0iF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Tv26OV3Ck4tTh0iF .rough-node .label,#mermaid-svg-Tv26OV3Ck4tTh0iF .node .label,#mermaid-svg-Tv26OV3Ck4tTh0iF .image-shape .label,#mermaid-svg-Tv26OV3Ck4tTh0iF .icon-shape .label{text-align:center;}#mermaid-svg-Tv26OV3Ck4tTh0iF .node.clickable{cursor:pointer;}#mermaid-svg-Tv26OV3Ck4tTh0iF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .arrowheadPath{fill:#333333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Tv26OV3Ck4tTh0iF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Tv26OV3Ck4tTh0iF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Tv26OV3Ck4tTh0iF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Tv26OV3Ck4tTh0iF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Tv26OV3Ck4tTh0iF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Tv26OV3Ck4tTh0iF .cluster text{fill:#333;}#mermaid-svg-Tv26OV3Ck4tTh0iF .cluster span{color:#333;}#mermaid-svg-Tv26OV3Ck4tTh0iF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Tv26OV3Ck4tTh0iF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Tv26OV3Ck4tTh0iF rect.text{fill:none;stroke-width:0;}#mermaid-svg-Tv26OV3Ck4tTh0iF .icon-shape,#mermaid-svg-Tv26OV3Ck4tTh0iF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Tv26OV3Ck4tTh0iF .icon-shape p,#mermaid-svg-Tv26OV3Ck4tTh0iF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Tv26OV3Ck4tTh0iF .icon-shape rect,#mermaid-svg-Tv26OV3Ck4tTh0iF .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Tv26OV3Ck4tTh0iF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Tv26OV3Ck4tTh0iF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Tv26OV3Ck4tTh0iF :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

1. updateForm (数据)

2. 代理数据

3. 渲染布局

App 主进程 (Provider)

系统服务

SystemUI 桌面进程 (Renderer)

桌面卡片

  • 进程分离:
    • App 进程: 负责提供数据 (FormBindingData)。
    • SystemUI 进程: 负责解析布局、绘制卡片。
  • 安全性与性能: 为了保证桌面性能,系统限制卡片执行复杂的 JS 逻辑、高频动画及复杂 Canvas 绘图。
  • 1.2 快照技术

    当调用 updateForm 时,系统序列化布局树,桌面进程收到后进行布局更新。 这使得卡片非常省电。

    二、核心组件:FormProvider

    卡片的后台逻辑是由 FormExtensionAbility 管理的。

    2.1 生命周期

    • onAddForm: 用户把卡片拖到桌面上。
    • onUpdateForm: 定时刷新(最小 30 分钟)。
    • onRemoveForm: 用户移除卡片。

    #mermaid-svg-llRGMfXTh4LZW5Cu{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-llRGMfXTh4LZW5Cu .error-icon{fill:#552222;}#mermaid-svg-llRGMfXTh4LZW5Cu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-llRGMfXTh4LZW5Cu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-llRGMfXTh4LZW5Cu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-llRGMfXTh4LZW5Cu .marker.cross{stroke:#333333;}#mermaid-svg-llRGMfXTh4LZW5Cu svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-llRGMfXTh4LZW5Cu p{margin:0;}#mermaid-svg-llRGMfXTh4LZW5Cu .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-llRGMfXTh4LZW5Cu .cluster-label text{fill:#333;}#mermaid-svg-llRGMfXTh4LZW5Cu .cluster-label span{color:#333;}#mermaid-svg-llRGMfXTh4LZW5Cu .cluster-label span p{background-color:transparent;}#mermaid-svg-llRGMfXTh4LZW5Cu .label text,#mermaid-svg-llRGMfXTh4LZW5Cu span{fill:#333;color:#333;}#mermaid-svg-llRGMfXTh4LZW5Cu .node rect,#mermaid-svg-llRGMfXTh4LZW5Cu .node circle,#mermaid-svg-llRGMfXTh4LZW5Cu .node ellipse,#mermaid-svg-llRGMfXTh4LZW5Cu .node polygon,#mermaid-svg-llRGMfXTh4LZW5Cu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-llRGMfXTh4LZW5Cu .rough-node .label text,#mermaid-svg-llRGMfXTh4LZW5Cu .node .label text,#mermaid-svg-llRGMfXTh4LZW5Cu .image-shape .label,#mermaid-svg-llRGMfXTh4LZW5Cu .icon-shape .label{text-anchor:middle;}#mermaid-svg-llRGMfXTh4LZW5Cu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-llRGMfXTh4LZW5Cu .rough-node .label,#mermaid-svg-llRGMfXTh4LZW5Cu .node .label,#mermaid-svg-llRGMfXTh4LZW5Cu .image-shape .label,#mermaid-svg-llRGMfXTh4LZW5Cu .icon-shape .label{text-align:center;}#mermaid-svg-llRGMfXTh4LZW5Cu .node.clickable{cursor:pointer;}#mermaid-svg-llRGMfXTh4LZW5Cu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-llRGMfXTh4LZW5Cu .arrowheadPath{fill:#333333;}#mermaid-svg-llRGMfXTh4LZW5Cu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-llRGMfXTh4LZW5Cu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-llRGMfXTh4LZW5Cu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-llRGMfXTh4LZW5Cu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-llRGMfXTh4LZW5Cu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-llRGMfXTh4LZW5Cu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-llRGMfXTh4LZW5Cu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-llRGMfXTh4LZW5Cu .cluster text{fill:#333;}#mermaid-svg-llRGMfXTh4LZW5Cu .cluster span{color:#333;}#mermaid-svg-llRGMfXTh4LZW5Cu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-llRGMfXTh4LZW5Cu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-llRGMfXTh4LZW5Cu rect.text{fill:none;stroke-width:0;}#mermaid-svg-llRGMfXTh4LZW5Cu .icon-shape,#mermaid-svg-llRGMfXTh4LZW5Cu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-llRGMfXTh4LZW5Cu .icon-shape p,#mermaid-svg-llRGMfXTh4LZW5Cu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-llRGMfXTh4LZW5Cu .icon-shape rect,#mermaid-svg-llRGMfXTh4LZW5Cu .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-llRGMfXTh4LZW5Cu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-llRGMfXTh4LZW5Cu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-llRGMfXTh4LZW5Cu :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    添加卡片

    返回 BindingData

    触发

    updateForm

    移除卡片

    清理

    用户操作

    onAddForm (创建 ID)

    显示 UI

    系统定时器 (30min)

    onUpdateForm

    onRemoveForm

    销毁 ID

    最佳实践: 在 onUpdateForm 里,不要做耗时操作。通过 TaskPool 异步获取数据,再调用 formProvider.updateForm。

    三、开发约束 (Restrictions)

    由于渲染机制限制,只能使用 ArkTS 的子集。

    • ❌ 不支持: List, Scroll (除了特定组件), 自定义组件的复杂生命周期。
    • ✅ 支持: Column, Row, Image, Text, Button.

    四、交互:postCardAction

    卡片的主要交互方式。

    • router: 跳回 App。
    • call: 后台静默执行(如:切歌)。
      • 注意:call 事件有 5 秒限制。超时未返回,系统会终止 Action。

    五、总结

    开发卡片需要遵循 “克制” 的原则。 它是 App 的延伸,负责展示核心信息。

    下一篇,将进入 性能调优,利用 Profiler 进行性能分析。

    赞(0)
    未经允许不得转载:171主机测评 » 鸿蒙开发入坑篇(十六):元服务与万能卡片 (Atomic Services & Cards)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址