-
-
[原创]深度解析HarmonyOS SDK实况窗服务源码,Get不同场景下的多种模板
-
发表于: 2024-8-28 11:41 3021
-
HarmonyOS SDK实况窗服务(Live View Kit)作为一个实时呈现应用服务信息变化的小窗口,遍布于设备的各个使用界面,它的魅力在于将复杂的应用场景信息简洁提炼并实时刷新,在不影响当前其他应用操作的情况下,时刻向用户展示最新的信息动态,用户也可以点击实况窗卡片或胶囊进入应用落地页查看详细信息,享受来自应用的高效信息同步服务。
实况窗服务为不同场景定制了多样化的卡片模板,包括进度可视化模板、强调文本模板、左右文本模板、赛事比分模板、导航模板,除了这5种卡片形态的模板外,实况窗还有实况胶囊和实况计时器两种形态。下面,本文将详细展示这些模板,介绍其适用的场景,并讲解模板的具体实现步骤。
开发准备
在创建本地实况窗之前,需要先完成基本的准备工作,并开通实况窗服务权益。开通实况窗权益大致分为5个步骤,详细的申请步骤可参考实况窗服务的开发指南。
开发步骤
下面将以在本地创建、更新和结束实况窗为例,展示具体的开发步骤。
1.导入liveViewManager。
在创建本地实况窗前,需要在项目中导入liveViewManager,并新建实况窗控制类,构造isLiveViewEnabled()方法,用于校验实况窗开关是否打开。打开实况窗开关是创建实况窗的前提条件。示例代码如下:
1 2 3 4 5 6 7 | import { liveViewManager } from '@kit.LiveViewKit' ; export class LiveViewController { private static async isLiveViewEnabled(): Promise<boolean> { return await liveViewManager.isLiveViewEnabled(); } } |
2.创建实况窗。
实况窗根据扩展区不同共有5种样式模板:进度可视化模板、强调文本模板、左右文本模板、赛事比分模板和导航模板。
进度可视化模板
进度可视化模板可适用于打车、外卖等需要呈现完整进程及当前节点的场景,通过进度可视化模板的实况窗,用户可一眼查看应用的服务进程和实时变化。这里以即时配送场景为例,展示具体的示例代码。
在构建LiveViewController后,需要在代码中初始化LiveViewController并调用liveViewManager.startLiveView()方法创建实况窗。其中event的取值为DELIVERY则代表即时配送场景,若取值为TAXI则表示出行打车场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "DELIVERY" , / / 实况窗的应用场景。DELIVERY:即时配送(外卖、生鲜) liveViewData: { primary: { title: "骑手已接单" , content: [ { text: "距商家 " }, { text: "300 " , textColor: "#FF007DFF" }, { text: "米 | " }, { text: "3 " , textColor: "#FF007DFF" }, { text: "分钟到店" } ], / / 所有文本仅能设置为一种颜色,不设置textColor时,默认展示 #FF000000 keepTime: 15 , clickAction: await LiveViewController.buildWantAgent(), layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS, progress: 40 , color: "#FF317AF7" , backgroundColor: "#f7819ae0" , indicatorType: liveViewManager.IndicatorType.INDICATOR_TYPE_UP, indicatorIcon: "indicator.png" , / / 进度条指示器图标,取值为 "/resources/rawfile" 路径下的文件名 lineType: liveViewManager.LineType.LINE_TYPE_DOTTED_LINE, nodeIcons: [ "icon_1.png" , "icon_2.png" , "icon_3.png" ] / / 进度条每个节点图标, 取值为 "/resources/rawfile" 路径下的文件名 } } } }; } private static async isLiveViewEnabled(): Promise<boolean> { return await liveViewManager.isLiveViewEnabled(); } private static async buildWantAgent(): Promise<Want> { const wantAgentInfo: wantAgent.WantAgentInfo = { wants: [ { bundleName: 'xxx.xxx.xxx' , / / 应用实际bundleName abilityName: 'EntryAbility' } as Want ], operationType: wantAgent.OperationType.START_ABILITIES, requestCode: 0 , wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] }; const agent = await wantAgent.getWantAgent(wantAgentInfo); return agent; } } |
强调文本模板
强调文本模板适用于取餐、排队等需要强调部分文本信息的场景。通过强调文本模板实况窗,用户可以快速获取取餐码、排号情况等重要信息,这里以取餐场景为例,展示具体的示例代码。
在强调文本模板中,event取值为PICK_UP则代表取餐场景,若取值为QUEUE则代表排队场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "PICK_UP" , / / 实况窗的应用场景。PICK_UP:取餐。 liveViewData: { primary: { title: "餐品已备好" , content: [ { text: "请前往" , textColor: "#FF000000" }, { text: "XXX店取餐" , textColor: "#FF000000" } ], keepTime: 15 , clickAction: await LiveViewController.buildWantAgent(), layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PICKUP, title: "取餐码" , content: "72988" , underlineColor: "#FF0A59F7" , descPic: "coffee.png" } } } }; } ... ... } |
左右文本模板
左右文本模板适用于高铁、航班等左右信息对称的场景,通过该模板,用户可以快速获取始发地、目的地、开始和结束时间等出行信息。这里以高铁列车票场景为例,展示具体的示例代码。
在左右文本模板中,event取值为TRAIN则代表高铁/火车场景,若取值为FLIGHT则代表航班场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "TRAIN" , / / 实况窗的应用场景。TRAIN:高铁 / 火车。 liveViewData: { primary: { title: "列车检票提醒" , content: [ { text: "检票口 " }, { text: "6B " , textColor: "#FF007DFF" }, { text: "| 座位 " }, { text: "03车 12F" , textColor: "#FF007DFF" } ], / / 所有文本仅能设置为一种颜色,不设置textColor时,默认展示 #FF000000 keepTime: 15 , clickAction: await LiveViewController.buildWantAgent(), / / 点击实况窗默认动作。 layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_FLIGHT, firstTitle: "09:00" , firstContent: "上海虹桥" , lastTitle: "14:20" , lastContent: "汉口" , spaceIcon: "icon.png" , isHorizontalLineDisplayed: true, additionalText: "以上信息仅供参考" / / 扩展区底部内容,仅可用于左右文本模板。 } } } }; } ... ... } |
赛事比分模板
赛事比分模板适用于竞技比赛的场景,通过该模板,用户可以快速获取比赛队伍、当前比分、场次等比赛信息。
在赛事比分模板中,SCORE代表赛事比分场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "SCORE" , / / 实况窗的应用场景。SCORE:赛事比分。 liveViewData: { primary: { title: "第四节比赛中" , content: [ { text: "XX VS XX" }, { text: " | " , textColor: "#f7b7b1b3" }, { text: "小组赛第五场" } ], keepTime: 1 , clickAction: await LiveViewController.buildWantAgent(), layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_SCORE, hostName: "队名A" , hostIcon: "host.png" , hostScore: "110" , guestName: "队名B" , guestIcon: "guest.png" , guestScore: "102" , competitionDesc: [ { text: "●" , textColor: "#FFFF0000" }, { text: "Q4" } ], competitionTime: "02:16" , isHorizontalLineDisplayed: true } } } }; } ... ... } |
导航模板
导航模板适用于出行导航场景。通过该模板,用户可以快速获取所需导航的目的地大致方位信息。在导航模板中,event取值为NAVIGATION则代表导航场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "NAVIGATION" , / / 实况窗的应用场景。NAVIGATION:导航。 liveViewData: { primary: { title: "178米后左转" , content: [ { text: "去往" , textColor: "#FF000000" }, { text: " 南京东路" , textColor: "#FF000000" } ], keepTime: 15 , clickAction: await LiveViewController.buildWantAgent(), layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_NAVIGATION, currentNavigationIcon: "navigation.png" , navigationIcons: [ "left.png" , "straight.png" , "straight.png" , "right.png" ] } } } }; } ... ... } |
实况胶囊
实况胶囊是在设备熄屏和状态栏中展示的区别于卡片态的另一种实况形态,胶囊内需显示最精简、最重要的内容,保证用户一瞥即得重要信息。并且,胶囊形态各模板参数固定,与创建实况窗时的模板类型无关。
在同步创建实况窗胶囊时,需要在liveViewManager.LiveView结构体中携带胶囊所需的参数capsule,不同胶囊类型携带不同的参数。可创建的胶囊类型有:文本胶囊、计时器胶囊和进度胶囊。这里以文本胶囊为例,展示具体的示例代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "DELIVERY" , / / 实况窗的应用场景。DELIVERY:即时配送(外卖、生鲜)。 liveViewData: { primary: { title: "餐品待支付" , content: [ { text: "咖啡 " , textColor: "#FF000000" }, { text: "等2件商品" , textColor: "#FF000000" } ], keepTime: 15 , clickAction: await LiveViewController.buildWantAgent(), layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PICKUP, title: "待支付金额" , content: "25.5元" , underlineColor: "#FF0A59F7" , descPic: "coffee.png" } }, / / 实况胶囊相关参数 capsule: { type : liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT, status: 1 , icon: "capsule_store.png" , backgroundColor: "#ff0676e7" , title: "待支付" } } }; } ... ... } |
实况窗计时器
实况窗计时器适用于排队、抢票等场景。开发者若需要使用实况窗计时器,则需在liveViewManager.LiveView结构体中的配置timer字段,并在当前支持的字段中使用占位符:${placeholder.timer}。
具体的示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "QUEUE" , / / 实况窗的应用场景。QUEUE:排队 timer: { time: 620000 , isCountdown: false, isPaused: false }, liveViewData: { primary: { title: "大桌4人等位 32桌" , content: [ { text: "已等待 " }, { text: "${placeholder.timer}" , textColor: "#ff10c1f7" }, { text: " | 预计还需>30分钟" } ], / / 所有文本仅能设置为一种颜色,不设置textColor时,默认展示 #FF000000 keepTime: 15 , clickAction: await LiveViewController.buildWantAgent(), layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS, progress: 0 , color: "#FFFF0000" , backgroundColor: "#FF000000" , indicatorType: liveViewManager.IndicatorType.INDICATOR_TYPE_OVERLAY, indicatorIcon: "indicator.png" , / / 进度条指示器图标,取值为 "/resources/rawfile" 路径下的文件名 lineType: liveViewManager.LineType.LINE_TYPE_DOTTED_LINE, nodeIcons: [ "icon_1.png" , "icon_2.png" ] / / 进度条每个节点图标,取值为 "/resources/rawfile" 路径下的文件名 } } } }; } ... ... } |
3.本地更新和结束实况窗。
在本地创建完实况窗后,若应用业务状态发生变化,则需要调用liveViewManager的updateLiveView()更新实况窗,更新时对请求体中需要修改的对应参数进行修改。在该应用的服务进程结束时,需要调用stopLiveView()来结束实况窗。这里以即时配送场景的进度可视化模板为例,来说明更新和结束实况窗及实况胶囊的方法,具体示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | import { liveViewManager } from '@kit.LiveViewKit' ; import { Want, wantAgent } from '@kit.AbilityKit' ; export class LiveViewController { private static contentColor: string = '#FF000000' ; private static capsuleColor: string = '#FF308977' ; public async startLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 创建实况窗 const defaultView = await LiveViewController.buildDefaultView(); return await liveViewManager.startLiveView(defaultView); } public async updateLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 修改实况窗内容 const defaultView = await LiveViewController.buildDefaultView(); defaultView.liveViewData.primary.title = "预计23:49送达" ; defaultView.liveViewData.primary.content = [ { text: "等待商家接单," , textColor: LiveViewController.contentColor }, { text: "03:20未接单自动取消" , textColor: LiveViewController.contentColor } ]; defaultView.liveViewData.primary.layoutData = { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS, progress: 0 , lineType: 0 , nodeIcons: [ / / 进度条每个节点图标,取值为 "/resources/rawfile" 路径下的文件名 'icon_store_white.png' , 'icon_finish.png' ] }; defaultView.liveViewData.capsule = { type : liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT, status: 1 , icon: 'capsule_store.png' , backgroundColor: LiveViewController.capsuleColor, title: "待接单" }; / / 更新实况窗 return await liveViewManager.updateLiveView(defaultView); } public async stopLiveView(): Promise<liveViewManager.LiveViewResult> { / / 校验实况窗开关是否打开 if (!LiveViewController.isLiveViewEnabled()) { throw new Error( "Live view is disabled." ); } / / 修改实况窗内容 const defaultView = await LiveViewController.buildDefaultView(); defaultView.liveViewData.primary.title = '商品已送达' ; defaultView.liveViewData.primary.content = [ { text: '感谢您的认可,' , textColor: LiveViewController.contentColor }, { text: '期待下一次光临' , textColor: LiveViewController.contentColor } ]; defaultView.liveViewData.primary.layoutData = { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS, progress: 100 , lineType: 0 , nodeIcons: [ / / 进度条每个节点图标,取值为 "/resources/rawfile" 路径下的文件名 'icon_order.png' , 'icon_finish.png' ] }; defaultView.liveViewData.capsule = { type : liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT, status: 1 , icon: 'capsule_gps.png' , backgroundColor: LiveViewController.capsuleColor, title: '已送达' }; / / 结束实况窗 return await liveViewManager.stopLiveView(defaultView); } private static async buildDefaultView(): Promise<liveViewManager.LiveView> { return { / / 构造实况窗请求体 id : 0 , / / 实况窗 ID ,开发者生成。 event: "DELIVERY" , / / 实况窗的应用场景。DELIVERY:即时配送(外卖、生鲜) liveViewData: { primary: { title: "餐品待支付" , content: [ { text: "咖啡 " , textColor: "#FF000000" }, { text: "等2件商品" , textColor: "#FF000000" } ], keepTime: 15 , clickAction: await LiveViewController.buildWantAgent(), layoutData: { layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PICKUP, title: "待支付金额" , content: "25.5元" , underlineColor: "#FF0A59F7" , descPic: "coffee.png" } }, / / 实况胶囊相关参数 capsule: { type : liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT, status: 1 , icon: "capsule_store.png" , backgroundColor: "#FF308977" , title: "待支付" , content: "..." } } }; } ... ... } |
了解更多详情>>
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!