HarmonyOS 实况窗推送指南

准备工作

在开始使用鸿蒙实况窗功能之前,您需要完成以下准备工作:

  1. 已参考HarmonyOS SDK接入完成SDK的接入,并注册鸿蒙PushToken。

  2. 已参考实况窗设计规范依据样式模板设计您的实况窗通知范本。

  3. 已参考开发准备AppGallery Connect中申请实况窗权限。

快速开始

完成准备工作后,您可以通过下面的示例来快速创建一个打车实况窗:

PushRequest pushRequest = new PushRequest();
// 基础参数
pushRequest.setAppKey(appKey);
pushRequest.setPushType("NOTICE");
pushRequest.setDeviceType("HARMONY");
pushRequest.setTarget(target);
pushRequest.setTargetValue(targetValue);
pushRequest.setHarmonyTestMessage(true);

// 设置远程创建实况窗的参数
String startLiveViewPayload = """
{
  "activityId": 1,
  "operation": 0,
  "event": "TAXI",
  "status": "DRIVER_ON_THE_WAY",
  "activityData": {
    "notificationData": {
      "type": 3,       
      "contentTitle": "{{status}}",
      "contentText": [
        {
          "text": "距您"
        },
        {
          "text": "1.2公里",
          "foregroundColor": "#FF317AF7"
        },
        {
          "text": " | "
        },
        {
          "text": "5分钟",
          "foregroundColor": "#FF317AF7"
        }
      ],
      "clickAction": {
        "actionType": 1,
        "action": "xxxxxx"
      },
      "richProgress": {
        "type": 0,
        "nodeIcons": ["icon1.png", "icon2.png", "icon3.png"],
        "indicatorIcon": "taxi.png",
        "progress": 40,
        "indicatorType": 1,
        "color": "#FF317AF7",
        "bgColor": "#19000000"
      },
      "extend": {
        "type": 3,
        "pic": "phone.png",
        "clickAction": {
          "actionType": 0
        }
      }
    },
    "capsuleData": {
      "type": 1,
      "status": 1,
      "icon": "icon.svg",
      "bgColor": "#FF317AF7",
      "remind": "EXPAND",
      "title": "接驾中",
      "content": "预计5分钟"
    }
  }
}
""";
pushRequest.setHarmonyLiveViewPayload(startLiveViewPayload);

// 发送推送
PushResponse pushResponse = client.getAcsResponse(pushRequest);
System.out.printf("RequestId: %s, MessageId: %s\n", 
    pushResponse.getRequestId(), pushResponse.getMessageId());

客户端显示如下:

screenshot_20250924_111450screenshot_20250924_111500

核心概念

鸿蒙实况窗(Live View)是HarmonyOS NEXT系统提供的一种新型通知形态,能够帮助用户聚焦正在进行的任务,方便快速查看和即时处理。移动推送现已支持鸿蒙实况窗的创建、更新和结束操作,为开发者提供便捷的实况窗管理能力。

什么是实况窗

实况窗是一种具有时段性、时效性、变化性特点的通知形态,支持在锁屏、通知中心、状态栏等位置展示,主要有胶囊态和卡片态两种展示形式。

imageimageimageimage

核心特点

  • 时段性:事件或服务需要持续一段时间,有明确的开始和结束。

  • 时效性:内容为正在进行或即时发生的事件,在特定时间段内对用户有价值。

  • 变化性:展示的内容需要动态更新,确保用户看到最新状态。

提醒方式

实况窗能够在锁屏、通知中心等位置显示卡片。除此之外,还支持:

  1. 在状态栏显示胶囊状态,以及在状态栏点击胶囊后展开悬浮卡片。

  2. 在锁屏显示胶囊状态和卡片态,以及长按或点击卡片头图进入锁屏沉浸态。

多种显示方式能够将信息即时触达到用户,避免用户反复进出应用或服务的页面。在不同的显示位置中,通知中心顶部会显示全量实况窗,其他显示位置则根据用户的设置及业务的重要程度进行呈现。各种显示方式的详细样式请参考实况窗

  1. 同一个事件活动在不同场景下仅出现一个形态,如当前事件所承载的落地页在前台,则当前无胶囊;如当前为通知中心/锁屏,则不显示状态栏胶囊。

  2. 通知中心的实况卡片会默认显示在顶部,需避免滥用对用户造成打扰。

