feat(push): 添加推送服务功能支持

- 新增推送相关的类型定义,包括消息类型、聊天类型、推送配置等接口
- 实现 HarmonyOS 推送 SDK,集成 HarmonyOS NEXT Push Kit 服务
- 实现 iOS 推送 SDK,支持 APNS 推送注册和消息接收
- 添加服务器端 APNS 推送提供商,支持 JWT 认证和推送消息发送
- 添加服务器端 HarmonyOS 推送提供商基础框架
- 集成推送配置加载和路由功能,支持多渠道推送分类管理
这个提交包含在:
XuqmGroup 2026-05-05 22:26:31 +08:00
父节点 60171ed90c
当前提交 6c11380a36
共有 5 个文件被更改,包括 127 次插入53 次删除

文件差异因一行或多行过长而隐藏

文件差异因一行或多行过长而隐藏

查看文件

@ -32,20 +32,20 @@
"IS_HVIGORFILE_TYPE_CHECK": false, "IS_HVIGORFILE_TYPE_CHECK": false,
"TASK_TIME": { "TASK_TIME": {
"923fe53966c6cd9343e11af776cd4b05be315ea4b200b02e4d5dfb0f929b73bf": { "923fe53966c6cd9343e11af776cd4b05be315ea4b200b02e4d5dfb0f929b73bf": {
"CreateModuleInfo": 299292, "CreateModuleInfo": 293166,
"PreCheckSyscap": 126000, "PreCheckSyscap": 112917,
"ProcessIntegratedHsp": 331000, "ProcessIntegratedHsp": 261375,
"SyscapTransform": 7137708, "SyscapTransform": 11097875,
"ProcessStartupConfig": 783208, "ProcessStartupConfig": 704125,
"ConfigureCmake": 53875, "ConfigureCmake": 54750,
"BuildNativeWithCmake": 53292, "BuildNativeWithCmake": 55208,
"BuildNativeWithNinja": 121458, "BuildNativeWithNinja": 126708,
"BuildJS": 653333 "BuildJS": 622708
}, },
"77aabe6c19463543339f337db9c84e4d10fd2f56ea0aedaf85a0214d59e93ec4": { "77aabe6c19463543339f337db9c84e4d10fd2f56ea0aedaf85a0214d59e93ec4": {
"ConfigureCmake": 76458, "ConfigureCmake": 67416,
"BuildNativeWithCmake": 126167, "BuildNativeWithCmake": 116292,
"BuildNativeWithNinja": 223750 "BuildNativeWithNinja": 239792
} }
}, },
"APIS": [ "APIS": [
@ -56,157 +56,157 @@
"ENABLE_CPP_FUNCTION_LEVEL_INCREMENTAL": false "ENABLE_CPP_FUNCTION_LEVEL_INCREMENTAL": false
}, },
"CONFIG_PROPERTIES": {}, "CONFIG_PROPERTIES": {},
"BUILD_ID": "202605051732210700", "BUILD_ID": "202605052221561580",
"ERROR_MESSAGE": [ "ERROR_MESSAGE": [
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605040", "CODE": "10605040",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605040", "CODE": "10605040",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605008", "CODE": "10605008",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605008", "CODE": "10605008",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605008", "CODE": "10605008",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605008", "CODE": "10605008",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605008", "CODE": "10605008",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605040", "CODE": "10605040",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10605038", "CODE": "10605038",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10505001", "CODE": "10505001",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
}, },
{ {
"CODE": "10505001", "CODE": "10505001",
"TIMESTAMP": "1777973544163" "TIMESTAMP": "1777990919564"
} }
], ],
"TOTAL_TIME": 3094060000 "TOTAL_TIME": 3406688333
} }
} }

查看文件

@ -176,3 +176,30 @@ export interface PushTokenInfo {
token: string token: string
platform: string platform: string
} }
export interface PushNotificationChannelConfig {
key: string
channelId: string
version: number
name: string
description?: string
importance: string
sound: boolean
vibration: boolean
badge: boolean
}
export interface PushNotificationRouteConfig {
channel: string
category: string
priority: string
}
export interface PushServiceConfig {
channels?: PushNotificationChannelConfig[]
routing?: Record<string, PushNotificationRouteConfig>
}
export interface SdkConfigData {
pushConfig?: PushServiceConfig
}

