跳到内容

原生应用内模板语法

原生应用内消息由 SDK 直接渲染。不涉及 WebView。ZIP 资源不包含 index.html 页面,而是携带一个 native-config.json 文件,该文件将消息描述为结构化数据(布局类型、文本、颜色、图像、按钮)。SDK 读取此文件并绘制匹配的原生视图,与嵌入式网页相比,这能提供更流畅的动画和更好的性能。

本指南记录了 native-config.json 的模式:字段、类型以及每种显示类型的示例。关于经典的基于 HTML 的格式,请参阅富媒体模板语法

先决条件

Anchor link to

原生应用内消息需要:

  • iOS: SDK 7.2.0 或更高版本(横幅、轮播和底部弹窗需要 7.2.1+)
  • Android: SDK 6.10.0 或更高版本(横幅、轮播和底部弹窗需要 6.10.1+)

并非所有显示类型都已在两个平台上可用。在依赖特定格式之前,请检查平台支持

平台支持

Anchor link to
显示类型
iOS
Android
modal✅ 7.2.0+✅ 6.10.0+
fullscreen✅ 7.2.0+✅ 6.10.0+
stories✅ 7.2.0+✅ 6.10.0+
banner✅ 7.2.1+✅ 6.10.1+
carousel✅ 7.2.1+✅ 6.10.1+
sheet✅ 7.2.1+✅ 6.10.1+
video尚不可用
pip尚不可用
scratchcard尚不可用
spinwheel尚不可用

模板结构

Anchor link to

原生应用内模板是一个 ZIP 压缩包,与常规的富媒体模板相同,只是根目录包含一个 native-config.json 文件,而不是 index.html

<template>.zip
├── native-config.json ← 必需,布局和内容
├── pushwoosh.json ← 可选,本地化(见下文)

native-config.json 中引用的图像和视频(pip/video 上的 imageposterfallbackurl)必须是绝对的 HTTPS URL。SDK 通过网络加载它们,不从压缩包中读取本地文件。

配置本身是一个单一的 JSON 对象:

{ "displayType": "<type>", "<type>": { /* 此类型的内容块 */ } }

displayType 选择以下十种格式之一。匹配键下的对象持有该格式的内容。如果配置的 displayType 未知、缺少内容块或必需的列表为空(carousel/storiesitemsspinwheelsegments),则该配置无效。SDK 会跳过显示它,而不是渲染一个损坏的布局。

投放设置(开始/结束日期和频率上限)属于 native-config.json 的一部分。它们的配置方式与任何其他应用内消息相同,在营销活动的显示设置步骤中进行配置。

频率上限还需要在 SDK 端明确选择加入才能对原生应用内消息生效。请参阅 SDK 集成

每个颜色值都是一个 CSS 十六进制字符串:#RGB#RGBA#RRGGBB#RRGGBBAA。所有四种形式都必须以 # 开头。

共享构建块

Anchor link to

这些较小的对象在多种显示类型中被重用。

字段类型必需描述
textstring文本内容
colorstring文本颜色
{ "text": "Spin for a garage perk", "color": "#FFFFFFFF" }
字段类型必需描述
colorstring边框颜色
radiusnumber圆角半径,单位为点
{ "color": "#0E72E5FF", "radius": 12 }

背景颜色上的可选图像。由 fullscreenscratchcard 使用。

字段类型必需描述
imagestring封面图片 URL
backgroundstring在图片下方(或替代图片)显示的背景颜色
{ "image": "https://example.com/cover.jpg", "background": "#1A1A1EFF" }

一个基于 type 的可辨识联合体:

变体字段描述
{ "type": "close" }关闭应用内消息
{ "type": "url", "url": string }url 必需打开一个 URL 或深层链接
{ "type": "url", "url": "pushwoosh://sale" }
字段类型必需描述
textText按钮标签
backgroundstring按钮填充颜色
borderBorder按钮边框
actionAction点击时触发的动作

spinButton (spinwheel) 和 revealButton (scratchcard) 使用相同的形状,但没有 action。它们的行为(旋转轮盘,揭开卡片)是内置的。