image

基础交互

image

点击单个胶囊,呼出悬浮卡片,胶囊消失;点击卡片空白处,进入对应详情页。

image

进入沉浸态:锁屏后默认进入;点击锁屏卡片态头图;点击锁屏胶囊态。

退出沉浸态:侧边back手势退出,返回至展开前状态;下拉收起至胶囊态;上滑进入锁屏卡片态。

实况窗支持的场景类型

场景类型

EVENT取值

场景描述

适用范围

出行打车

TAXI

用户线上约车后,向用户展示司机接驾等待时间、行程中的剩余距离和时间等信息。

适用于网约车、出租车、拼车、顺风车等场景。

即时配送

DELIVERY

指配送员将餐品、商品送达到用户指定地点的业务场景,通常在较短时间内完成配送环节。

适用于外卖、生鲜配送、同城配送等场景。

航班

FLIGHT

用户主动关注某个航班时,向用户展示航班的关键变动,如航班开始登机、航班起飞、航班延误、航班取消、航班到达等关键场景。

适用于用户通过航班出行或者主动关注某个航班进展的场景。

高铁/火车

TRAIN

用户通过高铁、火车出行,向用户展示检票口、座位号、车次信息及列车运行状态等信息。

适用于高铁出行、火车出行的场景。

排队

QUEUE

需要通过排队叫号的方式,按顺序为用户提供服务的业务场景。

适用于办事大厅、医院、银行、餐饮等排队叫号能力场景。

取餐

PICK_UP

指的是用户完成餐品/商品下单后,自行取餐或者取件的场景。

适用于餐饮线下取餐提醒,包括餐品排队情况、制作进度、取餐提醒等。

赛事比分

SCORE

展示比赛双方成绩变化情况。

适用于游戏赛事、体育赛事等展示比分变化情况的场景。

共享租赁

RENT

用户使用临时租赁服务时,向用户展示实时租赁时长和费用等租赁状态信息的场景。

适用于共享单车、共享充电宝、停车场临时停车等场景。

计时

TIMER

用户在某个短时间段持续的正计时或任务前的倒计时场景。

适用于专注时刻、番茄时钟、抢票倒计时提醒场景,仅限于工具类应用申请。

运动锻炼

WORKOUT

运动过程中,向用户实时展示运动的时长和进度等信息。

适用于户外或室内的运动记录,如跑步、骑行等。

导航

NAVIGATION

用户使用导航服务时,展示将要发生的路线变化。

适用于步行导航、骑行导航、车辆导航。

实况窗的三种操作类型对于各场景的限制如下:

实况窗消息操作类型

说明

创建实况窗

航班(FLIGHT)出行打车(TAXI)高铁/火车(TRAIN)三种场景支持通过移动推送接口远程创建实况窗,其他场景请通过鸿蒙Live View Kit本地创建。

更新实况窗

所有场景皆支持通过移动推送接口远程更新实况窗。

结束实况窗

所有场景皆支持通过移动推送接口远程结束实况窗。

实况窗样式模板

实况窗的卡片态支持固定区、辅助区、扩展区三个板块,其中固定区为必选,辅助区和扩展区为可选。

image

进度可视化模板

进度可视化模板适用于打车、外卖等场景。

image

强调文本模板

强调文本模板适用于取餐、排队等场景。

image

左右文本模板

左右文本模板适用于高铁、航班等场景。

image

赛事比分模板

赛事比分模板适用于赛事场景。

image

导航模板

导航模板适用于出行导航场景。

image

说明

导航模板仅能通过鸿蒙Live View Kit本地操作,无法通过移动推送接口远程操作。

通过鸿蒙Live View Kit本地创建/更新/结束实况窗

应用进程活跃时,可以通过鸿蒙Live View KitliveViewManager在客户端本地操作实况窗,其中startLiveView/updateLiveView/stopLiveView分别为创建/更新/结束实况窗的方法。具体各模板的代码请参考构建本地实况窗,实况窗的数据结构请参考liveViewManager.LiveView

