跳转到内容

推送(SuperSDK.push namespace)

设备推送桥接能力 · H5 通过 SuperSDK.push.* 调用。Android 需宿主集成可选模块 supersdk-push-firebase 并实现 SuperSDKProvider.getPushService()(接入见 Android 接入文档「推送」节与 SUPERPUSH.md);iOS 当前为明确的「不支持」stub(四个方法 reject UNSUPPORTED)。

SDK 只负责登记设备、把前台消息 / 点击交回 H5、上报打开;发送、受众筛选在控制台「消息推送」完成。所有接口在浏览器 / 宿主未接线 / iOS 三种环境下都给明确结果而不是报错(见下表),业务代码可以无条件调用。

环境getStatus()其余三个方法
Android · 宿主已接线真实状态(supported: true)正常执行
Android · 宿主未接线(getPushService() 为 null){ supported: false }reject UNSUPPORTED(Native NOT_IMPLEMENTED 经注册表归一 · retryable: false)
iOS(stub){ supported: false }reject UNSUPPORTED
纯浏览器(无 window.appbridge){ supported: false }reject NOT_SUPPORTED(不抛同步异常)
Native 过旧(无推送 JSB)reject SDK_TOO_OLDreject SDK_TOO_OLD

获取推送状态快照。

const status = await SuperSDK.push.getStatus();
// {
// supported: true,
// permission: 'granted', // 'granted' | 'denied' | 'prompt'
// registered: true, // 存在上一次成功登记且其后无错误
// lastError: 'NETWORK_ERROR', // 可选 · 最近一次登记失败原因(成功后清空)
// lastOpened: { // 可选 · 一次性字段,见下方说明
// messageId: 'pm_0123456789ab',
// url: 'https://example.com/promo',
// clickType: 'open_url', // 'open_app' | 'open_url'
// openedAt: 1760000000000,
// verified: true
// }
// }

返回值: Promise<PushStatus>

字段类型说明
supportedbooleanfalse 时其余字段省略(浏览器 / 未接线 / iOS)
permission'granted' | 'denied' | 'prompt'通知对用户是否可见。denied 同时覆盖「权限被拒」和「系统通知开关关闭」;prompt = Android 13+ 尚未询问过
registeredboolean派生值:存在上一次成功登记的指纹且其后无错误。setTags 之后、新登记成功之前的瞬态仍为 true;任何登记失败(含 24h 刷新失败)翻为 false
lastErrorstring闭集 TOKEN_UNAVAILABLE / NOT_FOUND / INVALID_REQUEST / RATE_LIMITED / NETWORK_ERROR / UNAVAILABLE;闭集外的服务端 code 已在 Native 归一为 UNAVAILABLE。登记成功后省略
lastOpenedobject最近一次尚未被读取的推送点击,字段同 push.opened 载荷;无未读点击时省略

🔴 lastOpened 是一次性字段:由首个读到它的 getStatus() 调用消费(任何 WebView 的任何一次调用,含轮询),之后不再返回。它解决的是「点击通知冷启动 App 时页面还没加载、push.opened 事件没人接」这一种场景。多 WebView 下只有一个页面能读到;已经通过 push.opened 收到事件的页面再调 getStatus() 仍可能读到同一条 —— 请用 push.opened 事件 + lastOpened 两者兜底、按 messageId 去重,并且不要在轮询里调用 getStatus()(会把别的页面该拿到的点击抢先消费掉)。

申请通知权限。Android 13+ 弹系统权限框(每台设备只会真正弹一次,之后由系统决定);Android 12 及以下不弹框,直接返回真实可达性。

const { permission } = await SuperSDK.push.requestPermission();
if (permission !== 'granted') {
// 引导用户去系统设置开启通知
}

返回值: Promise<{ permission: 'granted' | 'denied' | 'prompt' }>

交互类方法,H5 侧回调超时 120000ms(等用户操作系统弹框)。无可用前台 Activity(如后台调用)时 reject UNAVAILABLE(retryable: true),稍后在前台重试即可。权限结果变化会触发 SDK 重新登记(控制台设备 enabled 随之更新)。