{
"text": { "text": "Book a test drive", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}

scratchcardspinwheel 显示的奖励面板。一个有效的奖励必须有 titlecode

字段类型必需描述
titleText奖励标题
messageText奖励描述
codestring优惠码,会带有一个复制按钮进行渲染
buttonButton带有自身动作的确认按钮
{
"title": { "text": "20% off detailing", "color": "#111111FF" },
"message": { "text": "Valid for any full-detail booking this month.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Book detailing", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}

显示类型

Anchor link to

一个紧凑的条,停靠在屏幕的顶部或底部边缘。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
positiontop | bottom屏幕边缘
backgroundstring条的背景颜色
imagestring左侧的缩略图
titleText单行标题,用省略号截断
messageText正文文本,最多 2 行
actionAction当条本身被点击时触发
autoDismissnumber这么多秒后自动关闭。省略则保持显示直到关闭
{
"displayType": "banner",
"banner": {
"showClose": true,
"position": "bottom",
"background": "#4B5057FF",
"image": "https://example.com/thumb.jpg",
"title": { "text": "Alpine A110 just dropped", "color": "#FFFFFFFF" },
"message": { "text": "The featherweight icon — tap to see the build", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" },
"autoDismiss": 6
}
}

一个全屏、可滑动的卡片集,带有页面指示点。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
itemsItem[]卡片(至少 1 个)

轮播项:

字段类型必需描述
titleText卡片标题
messageText卡片副标题
imagestring卡片图片
actionAction当卡片被点击时触发
{
"displayType": "carousel",
"carousel": {
"showClose": true,
"items": [
{
"image": "https://example.com/card-1.jpg",
"title": { "text": "AMG GT R", "color": "#FFFFFFFF" },
"message": { "text": "585 hp biturbo V8 — just landed", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/n6fx" }
},
{
"image": "https://example.com/card-2.jpg",
"title": { "text": "Alpine A110", "color": "#FFFFFFFF" },
"message": { "text": "Featherweight icon — limited allocation", "color": "#FFFFFFFF" },
"action": { "type": "url", "url": "pushwoosh://product/x6f" }
}
]
}
}

fullscreen

Anchor link to

一个边缘到边缘的封面图片,上面有文本和按钮。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
coverCover背景图片和颜色
titleText标题
messageText正文文本
buttonsButton[]底部的按钮(可以为空)
{
"displayType": "fullscreen",
"fullscreen": {
"showClose": true,
"cover": { "image": "https://example.com/hero.jpg", "background": "#1A1A1EFF" },
"title": { "text": "Pure Maranello", "color": "#FFFFFFFF" },
"message": { "text": "The prancing horse, reimagined.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Reserve now", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 8 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Not now", "color": "#FFFFFFFF" },
"background": "#00000000",
"border": { "color": "#FFFFFF99", "radius": 8 },
"action": { "type": "close" }
}
]
}
}

一个居中的卡片。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
dimBackgroundboolean使卡片后面的屏幕变暗
backgroundstring卡片背景颜色
imagestring封面图片
titleText标题
messageText正文文本
buttonsButton[]文本下方的按钮(可以为空)
{
"displayType": "modal",
"modal": {
"showClose": true,
"dimBackground": true,
"background": "#FFFFFFFF",
"image": "https://example.com/cover.jpg",
"title": { "text": "The GT R has landed", "color": "#4B5057FF" },
"message": { "text": "585 hp — now in the showroom.", "color": "#4B5057FF" },
"buttons": [
{
"text": { "text": "Book a test drive", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
},
{
"text": { "text": "Not now", "color": "#4B5057FF" },
"background": "#FFFFFFFF",
"border": { "color": "#4B5057FF", "radius": 12 },
"action": { "type": "close" }
}
]
}
}

一个浮动的画中画视频窗口,停靠在屏幕一角。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
positionbottom-right | bottom-left | top-right | top-left屏幕角落
loopboolean循环播放
mutedboolean开始时静音
urlstring视频 URL
posterstring播放开始前显示的海报
fallbackstring视频播放失败时显示的图片
widthnumber窗口宽度占屏幕宽度的百分比,限制在 15–70 之间
aspectRationumber窗口高宽比
borderRadiusnumber窗口圆角半径,单位为点
actionAction当窗口本身被点击时触发

pip 上没有可配置的按钮。窗口控件(展开到全屏、静音、关闭)由系统提供。

{
"displayType": "pip",
"pip": {
"showClose": true,
"position": "bottom-right",
"loop": true,
"muted": true,
"url": "https://example.com/teaser.mp4",
"poster": "https://example.com/poster.jpg",
"width": 40,
"aspectRatio": 0.5625,
"action": { "type": "url", "url": "pushwoosh://product/x6f" }
}
}

scratchcard

Anchor link to

一张卡片,奖励隐藏在可刮开的箔层下。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
backgroundstring | string[]卡片背景颜色,或渐变色标
revealThresholdnumber必须刮掉的箔层比例 (0–1),之后奖励才会显示
coverCover箔层。如果没有 image,则在背景颜色上显示“在此刮开”的提示
revealButtonButton (无 action)“立即揭晓”按钮
titleText标题
messageText正文文本
rewardReward隐藏在箔层下的奖品
{
"displayType": "scratchcard",
"scratchcard": {
"showClose": true,
"background": ["#3A1C71FF", "#B3227CFF", "#E0503AFF"],
"revealThreshold": 0.55,
"cover": { "background": "#C9CDD6FF" },
"revealButton": {
"text": { "text": "Reveal without scratching", "color": "#3A1C71FF" },
"background": "#F2DFF5FF",
"border": { "color": "#F2DFF5FF", "radius": 10 }
},
"title": { "text": "Your loyalty reward", "color": "#FFFFFFFF" },
"message": { "text": "Scratch the foil to reveal this week's garage perk.", "color": "#F2DFF5FF" },
"reward": {
"title": { "text": "20% off detailing", "color": "#111111FF" },
"message": { "text": "Valid for any full-detail booking this month.", "color": "#555555FF" },
"code": "APEX20",
"button": {
"text": { "text": "Book detailing", "color": "#FFFFFFFF" },
"background": "#B3227CFF",
"border": { "color": "#B3227CFF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://detailing" }
}
}
}
}

一张固定在底部边缘的卡片,带有一个拖动手柄。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
dimBackgroundboolean使底部弹窗后面的屏幕变暗
backgroundstring底部弹窗背景颜色
imagestring封面图片
titleText标题
messageText正文文本
buttonsButton[]文本下方的按钮(可以为空)
{
"displayType": "sheet",
"sheet": {
"showClose": true,
"dimBackground": true,
"background": "#FFFFFFFF",
"image": "https://example.com/cover.jpg",
"title": { "text": "Your quote is ready", "color": "#000000FF" },
"message": { "text": "Guaranteed buyout for your A110: $68,500.", "color": "#000000FF" },
"buttons": [
{
"text": { "text": "Get guaranteed quote", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

一个带有加权扇区和中心枢纽按钮的幸运转盘。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
backgroundstring | string[]卡片背景颜色,或渐变色标
winIndexnumber获胜扇区的索引(从 0 开始)
spinButtonButton (无 action)中心枢纽按钮
titleText标题
messageText正文文本
rewardReward获胜旋转的奖励(作为没有自身奖励的扇区的备用)
loseTitleText失败时显示的标题
segmentsSegment[]轮盘扇区(SDK 期望 2–12 个)

扇区:

字段类型必需描述
messageText扇区标签
colorstring扇区颜色。省略则使用围绕轮盘应用的备用调色板
weightnumber相对扇区大小
rewardReward特定扇区的奖励
{
"displayType": "spinwheel",
"spinwheel": {
"showClose": true,
"background": ["#1B1B46FF", "#5B2B8FFF", "#B0338AFF"],
"winIndex": 1,
"spinButton": {
"text": { "text": "SPIN", "color": "#1B1B46FF" },
"background": "#F2C94CFF",
"border": { "color": "#D9A02BFF", "radius": 36 }
},
"title": { "text": "Spin for a garage perk", "color": "#FFFFFFFF" },
"message": { "text": "One spin — every slice wins this week.", "color": "#E3D9F2FF" },
"reward": {
"title": { "text": "You won a garage perk!", "color": "#FFFFFFFF" },
"code": "APEXPERK",
"button": {
"text": { "text": "Claim", "color": "#FFFFFFFF" },
"background": "#5B2B8FFF",
"border": { "color": "#5B2B8FFF", "radius": 12 },
"action": { "type": "close" }
}
},
"segments": [
{ "message": { "text": "5% off", "color": "#FFFFFFFF" }, "color": "#5856D6FF", "weight": 1 },
{
"message": { "text": "20% off", "color": "#FFFFFFFF" },
"color": "#30B0C7FF",
"weight": 1,
"reward": {
"title": { "text": "20% off your next service", "color": "#FFFFFFFF" },
"code": "SPIN20",
"button": {
"text": { "text": "Claim service deal", "color": "#FFFFFFFF" },
"background": "#30B0C7FF",
"border": { "color": "#30B0C7FF", "radius": 12 },
"action": { "type": "url", "url": "pushwoosh://service" }
}
}
},
{ "message": { "text": "Free wash", "color": "#FFFFFFFF" }, "color": "#FF2D55FF", "weight": 1 }
]
}
}

全屏幻灯片,顶部有进度条,类似于社交媒体故事。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
loopboolean在最后一张幻灯片后从第一张重新开始
itemsItem[]幻灯片(至少 1 张)

故事项:

字段类型必需描述
titleText标题
messageText副标题
imagestring幻灯片背景图片
buttonsButton[]底部的 CTA 按钮(可以为空)
durationnumber幻灯片持续时间,单位为秒
{
"displayType": "stories",
"stories": {
"showClose": true,
"loop": false,
"items": [
{
"image": "https://example.com/slide-1.jpg",
"title": { "text": "AMG GT R", "color": "#FFFFFFFF" },
"message": { "text": "The Green Hell special", "color": "#FFFFFFFF" },
"buttons": [
{
"text": { "text": "Configure yours", "color": "#FFFFFFFF" },
"background": "#0F0F0FFF",
"border": { "color": "#0F0F0FFF", "radius": 26 },
"action": { "type": "url", "url": "pushwoosh://product/n6fx" }
}
],
"duration": 4
},
{
"image": "https://example.com/slide-2.jpg",
"title": { "text": "Alpine A110", "color": "#FFFFFFFF" },
"message": { "text": "The featherweight legend, reborn", "color": "#FFFFFFFF" },
"buttons": [],
"duration": 4
}
]
}
}

全屏视频,上面有文本和按钮。

字段类型必需描述
showCloseboolean显示一个关闭 (✕) 按钮
loopboolean循环播放
mutedboolean开始时静音
urlstring视频 URL (HLS 或 MP4)
posterstring播放开始前显示的海报
fallbackstring视频播放失败时显示的图片
titleText标题
messageText正文文本
buttonsButton[]底部的 CTA 按钮(可以为空)
{
"displayType": "video",
"video": {
"showClose": true,
"loop": true,
"muted": true,
"url": "https://example.com/reveal.mp4",
"poster": "https://example.com/poster.jpg",
"title": { "text": "The reveal", "color": "#FFFFFFFF" },
"message": { "text": "Watch it move before anyone else.", "color": "#EBEBEBFF" },
"buttons": [
{
"text": { "text": "Shop the lineup", "color": "#FFFFFFFF" },
"background": "#0E72E5FF",
"border": { "color": "#0E72E5FF", "radius": 14 },
"action": { "type": "url", "url": "pushwoosh://sale" }
}
]
}
}

原生应用内消息重用与 HTML 富媒体完全相同的本地化机制:native-config.json 中的字符串值可以携带 {{key|type|default}} 占位符,翻译内容存放在旁边的 pushwoosh.json 文件中,格式与添加 pushwoosh.json 中描述的相同。占位符可以出现在任何字符串字段中,任何深度(标题、按钮标签、图片 URL、动作 URL)。

SDK 集成

Anchor link to

一旦您将原生应用内 SDK 模块添加到您的应用中,消息就会自动显示。无需额外代码即可显示由推送、Customer Journey、postEvent 或收件箱触发的消息。

SDK 还公开了一个小型的 API 用于手动控制:

  • iOS: Pushwoosh.inApp (模块 PushwooshInApp)
  • Android: PushwooshInAppUi (模块 pushwoosh-inapp-ui)
功能iOSAndroid
直接显示配置(测试/手动使用)Pushwoosh.inApp.present(config)PushwooshInAppUi.present(configJson)
观察生命周期和点击delegate (PWInAppMessageDelegate)delegate (InAppMessageDelegate)
检查屏幕上是否有内容isPresentingisPresenting
关闭当前显示的任何内容dismiss()dismiss()
暂停/恢复显示isPausedisPaused
强制执行 maxDisplays / cooldown 上限setFrequencyCapEnabled(_:)setFrequencyCapEnabled(...)

委托回调(都在主线程上触发):shouldDisplay(返回 false 以在消息显示前抑制它,例如在结账屏幕上)、willPresentdidPresentdidCloseclickedAction(当用户点击 url 动作时,在 URL 打开前触发)。

iOS 还会为游戏化的 scratchcardspinwheel 模板报告 rewardRevealedrewardClaimed

// iOS
Pushwoosh.inApp.delegate = self
Pushwoosh.inApp.setFrequencyCapEnabled(true)
// Android
PushwooshInAppUi.delegate = this
PushwooshInAppUi.setFrequencyCapEnabled(true)