通过移动推送接口远程创建/更新/结束实况窗

移动推送支持通过Push接口或MassPush接口远程创建/更新/结束实况窗,其中创建只支持航班(FLIGHT)出行打车(TAXI)高铁/火车(TRAIN)三种场景,更新与结束无场景限制。

参数设置

调用接口时注意以下关键参数:

  • PushType: 推送实况窗时固定设置为 NOTICE

  • HarmonyTestMessage: 测试消息设置为 true,正式消息设置为false

  • HarmonyLiveViewPayload: 实况窗数据结构LiveViewPayloadJSON字符串,其中operation在创建/更新/结束时分别设置为0/1/2

LiveViewPayload的结构如下表所示:

参数

是否必选

参数类型

描述

activityId

Integer

实况窗唯一标识,取值范围为[-2147483648, 2147483647],由开发者自行生成。对应Live View Kit中的id字段。

重要

若发送的activityId对应的实况窗不存在(更新或结束实况窗的场景中),将限制使用该activityId发送实况窗消息24小时。

operation

Integer

实况窗消息操作类型:

  • 0:表示创建实况窗消息,仅允许event值为FLIGHT、TAXI、TRAIN,详情见创建实况窗约束

  • 1:表示更新实况窗消息(确保activityId对应的实况窗存在)

  • 2:表示结束实况窗消息(确保activityId对应的实况窗存在)

更新和结束实况窗时,对于非必选字段,若无特殊说明和默认值,则不携带时默认继承上一次的状态。

event

String

业务场景取值,必须为以下内容之一:

  • TAXI:出行打车

  • DELIVERY:即时配送(外卖、生鲜)

  • FLIGHT:航班

  • TRAIN:高铁/火车

  • QUEUE:排队

  • PICK_UP:取餐

  • SCORE:赛事比分

  • RENT:共享租赁

  • TIMER:计时

  • WORKOUT:运动锻炼

  • NAVIGATION:导航

使用对应场景需要申请权益,详情请参见实况窗权益申请填写要求

重要

当创建实况窗消息(operation取值为0)时,event取值仅允许为FLIGHT、TAXI、TRAIN。

status

String

表示实况窗消息状态。

operation0,或operation1且更新的实况窗为通过移动推送远程创建的实况窗时必填。

status的取值范围根据场景类型而定,详情见Status取值范围

消息体中占位符{{status}}的使用,参见支持携带占位符的字段,满足要求时将替换字段中的占位符为目标值

title

String

可选,当系统不支持实况窗通知时,展示在通知栏的标题。

content

String

可选,当系统不支持实况窗通知时,展示在通知栏的内容。

mute

Boolean

标识消息更新是否需要提醒。

  • true:静默提醒(默认值)

  • false:铃声震动提醒

version

Integer

更新实况窗通知的版本号,大于等于0,新的实况窗通知版本号需大于当前实况窗通知版本号,否则会刷新失败。

activityData

ActivityData Object

实况窗通知详细数据,具体字段请参见ActivityData结构体。

示例代码

远程创建实况窗

PushRequest pushRequest = new PushRequest();
// 基础参数
pushRequest.setAppKey(appKey);
pushRequest.setPushType("NOTICE");
pushRequest.setDeviceType("HARMONY");
pushRequest.setTarget(target);
pushRequest.setTargetValue(targetValue);
pushRequest.setHarmonyTestMessage(true);

// 设置远程创建实况窗的参数
String startLiveViewPayload = """
{
  "activityId": 1,
  "operation": 0,
  "event": "TAXI",
  "status": "DRIVER_ON_THE_WAY",
  "activityData": {
    "notificationData": {
      "type": 3,       
      "contentTitle": "{{status}}",
      "contentText": [
        {
          "text": "距您"
        },
        {
          "text": "1.2公里",
          "foregroundColor": "#FF317AF7"
        },
        {
          "text": " | "
        },
        {
          "text": "5分钟",
          "foregroundColor": "#FF317AF7"
        }
      ],
      "clickAction": {
        "actionType": 1,
        "action": "xxxxxx"
      },
      "richProgress": {
        "type": 0,
        "nodeIcons": ["icon1.png", "icon2.png", "icon3.png"],
        "indicatorIcon": "taxi.png",
        "progress": 40,
        "indicatorType": 1,
        "color": "#FF317AF7",
        "bgColor": "#19000000"
      },
      "extend": {
        "type": 3,
        "pic": "phone.png",
        "clickAction": {
          "actionType": 0
        }
      }
    },
    "capsuleData": {
      "type": 1,
      "status": 1,
      "icon": "icon.svg",
      "bgColor": "#FF317AF7",
      "remind": "EXPAND",
      "title": "接驾中",
      "content": "预计5分钟"
    }
  }
}
""";
pushRequest.setHarmonyLiveViewPayload(startLiveViewPayload);

