/** * iOS 远程推送消息封装(原生插件:NetworkUtils-NetworkUtilsModule) * 对应原生方法:onPushNotificationAsync、consumePendingPushNotificationsAsync */ // #ifdef APP-PLUS const pushNetworkModule = uni.requireNativePlugin('NetworkUtils-NetworkUtilsModule') // #endif let lastPushNotification = null const processedPushKeys = {} function getPushDedupeKey(title, content) { return `${title || ''}|${content || ''}` } function markPushProcessed(title, content) { const key = getPushDedupeKey(title, content) processedPushKeys[key] = true return key } function isPushProcessed(title, content) { return !!processedPushKeys[getPushDedupeKey(title, content)] } function dispatchPushMessage(onMessage, payload, meta = {}) { if (!meta.userTapped && isPushProcessed(payload.title, payload.content)) { console.log('[Push] skip duplicate push:', getPushDedupeKey(payload.title, payload.content)) return } markPushProcessed(payload.title, payload.content) lastPushNotification = payload if (typeof onMessage === 'function') { onMessage(payload, meta) } } function parseUserTappedFlag(value) { return value === true || value === 1 || value === '1' || value === 'true' } function getPushConfirmNo(res = {}) { const confirmNo = res.ConfirmNo || res.confirmNo || res.confNo || res.raw?.ConfirmNo || res.raw?.confirmNo || res.raw?.confNo return confirmNo ? String(confirmNo) : '' } /** * 将原生回调数据规范化为 { title, content, body, confirmNo, userTapped, raw } * @param {Record} res */ export function normalizePushPayload(res = {}) { const title = typeof res.title === 'string' ? res.title : (res.title ? String(res.title) : '') const body = typeof res.body === 'string' ? res.body : (res.body ? String(res.body) : '') const confirmNo = getPushConfirmNo(res) return { title, content: body, body, confirmNo, userTapped: parseUserTappedFlag(res.userTapped), raw: res } } /** * 获取最近一次收到的推送(内存缓存) */ export function getLastPushNotification() { return lastPushNotification } /** * 读取并清空 Native 侧缓存的待处理推送(后台/冷启动场景) * @returns {Promise>} */ export function consumePendingPushNotifications() { return new Promise((resolve) => { // #ifdef APP-PLUS if (!pushNetworkModule) { console.error('[Push] NetworkUtils 原生插件不可用') resolve([]) return } if (typeof pushNetworkModule.consumePendingPushNotificationsAsync !== 'function') { console.warn('[Push] 原生暂不支持 consumePendingPushNotificationsAsync,跳过 Native pending 同步') resolve([]) return } console.log('[Push] 调用 consumePendingPushNotificationsAsync ...') pushNetworkModule.consumePendingPushNotificationsAsync({}, (ret) => { const items = Array.isArray(ret?.items) ? ret.items : [] console.log('[Push] consumePendingPushNotificationsAsync 返回 count=', ret?.count ?? items.length) resolve(items.map((item) => normalizePushPayload(item))) }) // #endif // #ifndef APP-PLUS resolve([]) // #endif }) } /** * 同步处理 Native 缓存的推送 * @param {(payload: { title: string, content: string, body: string, raw: object }, meta?: object) => void} onMessage * @param {{ showToast?: boolean }} [options] */ export async function syncPendingPushNotifications(onMessage, options = {}) { console.log('[Push] syncPendingPushNotifications start') const pending = await consumePendingPushNotifications() if (!pending.length) { console.log('[Push] syncPendingPushNotifications: 队列为空') return pending } console.log('[Push] syncPendingPushNotifications count=', pending.length) for (const payload of pending) { dispatchPushMessage(onMessage, payload, { fromPending: true, userTapped: payload.userTapped === true, showToast: options.showToast !== false }) } return pending } /** * 注册推送消息监听;每次收到远程推送时 callback 会被调用 * @param {(payload: { title: string, content: string, body: string, raw: object }, meta?: object) => void} onMessage * @returns {() => void} */ export function listenPushNotification(onMessage) { // #ifdef APP-PLUS if (!pushNetworkModule || typeof pushNetworkModule.onPushNotificationAsync !== 'function') { console.warn('[Push] NetworkUtils 原生插件不可用或未注册 onPushNotificationAsync') return () => {} } pushNetworkModule.onPushNotificationAsync({}, (res) => { const payload = normalizePushPayload(res) console.log('[Push] 收到推送通知:', JSON.stringify(payload)) dispatchPushMessage(onMessage, payload, { fromPending: !!res?.fromPending, userTapped: payload.userTapped === true, showToast: true }) }) return () => {} // #endif // #ifndef APP-PLUS console.warn('[Push] 非 App-PLUS 环境,跳过推送监听') return () => {} // #endif }