XuqmGroup-RNSDK/packages/push/src/PushSDK.ts

124 行
3.8 KiB
TypeScript

import { apiRequest, getConfig, getDeviceInfo, getUserId as getCommonUserId } from '@xuqm/rn-common'
import type { PushVendor } from '@xuqm/rn-common'
import { detectVendorNative, registerPushNative, addPushTokenListener } from './NativePush'
export type { PushVendor }
type PendingDeviceToken = {
token: string
vendor?: PushVendor
}
let currentUserId: string | null = null
let pendingToken: PendingDeviceToken | null = null
let _tokenUnsubscribe: (() => void) | null = null
async function registerPendingToken(): Promise<void> {
const userId = currentUserId ?? getCommonUserId()
if (!userId || !pendingToken) return
const device = await getDeviceInfo()
const config = getConfig()
await apiRequest('/api/push/register', {
method: 'POST',
params: {
appId: config.appId,
userId,
vendor: pendingToken.vendor ?? device.pushVendor,
token: pendingToken.token,
platform: device.platform,
deviceId: device.deviceId,
brand: device.brand,
model: device.model,
osVersion: device.osVersion,
},
})
}
export const PushSDK = {
async initialize(userId?: string): Promise<void> {
currentUserId = userId ?? getCommonUserId()
await registerPendingToken()
},
async setDeviceToken(token: string, vendor?: PushVendor): Promise<void> {
pendingToken = { token, vendor }
await registerPendingToken()
},
/**
* Auto-detect vendor and request native push registration.
* On Android this attempts to register with the vendor SDK (Huawei, Xiaomi, OPPO, vivo, Honor, FCM).
* On iOS this requests APNs registration.
* Listen for token updates via onPushToken(callback).
*/
async requestNativeRegistration(): Promise<void> {
await registerPushNative()
},
/**
* Listen for push tokens from the native layer.
* Call setDeviceToken(token, vendor) inside the callback to register with the server.
*/
onPushToken(callback: (token: string, vendor: string) => void): () => void {
if (_tokenUnsubscribe) {
_tokenUnsubscribe()
_tokenUnsubscribe = null
}
_tokenUnsubscribe = addPushTokenListener((event) => {
callback(event.token, event.vendor)
})
return () => {
if (_tokenUnsubscribe) {
_tokenUnsubscribe()
_tokenUnsubscribe = null
}
}
},
/**
* Register a push device token for the given user.
* If vendor is omitted, it is auto-detected from the device brand.
*
* @param userId - The logged-in user's ID
* @param token - The device push token from the vendor SDK
* @param vendor - Optional; auto-detected when not provided
*/
async registerToken(userId: string, token: string, vendor?: PushVendor): Promise<void> {
currentUserId = userId
pendingToken = { token, vendor }
const config = getConfig()
const device = await getDeviceInfo()
await apiRequest('/api/push/register', {
method: 'POST',
params: {
appId: config.appId,
userId,
vendor: vendor ?? device.pushVendor,
token,
platform: device.platform,
deviceId: device.deviceId,
brand: device.brand,
model: device.model,
osVersion: device.osVersion,
},
})
},
async unregisterToken(userId: string): Promise<void> {
const config = getConfig()
const { deviceId } = await getDeviceInfo()
await apiRequest('/api/push/unregister', {
method: 'DELETE',
params: { appId: config.appId, userId, deviceId },
})
if (currentUserId === userId) currentUserId = null
if (pendingToken && currentUserId === null) pendingToken = null
},
async logout(userId?: string): Promise<void> {
const targetUserId = userId ?? currentUserId ?? getCommonUserId()
if (!targetUserId) return
await PushSDK.unregisterToken(targetUserId)
},
}