// 发送推送
PushResponse pushResponse = client.getAcsResponse(pushRequest);
System.out.printf("RequestId: %s, MessageId: %s\n", 
    pushResponse.getRequestId(), pushResponse.getMessageId());

远程更新实况窗

PushRequest pushRequest = new PushRequest();
// 基础参数
pushRequest.setAppKey(appKey);
pushRequest.setPushType("NOTICE");
pushRequest.setDeviceType("HARMONY");
pushRequest.setTarget(target);
pushRequest.setTargetValue(targetValue);
pushRequest.setHarmonyTestMessage(true);

// 设置远程更新实况窗的参数
String updateLiveViewPayload = """
{
  "activityId": 1,
  "operation": 1,
  "event": "TAXI",
  "status": "DRIVER_ARRIVE",
  "activityData": {
    "notificationData": {
      "type": 3,       
      "contentTitle": "{{status}}",
      "contentText": [
        {
          "text": "距您"
        },
        {
          "text": "0.5公里",
          "foregroundColor": "#FF317AF7"
        },
        {
          "text": " | "
        },
        {
          "text": "2分钟",
          "foregroundColor": "#FF317AF7"
        }
      ],
      "clickAction": {
        "actionType": 1,
        "action": "xxxxxx"
      },
      "richProgress": {
        "type": 0,
        "nodeIcons": ["icon1.png", "icon2.png", "icon3.png"],
        "indicatorIcon": "taxi.png",
        "progress": 40,
        "indicatorType": 1,
        "color": "#FF317AF7",
        "bgColor": "#19000000"
      },
      "extend": {
        "type": 3,
        "pic": "phone.png",
        "clickAction": {
          "actionType": 0
        }
      }
    },
    "capsuleData": {
      "type": 1,
      "status": 1,
      "icon": "icon.svg",
      "bgColor": "#FF317AF7",
      "remind": "EXPAND",
      "title": "司机已到达上车点",
      "content": "预计2分钟"
    }
  }
}
""";
pushRequest.setHarmonyLiveViewPayload(updateLiveViewPayload);

// 发送推送
PushResponse pushResponse = client.getAcsResponse(pushRequest);
System.out.printf("RequestId: %s, MessageId: %s\n", 
    pushResponse.getRequestId(), pushResponse.getMessageId());

远程结束实况窗

PushRequest pushRequest = new PushRequest();
// 基础参数
pushRequest.setAppKey(appKey);
pushRequest.setPushType("NOTICE");
pushRequest.setDeviceType("HARMONY");
pushRequest.setTarget(target);
pushRequest.setTargetValue(targetValue);
pushRequest.setHarmonyTestMessage(true);

// 设置远程结束实况窗的参数
String stopLiveViewPayload = """
{
  "activityId": 1,
  "operation": 2,
  "event": "TAXI",
  "status": "DRIVER_ARRIVE",
  "activityData": {
    "notificationData": {
      "type": 3,       
      "contentTitle": "{{status}}",
      "contentText": [
        {
          "text": "距您"
        },
        {
          "text": "0.5公里",
          "foregroundColor": "#FF317AF7"
        },
        {
          "text": " | "
        },
        {
          "text": "2分钟",
          "foregroundColor": "#FF317AF7"
        }
      ],
      "clickAction": {
        "actionType": 1,
        "action": "xxxxxx"
      },
      "richProgress": {
        "type": 0,
        "nodeIcons": ["icon1.png", "icon2.png", "icon3.png"],
        "indicatorIcon": "taxi.png",
        "progress": 40,
        "indicatorType": 1,
        "color": "#FF317AF7",
        "bgColor": "#19000000"
      },
      "extend": {
        "type": 3,
        "pic": "phone.png",
        "clickAction": {
          "actionType": 0
        }
      }
    },
    "capsuleData": {
      "type": 1,
      "status": 1,
      "icon": "icon.svg",
      "bgColor": "#FF317AF7",
      "remind": "EXPAND",
      "title": "司机已到达上车点",
      "content": "预计2分钟"
    }
  }
}
""";
pushRequest.setHarmonyLiveViewPayload(stopLiveViewPayload);

