feat(push): 添加推送服务功能支持
- 新增推送相关的类型定义,包括消息类型、聊天类型、推送配置等接口 - 实现 HarmonyOS 推送 SDK,集成 HarmonyOS NEXT Push Kit 服务 - 实现 iOS 推送 SDK,支持 APNS 推送注册和消息接收 - 添加服务器端 APNS 推送提供商,支持 JWT 认证和推送消息发送 - 添加服务器端 HarmonyOS 推送提供商基础框架 - 集成推送配置加载和路由功能,支持多渠道推送分类管理
这个提交包含在:
父节点
60171ed90c
当前提交
6c11380a36
2
.hvigor/cache/file-cache.json
vendored
2
.hvigor/cache/file-cache.json
vendored
文件差异因一行或多行过长而隐藏
2
.hvigor/cache/task-cache.json
vendored
2
.hvigor/cache/task-cache.json
vendored
文件差异因一行或多行过长而隐藏
@ -32,20 +32,20 @@
|
||||
"IS_HVIGORFILE_TYPE_CHECK": false,
|
||||
"TASK_TIME": {
|
||||
"923fe53966c6cd9343e11af776cd4b05be315ea4b200b02e4d5dfb0f929b73bf": {
|
||||
"CreateModuleInfo": 299292,
|
||||
"PreCheckSyscap": 126000,
|
||||
"ProcessIntegratedHsp": 331000,
|
||||
"SyscapTransform": 7137708,
|
||||
"ProcessStartupConfig": 783208,
|
||||
"ConfigureCmake": 53875,
|
||||
"BuildNativeWithCmake": 53292,
|
||||
"BuildNativeWithNinja": 121458,
|
||||
"BuildJS": 653333
|
||||
"CreateModuleInfo": 293166,
|
||||
"PreCheckSyscap": 112917,
|
||||
"ProcessIntegratedHsp": 261375,
|
||||
"SyscapTransform": 11097875,
|
||||
"ProcessStartupConfig": 704125,
|
||||
"ConfigureCmake": 54750,
|
||||
"BuildNativeWithCmake": 55208,
|
||||
"BuildNativeWithNinja": 126708,
|
||||
"BuildJS": 622708
|
||||
},
|
||||
"77aabe6c19463543339f337db9c84e4d10fd2f56ea0aedaf85a0214d59e93ec4": {
|
||||
"ConfigureCmake": 76458,
|
||||
"BuildNativeWithCmake": 126167,
|
||||
"BuildNativeWithNinja": 223750
|
||||
"ConfigureCmake": 67416,
|
||||
"BuildNativeWithCmake": 116292,
|
||||
"BuildNativeWithNinja": 239792
|
||||
}
|
||||
},
|
||||
"APIS": [
|
||||
@ -56,157 +56,157 @@
|
||||
"ENABLE_CPP_FUNCTION_LEVEL_INCREMENTAL": false
|
||||
},
|
||||
"CONFIG_PROPERTIES": {},
|
||||
"BUILD_ID": "202605051732210700",
|
||||
"BUILD_ID": "202605052221561580",
|
||||
"ERROR_MESSAGE": [
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605040",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605040",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605008",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605008",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605008",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605008",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605008",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605040",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10605038",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10505001",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
},
|
||||
{
|
||||
"CODE": "10505001",
|
||||
"TIMESTAMP": "1777973544163"
|
||||
"TIMESTAMP": "1777990919564"
|
||||
}
|
||||
],
|
||||
"TOTAL_TIME": 3094060000
|
||||
"TOTAL_TIME": 3406688333
|
||||
}
|
||||
}
|
||||
@ -176,3 +176,30 @@ export interface PushTokenInfo {
|
||||
token: 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 { HttpClient } from '../core/HttpClient'
|
||||
import { SDKContext } from '../core/SDKContext'
|
||||
import type { PushNotificationRouteConfig, PushServiceConfig, SdkConfigData } from '../core/Types'
|
||||
|
||||
const HARMONY_PUSH_VENDOR = 'HARMONY'
|
||||
const HARMONY_PLATFORM = 'HARMONY'
|
||||
@ -13,6 +14,9 @@ class PushRegisterBody {
|
||||
}
|
||||
|
||||
export class PushSDK {
|
||||
private static pushConfig: PushServiceConfig | null = null
|
||||
private static configLoadedAt: number = 0
|
||||
|
||||
async initPush(imUserId?: string): Promise<void> {
|
||||
await PushSDK.initPush(imUserId)
|
||||
}
|
||||
@ -37,6 +41,7 @@ export class PushSDK {
|
||||
*/
|
||||
static async initPush(imUserId?: string): Promise<void> {
|
||||
try {
|
||||
await PushSDK.applyTenantConfiguration()
|
||||
const token: string = await pushService.getToken()
|
||||
if (token && token.length > 0) {
|
||||
await PushSDK.registerToken(token, imUserId)
|
||||
@ -60,6 +65,7 @@ export class PushSDK {
|
||||
*/
|
||||
static async registerToken(token: string, imUserId?: string): Promise<void> {
|
||||
const config = SDKContext.getConfig()
|
||||
await PushSDK.applyTenantConfiguration()
|
||||
const userId = imUserId ?? SDKContext.getUserId()
|
||||
if (!userId) {
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
const parts: string[] = []
|
||||
for (const item of items) {
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户