查看文件

@ -1,6 +1,7 @@
import { pushService } from '@kit.PushKit' import { pushService } from '@kit.PushKit'
import { HttpClient } from '../core/HttpClient' import { HttpClient } from '../core/HttpClient'
import { SDKContext } from '../core/SDKContext' import { SDKContext } from '../core/SDKContext'
import type { PushNotificationRouteConfig, PushServiceConfig, SdkConfigData } from '../core/Types'
const HARMONY_PUSH_VENDOR = 'HARMONY' const HARMONY_PUSH_VENDOR = 'HARMONY'
const HARMONY_PLATFORM = 'HARMONY' const HARMONY_PLATFORM = 'HARMONY'
@ -13,6 +14,9 @@ class PushRegisterBody {
} }
export class PushSDK { export class PushSDK {
private static pushConfig: PushServiceConfig | null = null
private static configLoadedAt: number = 0
async initPush(imUserId?: string): Promise<void> { async initPush(imUserId?: string): Promise<void> {
await PushSDK.initPush(imUserId) await PushSDK.initPush(imUserId)
} }
@ -37,6 +41,7 @@ export class PushSDK {
*/ */
static async initPush(imUserId?: string): Promise<void> { static async initPush(imUserId?: string): Promise<void> {
try { try {
await PushSDK.applyTenantConfiguration()
const token: string = await pushService.getToken() const token: string = await pushService.getToken()
if (token && token.length > 0) { if (token && token.length > 0) {
await PushSDK.registerToken(token, imUserId) await PushSDK.registerToken(token, imUserId)
@ -60,6 +65,7 @@ export class PushSDK {
*/ */
static async registerToken(token: string, imUserId?: string): Promise<void> { static async registerToken(token: string, imUserId?: string): Promise<void> {
const config = SDKContext.getConfig() const config = SDKContext.getConfig()
await PushSDK.applyTenantConfiguration()
const userId = imUserId ?? SDKContext.getUserId() const userId = imUserId ?? SDKContext.getUserId()
if (!userId) { if (!userId) {
console.warn('[XuqmSDK] Push registration skipped: IM user id is empty.') console.warn('[XuqmSDK] Push registration skipped: IM user id is empty.')
@ -98,6 +104,47 @@ export class PushSDK {
await HttpClient.delete<void>('/api/push/unregister', query) await HttpClient.delete<void>('/api/push/unregister', query)
} }
static async applyTenantConfiguration(force: boolean = false): Promise<void> {
const now = Date.now()
if (!force && PushSDK.pushConfig && now - PushSDK.configLoadedAt < 5 * 60 * 1000) {
return
}
const config = SDKContext.getConfig()
const query = PushSDK.queryString([
new QueryItem('appId', config.appKey),
new QueryItem('platform', HARMONY_PLATFORM),
])
try {
const data = await HttpClient.get<SdkConfigData>('/api/sdk/config', query)
PushSDK.pushConfig = data?.pushConfig ?? null
PushSDK.configLoadedAt = now
PushSDK.persistRouteChannels()
} catch (err) {
console.warn('[XuqmSDK] Push config load failed:', JSON.stringify(err))
}
}
static routeOptions(routeType: string): PushNotificationRouteConfig | null {
return PushSDK.pushConfig?.routing?.[routeType] ?? null
}
private static persistRouteChannels(): void {
const config = PushSDK.pushConfig
if (!config?.channels || !config.routing) return
const channelByKey: Record<string, string> = {}
for (const channel of config.channels) {
const version = Math.max(channel.version ?? 1, 1)
channelByKey[channel.key] = `${channel.channelId}_v${version}`
}
for (const routeType of Object.keys(config.routing)) {
const route = config.routing[routeType]
const channelId = channelByKey[route.channel] ?? ''
if (channelId.length > 0) {
console.info(`[XuqmSDK] Push route ${routeType} uses channel ${channelId}`)
}
}
}
private static queryString(items: QueryItem[]): string { private static queryString(items: QueryItem[]): string {
const parts: string[] = [] const parts: string[] = []
for (const item of items) { for (const item of items) {