// 发送推送
PushResponse pushResponse = client.getAcsResponse(pushRequest);
System.out.printf("RequestId: %s, MessageId: %s\n", 
    pushResponse.getRequestId(), pushResponse.getMessageId());

实况窗限制

生命周期限制

  • 单个实况窗最长生命周期不超过8小时,超过8小时后系统会认为实况窗结束。

  • 超过2小时未更新会隐藏状态栏胶囊和锁屏展示,保留通知中心展示。

  • 超过4小时未更新,系统会认为实况窗结束,并从各个展示入口清除该实况窗。

  • 用户可以在实况窗通知展示的任何时间点对某一实况窗通知进行删除,删除后,该实况窗通知的更新将不再展示。

频率限制

测试阶段:

  • 每个项目每日最多推送1000条测试消息,推送测试消息需要设置HarmonyTestMessagetrue

正式阶段:

  • 单设备单应用下每日推送消息总条数受设备消息频控限制,所有场景化消息发送条数不超过3000条。

  • 单个实况窗消息,出行打车与赛事比分场景每个设备每5分钟最多更新30次,每小时最多更新180次。其余场景每个设备每5分钟最多更新10次,每小时最多更新60次。超过频次部分将丢弃不下发。

远程创建实况窗限制

  • 通过移动推送远程创建实况窗仅支持FLIGHT、TAXI、TRAIN三种场景。

  • 12小时内不允许通过移动推送远程对一台设备创建同一个activityId的实况窗。

  • 对于不同的event类型,创建实况窗时,对布局类型(activityData.notificationData.type)和必填字段,有以下场景约束:

event

创建时允许的布局类型

创建时必填字段

REST API创建的消息,更新时必填字段

FLIGHT

左右文本模板类型

status activityData.notificationData.keywords

status

TAXI

进度可视化类型

强调文本模板类型

左右文本模板类型

赛事类型

status

status

TRAIN

左右文本模板类型

status activityData.notificationData.keywords

status

  • 对于不同的布局类型(activityData.notificationData.type),需要在支持携带占位符的字段中填入至少一次status的占位符{{status}};如果该eventkeywords字段也必填,则也需要在支持携带占位符的字段中填入至少一次相应的占位符,占位符具体请参见keywords字段描述。

  • 通过移动推送远程创建的实况窗,在更新时必须同时满足statuskeywords要求。通过Live View Kit(实况窗服务)创建的实况窗,在移动推送远程更新时可以不填写statuskeywords字段,若开发者选择填写则需满足statuskeywords要求。

问题排查

创建实况窗失败

  1. 检查是否已在AppGallery Connect中申请对应场景实况窗权限。

  2. 检查设备是否支持实况窗,可参考构建本地实况窗调用liveViewManager.isLiveViewEnabled()方法检查。

  3. 检查是否触发频率限制

  4. 对于使用移动推送远程创建的实况窗,检查是否触发远程创建实况窗限制

  5. 根据消息ID与设备ID在移动推送控制台的排查工具->排查消息页面检查实况窗推送链路。

更新/结束实况窗失败

  1. 检查HarmonyLiveViewPayload参数中的activityId是否与创建实况窗时的相同。

  2. 检查HarmonyLiveViewPayload参数中的version是否正确设置。

  3. 检查是否触发频率限制

  4. 根据消息ID与设备ID在移动推送控制台的排查工具->排查消息页面检查实况窗推送链路。

实况窗样式异常

  1. 检查HarmonyLiveViewPayload参数中的type是否匹配对应模板。

  2. 检查资源文件路径是否正确