设置设备标签,用于控制台按标签筛选受众。值变化时 SDK 自动重新登记;相同值不重复请求。

await SuperSDK.push.setTags(['vip', 'zh-CN']);
await SuperSDK.push.setTags([]); // 清空(登记体显式带 tags: [])
await SuperSDK.push.setTags(null); // 同上
参数类型说明
tagsstring[] | null≤10 个,每个 ≤32 字符(按 Unicode 码点计),不含控制字符;SDK 会 trim / 去空 / 去重 / 保序。null 与 [] 等价

返回值: Promise<void>

边界规则由 Native 单源判定:越界 reject INVALID_ARGUMENT(err.nativeCode === 'INVALID_PARAM',err.detail 为原因)且不发请求、不落地。JSSDK 本地只拦「不是字符串数组」这类类型错误。

设置业务用户 ID,用于控制台按用户定向。值变化时 SDK 自动重新登记;登出时传 null 或 '' 清除。

await SuperSDK.push.setUserId('u_123456');
await SuperSDK.push.setUserId(null); // 登出:清除(登记体显式带 user_id: null)
参数类型说明
userIdstring | null≤128 字符(按 Unicode 码点计),不含控制字符;null / '' = 清除

返回值: Promise<void>

🔴 userId 与 tags 只是推送定向的匿名标识,不是身份认证:它们由 H5 自报、不经任何校验,服务端也不会据此信任设备身份。不要把它当作登录态,不要在推送内容里放仅凭 userId 就能看到的敏感信息。

监听 App 在前台时收到的推送(走既有 BROADCAST 通道,事件 key push.message;SuperSDK.subscribe('push.message', cb) 等价)。后台 / 被杀态由系统直接展示通知,不经此回调。

const unsubscribe = SuperSDK.push.onMessage((message) => {
// {
// messageId: 'pm_0123456789ab',
// title: '标题', body: '正文', imageUrl: 'https://…' | null,
// url: 'https://example.com/promo' | null,
// clickType: 'open_url', // 'open_app' | 'open_url'
// data: { message_id: '…', url: '…', ... } // FCM data 原键透传
// }
});
unsubscribe(); // 页面销毁前取消

返回值: 取消监听的函数。

监听推送点击(事件 key push.opened)。点击系统通知或前台通知 → SDK 校验并回执 → 投递此事件 → 拉起 App(clickType === 'open_url' 且宿主未接管时由 SDK 打开 url)。

const unsubscribe = SuperSDK.push.onOpened((opened) => {
// {
// messageId: 'pm_0123456789ab',
// url: 'https://example.com/promo', // 可选 · clickType=open_url 时存在
// clickType: 'open_url',
// openedAt: 1760000000000,
// verified: true
// }
});
字段说明
verifiedtrue = url / clickType 来自服务端回执(权威值);false = 点击时服务端不可达(离线 / 超时)的降级路径:url 为通知 intent 原值、未经服务端核验,SDK 此时只拉起 App、不自动打开 url。业务若要自行据 url 跳转,先检查 verified

返回值: 取消监听的函数。

🔴 事件只投递给事件发生时已存活且已订阅的 WebView(既有 BROADCAST 语义,无监听者时直接丢弃、不缓存)。点击通知冷启动 App 时页面尚未加载,必须在页面加载后用 getStatus().lastOpened 主动取一次 —— 两条路径按 messageId 去重即可覆盖全部场景。

错误(端内 · Error,带 code / nativeCode / retryable / detail):

err.code触发条件retryable
NOT_SUPPORTED纯浏览器(无 appbridge)-
UNSUPPORTED宿主未接线(Native NOT_IMPLEMENTED)/ iOS stub✗
SDK_TOO_OLDNative 没有推送 JSB✗
INVALID_ARGUMENT参数类型错误(本地)或越界(Native INVALID_PARAM)✗
UNAVAILABLErequestPermission 无前台 Activity(Native NO_ACTIVITY)✓
TIMEOUT回调超时(requestPermission 120s · 其余 15s)✓