目录
1 概述
Live View Kit(实况窗服务)支持应用将订单或者服务的实时状态信息变化在设备的关键界面展示,并对展示信息的生命周期、用户界面UI效果等进行管理。
1.1 场景介绍
实况窗是一种帮助用户聚焦正在进行的任务,方便快速查看和即时处理的通知形态,具有时段性、时效性、变化性的特点。
在展示形态上,实况窗支持在锁屏、通知中心、状态栏等位置展示,主要有两种展示形式:胶囊态和卡片态。
通知中心 | 状态栏 | 锁屏 |
---|---|---|
|
| |
1.1.1 时段性
该事件或服务需要持续一段时间,有明确的开始和结束,而非单点的提醒或信息。
例:打车、外卖等从事件开始到结束需要经历一段时间,属于实况窗;天气提示、电影票等单点提醒,则不属于实况窗。
1.1.2 时效性
内容为正在进行或即时发生的事件或服务的提醒,在特定时间段内,信息对用户有价值。
例:打车行程中、外卖配送中等正在进行的用户活动;2天后的机票,在刚买时不提醒,而在出发前提示,具体提醒时间根据业务实际情况确定,属于实况窗。权限调用、功能待机等系统状态,不属于实况窗。
1.1.3 变化性
实况窗所展示的内容需要动态更新,以确保用户看到最新的状态。
1.2 产品优势
- 面向HarmonyOS NEXT及以上的全量手机、平板设备
实况窗特性与设备硬件完全解耦,开发者接入后,可以覆盖到所有HarmonyOS NEXT及以上的全量手机、平板设备。
- 一步接入多触达点展示
开发者一次接入,可以实现包括锁屏、通知中心、状态栏在内多触达点展示实况窗。
- 不打断现有的操作,用户可及时关注服务进展
状态栏的实况胶囊支持点击交互,用户可以在任何界面查看实况胶囊或者点击实况胶囊展开卡片,查看详细进展。
实况窗点击后也可直接进入落地页,方便用户快速进入应用查看。
- 服务全流程展示,提升业务履约效率
用户可以在多个触达点及时关注到服务的最新进展,帮助业务实现服务的快速、高效闭环,提升业务履约效率。
1.3 支持的范围与场景
说明
- 实况窗目前为Beta阶段,开放申请。
- 实况窗支持HarmonyOS NEXT及以上的操作系统版本。
- 实况窗当前仅支持手机和平板机型,暂不支持模拟器使用。
1.3.1 实况窗场景准入原则
- 该活动场景是用户非常关注,且需要反复查看或快捷操作。
- 活动有开始和结束时间,且活动总时长较短,最长不得超过8小时。
- 用户对接收到该活动的实况窗通知有明确的预期,通常为用户主动行为触发实况窗通知。
- 需要确保展示内容对用户有足够的价值,且不可用于营销、广告场景。
1.3.2 实况窗支持对接的场景
场景类型 | EVENT取值 | 场景描述 | 适用范围 |
---|---|---|---|
出行打车 | TAXI | 用户线上约车后,向用户展示司机接驾等待时间、行程中的剩余距离和时间等信息。 | 适用于网约车、出租车、拼车、顺风车等场景。 |
即时配送 | DELIVERY | 指配送员将餐品、商品送达到用户指定地点的业务场景,通常在较短时间内完成配送环节。 | 适用于外卖、生鲜配送、同城配送等场景。 |
航班 | FLIGHT | 用户主动关注某个航班时,向用户展示航班的关键变动,如航班开始登机、航班起飞、航班延误、航班取消、航班到达等关键场景。 | 适用于用户通过航班出行或者主动关注某个航班进展的场景。 |
高铁/火车 | TRAIN | 用户通过高铁、火车出行,向用户展示检票口、座位号、车次信息及列车运行状态等信息。 | 适用于高铁出行、火车出行的场景。 |
排队 | QUEUE | 需要通过排队叫号的方式,按顺序为用户提供服务的业务场景。 | 适用于办事大厅、医院、银行、餐饮等排队叫号能力场景。 |
取餐 | PICK_UP | 指的是用户完成餐品/商品下单后,自行取餐或者取件的场景。 | 适用于餐饮线下取餐提醒,包括餐品排队情况、制作进度、取餐提醒等。 |
赛事比分 | SCORE | 展示比赛双方成绩变化情况。 | 适用于游戏赛事、体育赛事等展示比分变化情况的场景。 |
共享租赁 | RENT | 用户使用临时租赁服务时,向用户展示实时租赁时长和费用等租赁状态信息的场景。 | 适用于共享单车、共享充电宝、停车场临时停车等场景。 |
计时 | TIMER | 用户在某个短时间段持续的正计时或任务前的倒计时场景。 | 适用于专注时刻、番茄时钟、抢票倒计时提醒场景,仅限于工具类应用申请(计时场景仅支持通过端侧创建与更新)。 |
运动锻炼 | WORKOUT | 运动过程中,向用户实时展示运动的时长和进度等信息。 | 适用于户外或室内的运动记录,如跑步、骑行等。 |
导航 | NAVIGATION | 用户使用导航服务时,展示将要发生的路线变化。 | 适用于步行导航、骑行导航、车辆导航。 |
1.4 受限说明
- 实况窗的推送受权益管控,应用接入时,需要根据文档的指导开通实况窗权益。
- 应用在推送实况窗通知时,本地实况窗创建依赖应用进程运行,创建后支持本地更新和通过Push Kit更新两种方式。
- 实况窗可以通过Push Kit进行更新,保证实况窗不依赖应用进程的存活。通过Push Kit的更新,实况窗完成在生命周期内正常的更新和结束。
- 单个实况窗的生命周期最长不超过8小时,超过8小时后,系统会认为实况窗结束。
- 通过Push Kit更新实况窗时,单个实况窗消息,出行打车与赛事比分场景每个设备每5分钟最多更新30次,每小时最多更新180次。其余场景每个设备每5分钟最多更新10次,每小时最多更新60次。超过频次部分将丢弃不下发。
- 为了确保用户看到内容的时效性,请确保对实况窗内容进行及时更新。系统将在实况窗超过2小时未更新时,隐藏实况窗在状态栏胶囊和锁屏的展示,保留通知中心展示;超过4小时未更新,系统会认为实况窗结束,并从各个展示入口清除该实况窗。
- 用户可以在实况窗通知展示的任何时间点对某一实况窗通知进行删除,删除后,该实况窗通知的更新将不再展示。
- 通过Push Kit创建实况窗当前仅支持FLIGHT、TAXI、TRAIN场景。
1.5 使用入门
按照如下流程完成实况窗的开发工作。
开发步骤 | 说明 |
---|---|
依据实况窗设计规范设计实况窗通知样式 | 依据样式模板设计实况窗通知范本。 |
在AppGallery Connect中申请实况窗权限。 | |
根据实况窗设计规范完成本地实况窗的开发。 | |
通过Push Kit完成实况窗的创建。 | |
通过Push Kit完成实况窗的更新。 |
2 开通推送服务权益
在开通实况窗权益前,需要首先为项目开通“推送服务”权益,详情请参见开通推送服务。
- 若仅需在本地更新实况窗,请直接开通实况窗权益。
- 若要通过Push Kit更新实况窗,或使用Push Token添加白名单设备调试实况窗,还需在项目中配置Client ID。
3 设置数据处理位置
若要通过Push Kit更新实况窗,需要设置默认数据处理位置为“中国”。
在“项目设置 > 数据处理位置”页面设置数据处理位置,设置步骤如下:
- 登录AppGallery Connect,选择“我的项目”。
- 在项目列表中点击您需要设置数据处理位置的项目。
- 进入“项目设置 > 数据处理位置”页面,点击“管理”。
- 在“是否已启用”栏勾选“中国”,并在“是否设为默认”栏将中国设置为默认数据处理位置。
- 设置完成后,点击“保存”。
说明
如果设置的数据处理位置与服务器位置不一致,或者设置的数据处理位置与应用所服务的用户所在地不一致,都会导致推送消息无法下发。
4 开通实况窗权益
说明
申请邮件示例
邮件主题:【开通实况窗权益】- 应用名称
邮件正文:
申请权限名称:开通实况窗权益
企业名称:***
应用名称:***
应用包名:com.***.***(请在包名后标注是测试用或是商用,可同时提供测试包名与正式商用包名,避免多次申请)
Client ID:*** (与包名对应,可在AppGallery Connect网站中,找到您的项目,通过“增长 > 推送服务 > 配置”选择您本次申请的应用,提供对应的Client ID)
是否为HarmonyOS原生应用:(是/否)
场景类型:即时配送
场景描述:***是外卖点单平台,提供外卖下单功能,希望通过实况窗,实现帮助用户快速查看和即时处理订单消息的功能。
接入方案:(将初步的接入实况窗方案图示随邮件一并提供以供充分评估。方案图示截图可置于正文提供,避免使用超大附件或共享链接方式)
4.1 接入联调测试
- 登录AppGallery Connect网站,点击“我的项目”,在项目列表中找到您的项目,通过“增长 > 推送服务 > 配置”导航到“配置”页签。
- (可选)选择应用,点击实况窗-白名单设备管理,根据Push Token添加白名单设备后即可提前进行接入调试。
4.2 申请实况窗正式权限
- 可点击开通实况窗权限,进入实况窗介绍页面,点击“立即开通”。
- 若应用月活数大于等于1000且为已上架应用,点击“立即开通”后进入正式权限申请页面。单次最多申请3个场景,同个应用最多申请8个场景。勾选申请的场景。
注意
- 若应用月活数小于1000,点击开通后会直接开通实况窗通知测试权限,调试权限有效期为60天。到期之前可以点击“申请延期”将有效期延长60天。
- 测试权限仅供调测场景,若面向用户发布使用的场景,可通过页面“申请正式权限”按钮申请权限。详情见下图。
- 按要求填写场景的描述信息、场景接入方案和备注信息后提交申请,等待审批结果即可。可参见实况窗权益申请填写要求进行申请。
4.2.1 实况窗权益申请填写要求
场景描述
需包含:接入场景的描述、消息的展示时机基本说明、展示的主要节点。您填写的内容将用于客服答疑等场景,请尽可能详细地描述。
示例:
- 以打车场景接入为例,场景描述可按照如下字段描述提交
- 接入场景:用户打车后,通过实况窗通知展示接驾进展、行程进展等信息
- 展示时机:用户提交即时出行订单后,或预约订单开始前30分钟
- 展示节点:呼叫司机、司机赶来、司机到达上车点、前往目的地、到达目的地-待支付、到达目的地-已支付
注意
若应用内支持使用其他应用的小程序,需明确说明本次申请的场景使用范围是否涉及到其他应用的小程序。若涉及,您需确保不会出现同一个任务多端推送实况窗的体验,在提交申请时需在附件中一并附上如下内容:
- 与小程序客户端的沟通对齐证明。需双方明确客户端对您应用内其小程序产生的任务的处理方式,如客户端不会对在您应用内其小程序产生的任务进行实况窗通知等。
- 策略变更预案。若小程序客户端策略发生变更,针对继续保持上述体验的应对策略预案。
沟通证明和预案需按场景和小程序一对一制定。后续在该场景下若涉及新增其他小程序,需线下提交针对新增小程序的沟通对齐证明和对应预案。
接入方案
请将应用已验收通过的接入方案现网效果截图(含每个状态节点的卡片、胶囊、锁屏效果、展示时机说明)、主要特殊场景方案效果放在同一张图片中,图片大小需控制在3M内。
示例:
实况窗接入方案请需满足《实况窗设计规范》中的要求,您可按照模板进行设计。
申请前自验
应用在申请实况窗权限时,需对应用当前实况窗的效果和体验进行自检验收,并在申请时将自检项结果通过备注说明,如某项内容已完成自检,可在“[ ]”中打√
- [ ]确认上传的截图满足实况窗设计规范要求。
- [ ]每个创建的实况窗活动均已添加结束事件。
- [ ]确认实况窗与应用内任务进度与信息一致。
- [ ]确认同一实时任务不存在多个实况窗。
- [ ]确认已考虑并提供主要特殊场景的方案。
- [ ]已经完成实况窗场景测试,满足上线要求。
- [ ]认可实况窗的管理规范,若出现不符合设计规范或者违背场景准入要求,同意华为对相关场景[场景名称]权限进行收回。
注意
开通正式权益涉及方案评审与测试验收,方案评审阶段通过后,须开发者配合测试验收(如提供验收方式和验收版本)。整个流程周期约15个工作日,请您留意AppGallery Connect平台申请结果或邮箱。
5 构建本地实况窗
5.1 导入liveViewManager
在项目中导入liveViewManager,并新建实况窗控制类(例如LiveViewController),构造isLiveViewEnabled()方法,用于校验实况窗开关(设置>应用和元服务>应用名>实况窗)是否打开。打开实况窗开关是创建实况窗的前提条件。示例代码如下:
import { liveViewManager } from '@kit.LiveViewKit';
export class LiveViewController {
private static async isLiveViewEnabled(): Promise<boolean> {
return await liveViewManager.isLiveViewEnabled();
}
}
5.2 创建实况窗
实况窗根据扩展区不同共有5种样式模板:进度可视化模板、强调文本模板、左右文本模板、赛事比分模板和导航模板。
调用liveViewManager.startLiveView创建实况窗,该API接口传入参数为实况窗实例(liveViewManager.LiveView)。
5.2.1 进度可视化模板
进度可视化模板适用于打车、外卖等场景。
示例代码如下:
构建LiveViewController后,请在代码中初始化LiveViewController并调用LiveViewController.startLiveView()方法。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!await 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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
5.2.2 强调文本模板
强调文本模板适用于取餐、排队等场景。
示例代码如下:
构建LiveViewController后,请在代码中初始化LiveViewController并调用LiveViewController.startLiveView()方法。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!await 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"
}
}
}
};
}
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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
5.2.3 左右文本模板
左右文本模板适用于高铁、航班等场景。
示例代码如下:
构建LiveViewController后,请在代码中初始化LiveViewController并调用LiveViewController.startLiveView()方法。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!await 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: "以上信息仅供参考" // 扩展区底部内容,仅可用于左右文本模板。
}
}
}
};
}
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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
5.2.4 赛事比分模板
赛事比分模板适用于赛事场景。
示例代码如下:
构建LiveViewController后,请在代码中初始化LiveViewController并调用LiveViewController.startLiveView()方法。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!await 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
}
}
}
};
}
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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
5.2.5 导航模板
导航模板适用于出行导航场景。
示例代码如下:
构建LiveViewController后,请在代码中初始化LiveViewController并调用LiveViewController.startLiveView()方法。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!await 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"]
}
}
}
};
}
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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
5.2.6 实况胶囊
除了实况窗卡片形态,还需考虑实况窗胶囊形态的展示效果。若创建实况窗时还想同步创建实况窗胶囊,则需在liveViewManager.LiveView(结构体)中携带胶囊所需的参数liveViewData.capsule(不同胶囊类型携带不同的参数)。
示例代码如下:
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!await 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: "TAXI", // 实况窗的应用场景。TAXI:出行打车。
liveViewData: {
primary: {
title: "司机预计5分钟后到达",
content: [
{ text: "白", textColor: "#FF000000" },
{ text: "●" },
{ text: "沪AXXXXXX", textColor: "#FF000000" }
],
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS,
progress: 30,
color: "#ff0959F8",
backgroundColor: "#ffc9d7e4",
indicatorType: liveViewManager.IndicatorType.INDICATOR_TYPE_UP,
indicatorIcon: "indicator.png", // 进度条指示器图标,取值为“/resources/rawfile”路径下的文件名
lineType: liveViewManager.LineType.LINE_TYPE_NORMAL_SOLID_LINE,
nodeIcons: ["icon_1.png", "icon_2.png", "icon_3.png"] // 进度条每个节点图标,取值为“/resources/rawfile”路径下的文件名
}
},
// 实况胶囊相关参数
capsule: {
type: liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT,
status: 1,
icon: "capsule_store.png", // 胶囊图标,取值为“/resources/rawfile”路径下的文件名
backgroundColor: "#ff0959F8",
title: "5分钟"
}
}
};
}
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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
5.2.7 实况窗计时器
实况窗计时器适用于排队、抢票等场景。
若需要使用实况窗计时器,则需在liveViewManager.LiveView(结构体)中的配置timer字段,并在当前支持的字段中使用占位符:${placeholder.timer}。
例如:固定区的文本内容中使用占位符,系统将替代占位符为实况窗计时器。
示例代码如下:
构建LiveViewController后,请在代码中初始化LiveViewController并调用LiveViewController.startLiveView()方法。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!await 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”路径下的文件名
}
}
}
};
}
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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
5.2.8 点击实况窗动作
请调用wantAgent.getWantAgent()构造点击动作字段所需的参数值,当前实况窗支持的点击动作如下:
- 点击实况窗的默认动作:在liveViewManager.LiveView(结构体)中携带胶囊所需的参数liveViewData.primary.clickAction字段。
- 点击辅助区的跳转动作:在liveViewManager.LiveView(结构体)中携带胶囊所需的参数liveViewData.primary.extensionData.clickAction字段。
5.3 本地更新和结束实况窗
调用liveViewManager.isLiveViewEnabled()确认实况窗开关打开后,调用liveViewManager的updateLiveView更新实况窗,调用stopLiveView结束实况窗。更新时需要修改请求体中对应的参数。示例代码如下:
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 (!await 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 (!await 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 (!await 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: "..."
}
}
};
}
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
],
actionType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
6 通过Push Kit更新实况窗
6.1场景介绍
本地实况窗的更新依赖于应用进程的存活,为了让实况窗在生命周期内正常完成更新和结束,我们更推荐使用Push Kit实时更新实况窗状态。
通过Push Kit更新实况窗的流程如下图:
- 使用Push Kit,获取Push Token。
- 使用Live View Kit创建实况窗成功后,开发者需要将实况窗id、pushToken、实况窗场景event以及业务服务的相关的状态属性保存到业务服务端。
- 当业务服务的用户订单状态发生变化时,通过Push Kit通道推送更新消息,更新/结束实况窗。