import {
|
resolveCurrentAppUserId
|
} from './app-user.js'
|
|
const PUSH_ALIAS_CACHE_KEY = 'jpushBoundAlias'
|
let lastHandledPushMessageId = ''
|
|
/**
|
* 读取当前设备上的极光插件实例。
|
*/
|
function getJPushModule() {
|
// #ifdef APP-PLUS
|
try {
|
return uni.requireNativePlugin('JG-JPush')
|
} catch (error) {
|
return null
|
}
|
// #endif
|
// #ifndef APP-PLUS
|
return null
|
// #endif
|
}
|
|
/**
|
* 将当前登录用户 ID 归一化为极光 alias。
|
*/
|
function resolveCurrentPushAlias() {
|
const userId = resolveCurrentAppUserId()
|
if (!userId) {
|
return ''
|
}
|
return String(userId)
|
}
|
|
/**
|
* 绑定当前登录用户到极光 alias,便于服务端按用户 ID 精准推送。
|
*/
|
export function syncJPushAliasWithCurrentUser() {
|
const alias = resolveCurrentPushAlias()
|
if (!alias) {
|
return false
|
}
|
const jpushModule = getJPushModule()
|
if (!jpushModule || typeof jpushModule.setAlias !== 'function') {
|
return false
|
}
|
const sequence = Date.now()
|
const invoked = tryInvoke(() => jpushModule.setAlias({
|
sequence,
|
alias
|
})) || tryInvoke(() => jpushModule.setAlias({
|
sequence: String(sequence),
|
alias
|
})) || tryInvoke(() => jpushModule.setAlias(alias)) || tryInvoke(() => jpushModule.setAlias(alias, sequence))
|
if (invoked) {
|
uni.setStorageSync(PUSH_ALIAS_CACHE_KEY, alias)
|
}
|
return invoked
|
}
|
|
/**
|
* 退出登录后清理本地 alias 缓存,并尽量解除极光别名。
|
*/
|
export function clearJPushAliasBinding() {
|
uni.removeStorageSync(PUSH_ALIAS_CACHE_KEY)
|
const jpushModule = getJPushModule()
|
if (!jpushModule) {
|
return false
|
}
|
const sequence = Date.now()
|
return tryInvoke(() => {
|
if (typeof jpushModule.deleteAlias === 'function') {
|
jpushModule.deleteAlias({
|
sequence
|
})
|
return
|
}
|
if (typeof jpushModule.setAlias === 'function') {
|
jpushModule.setAlias({
|
sequence,
|
alias: ''
|
})
|
}
|
})
|
}
|
|
/**
|
* 初始化极光推送,并在连接成功后补一次 alias 同步。
|
*/
|
export function initJPushLifecycle() {
|
const jpushModule = getJPushModule()
|
if (!jpushModule) {
|
return null
|
}
|
if (typeof jpushModule.setLoggerEnable === 'function') {
|
jpushModule.setLoggerEnable(false)
|
}
|
if (typeof jpushModule.initJPushService === 'function') {
|
jpushModule.initJPushService()
|
}
|
if (typeof jpushModule.addConnectEventListener === 'function') {
|
jpushModule.addConnectEventListener((result) => {
|
const connectEnable = !!(result && result.connectEnable)
|
if (!connectEnable) {
|
return
|
}
|
syncJPushAliasWithCurrentUser()
|
})
|
}
|
if (typeof jpushModule.addNotificationListener === 'function') {
|
jpushModule.addNotificationListener((result) => {
|
handleJPushNotification(result)
|
})
|
}
|
return jpushModule
|
}
|
|
/**
|
* 安全执行插件调用,避免因参数签名差异直接中断业务。
|
*/
|
function tryInvoke(executor) {
|
try {
|
executor()
|
return true
|
} catch (error) {
|
return false
|
}
|
}
|
|
/**
|
* 根据极光通知内容决定是否执行页面跳转。
|
*/
|
function handleJPushNotification(result) {
|
const notificationEventType = normalizeOptionalText(result?.notificationEventType)
|
const messageId = normalizeOptionalText(result?.messageID || result?.messageId || result?.android?.msgId)
|
const extras = resolveJPushExtras(result)
|
const targetUrl = resolvePushTargetUrl(extras)
|
if (!targetUrl) {
|
return
|
}
|
if (!shouldHandlePushNavigation(notificationEventType, messageId)) {
|
return
|
}
|
navigateByPush(targetUrl)
|
}
|
|
/**
|
* 从极光回调中提取扩展参数,优先读取已解析 extras,缺失时兜底解析 Android 原始 JSON。
|
*/
|
function resolveJPushExtras(result) {
|
const extras = result?.extras
|
if (extras && typeof extras === 'object') {
|
return extras
|
}
|
const notificationExtras = normalizeOptionalText(result?.android?.notificationExtras)
|
if (!notificationExtras) {
|
return {}
|
}
|
try {
|
const parsedExtras = JSON.parse(notificationExtras)
|
return parsedExtras && typeof parsedExtras === 'object' ? parsedExtras : {}
|
} catch (error) {
|
return {}
|
}
|
}
|
|
/**
|
* 将推送类型映射到应用内页面。
|
*/
|
function resolvePushTargetUrl(extras) {
|
const noticeTypeCode = normalizeOptionalText(extras?.noticeTypeCode)
|
switch (noticeTypeCode) {
|
case 'MEMBER_EXPIRE_REMIND':
|
return '/pages/vip/vip'
|
case 'LIVE_REMIND':
|
return resolveLiveRemindTargetUrl(extras)
|
case 'ACTIVITY_NOTICE':
|
return resolveActivityNoticeTargetUrl(extras)
|
case 'ORDER_STATUS_UPDATE':
|
return resolveOrderStatusUpdateTargetUrl(extras)
|
case 'HEALTH_COURSE_VIDEO':
|
return resolveHealthCourseVideoTargetUrl(extras)
|
default:
|
return ''
|
}
|
}
|
|
/**
|
* 解析直播提醒跳转地址,直播详情页当前读取的是 id 参数。
|
*/
|
function resolveLiveRemindTargetUrl(extras) {
|
const courseId = normalizeOptionalText(extras?.courseId)
|
if (!courseId) {
|
return ''
|
}
|
return `/pages/liveDetail/liveDetail?id=${encodeURIComponent(courseId)}`
|
}
|
|
/**
|
* 解析活动通知跳转地址,活动详情页当前读取的是 id 参数。
|
*/
|
function resolveActivityNoticeTargetUrl(extras) {
|
const activityNoticeId = normalizeOptionalText(extras?.activityNoticeId)
|
if (!activityNoticeId) {
|
return ''
|
}
|
return `/pages/activityNotice/activityNoticeDetail?id=${encodeURIComponent(activityNoticeId)}`
|
}
|
|
/**
|
* 解析兑换订单状态变更跳转地址,明细页当前读取的是 orderId 参数。
|
*/
|
function resolveOrderStatusUpdateTargetUrl(extras) {
|
const orderId = normalizeOptionalText(extras?.orderId)
|
if (!orderId) {
|
return ''
|
}
|
return `/pages/myPatientExchangeItems/myPatientExchangeItems?orderId=${encodeURIComponent(orderId)}`
|
}
|
|
/**
|
* 解析养生课程视频更新跳转地址,课程详情页当前读取的是 id 参数。
|
*/
|
function resolveHealthCourseVideoTargetUrl(extras) {
|
const courseId = normalizeOptionalText(extras?.courseId)
|
if (!courseId) {
|
return ''
|
}
|
return `/pages/courseDetail/courseDetail?id=${encodeURIComponent(courseId)}`
|
}
|
|
/**
|
* 仅在点击通知或首次收到未处理通知时执行跳转,避免重复打开相同页面。
|
*/
|
function shouldHandlePushNavigation(notificationEventType, messageId) {
|
const normalizedEventType = normalizeOptionalText(notificationEventType)
|
const canNavigate = normalizedEventType === 'notificationOpened' ||
|
normalizedEventType === 'notificationClicked' ||
|
normalizedEventType === 'notificationArrived'
|
if (!canNavigate) {
|
return false
|
}
|
if (messageId && messageId === lastHandledPushMessageId) {
|
return false
|
}
|
lastHandledPushMessageId = messageId
|
return true
|
}
|
|
/**
|
* 根据页面栈状态执行推送跳转,避免在当前页重复打开。
|
*/
|
function navigateByPush(targetUrl) {
|
const currentPages = getCurrentPages()
|
const currentRoute = currentPages && currentPages.length > 0 ? currentPages[currentPages.length - 1].route || '' :
|
''
|
const normalizedTargetRoute = targetUrl.replace(/^\//, '').split('?')[0]
|
if (currentRoute === normalizedTargetRoute) {
|
return
|
}
|
uni.navigateTo({
|
url: targetUrl,
|
fail: () => {
|
uni.reLaunch({
|
url: targetUrl
|
})
|
}
|
})
|
}
|
|
/**
|
* 将未知值归一化为可安全使用的文本。
|
*/
|
function normalizeOptionalText(value) {
|
if (typeof value !== 'string') {
|
return ''
|
}
|
return value.trim()
|
}
|