docs(sdk): 添加 Android SDK 文档和 API 设计规范
- 新增 Android SDK 使用文档,包含模块结构、集成方式和快速开始指南 - 添加 SDK API 重设计规范,统一初始化和登录接口设计 - 补充安全设计规范,完善 UserSig 鉴权和敏感数据处理方案 - 创建平台 REST API 规范,定义服务端到服务端的调用接口 - 添加离线推送架构设计,集成各大厂商推送服务与 IM 联动方案
这个提交包含在:
父节点
cac5a39e2b
当前提交
67d54bf1f2
@ -41,9 +41,6 @@ import { XuqmSDK } from '@xuqm/rn-sdk'
|
|||||||
|
|
||||||
await XuqmSDK.init({
|
await XuqmSDK.init({
|
||||||
appKey: 'ak_your_app_key',
|
appKey: 'ak_your_app_key',
|
||||||
appSecret: 'as_your_app_secret',
|
|
||||||
apiBaseUrl: 'https://api.xuqm.com',
|
|
||||||
imBaseUrl: 'wss://im.xuqm.com',
|
|
||||||
debug: __DEV__,
|
debug: __DEV__,
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
export interface XuqmInitOptions {
|
export interface XuqmInitOptions {
|
||||||
appId: string
|
appKey: string
|
||||||
serverUrl: string // e.g. "http://192.168.116.9:8081" — SDK fetches config from here
|
|
||||||
appKey?: string
|
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface XuqmConfig {
|
export interface XuqmConfig {
|
||||||
appId: string
|
appId: string
|
||||||
appKey: string
|
appKey: string
|
||||||
serverUrl: string
|
apiUrl: string
|
||||||
apiBaseUrl: string // im-service base URL
|
imWsUrl: string
|
||||||
imWsUrl: string // fetched from remote config
|
|
||||||
fileServiceUrl: string // fetched from remote config
|
fileServiceUrl: string // fetched from remote config
|
||||||
debug: boolean
|
debug: boolean
|
||||||
}
|
}
|
||||||
@ -20,13 +17,12 @@ let _userId: string | null = null
|
|||||||
|
|
||||||
export function initConfigFromRemote(
|
export function initConfigFromRemote(
|
||||||
options: XuqmInitOptions,
|
options: XuqmInitOptions,
|
||||||
remote: { imWsUrl: string; fileServiceUrl: string; apiBaseUrl: string },
|
remote: { imWsUrl: string; fileServiceUrl: string; apiUrl: string },
|
||||||
): void {
|
): void {
|
||||||
_config = {
|
_config = {
|
||||||
appId: options.appId,
|
appId: options.appKey,
|
||||||
appKey: options.appKey ?? options.appId,
|
appKey: options.appKey,
|
||||||
serverUrl: options.serverUrl,
|
apiUrl: remote.apiUrl,
|
||||||
apiBaseUrl: remote.apiBaseUrl,
|
|
||||||
imWsUrl: remote.imWsUrl,
|
imWsUrl: remote.imWsUrl,
|
||||||
fileServiceUrl: remote.fileServiceUrl,
|
fileServiceUrl: remote.fileServiceUrl,
|
||||||
debug: options.debug ?? false,
|
debug: options.debug ?? false,
|
||||||
|
|||||||
@ -1,12 +1,2 @@
|
|||||||
/**
|
export const DEFAULT_TENANT_PLATFORM_URL = 'https://dev.xuqinmin.com'
|
||||||
* @deprecated These hardcoded URLs are no longer used by the SDK.
|
export const DEFAULT_IM_WS_URL = 'wss://dev.xuqinmin.com/ws/im'
|
||||||
* The SDK now fetches configuration from the tenant platform via
|
|
||||||
* XuqmSDK.initialize(). These constants are kept only as fallback
|
|
||||||
* references and for backward compatibility.
|
|
||||||
*/
|
|
||||||
export const API_BASE_URL = 'http://192.168.116.9:8081'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated See API_BASE_URL.
|
|
||||||
*/
|
|
||||||
export const IM_WS_URL = 'ws://192.168.116.9:8082/ws/im'
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export async function apiRequest<T>(
|
|||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
|
|
||||||
let url = config.apiBaseUrl + path
|
let url = config.apiUrl + path
|
||||||
if (options.params) {
|
if (options.params) {
|
||||||
const qs = new URLSearchParams(options.params).toString()
|
const qs = new URLSearchParams(options.params).toString()
|
||||||
url += (url.includes('?') ? '&' : '?') + qs
|
url += (url.includes('?') ? '&' : '?') + qs
|
||||||
|
|||||||
@ -2,7 +2,7 @@ export { XuqmSDK } from './sdk'
|
|||||||
export type { XuqmInitOptions, XuqmConfig } from './config'
|
export type { XuqmInitOptions, XuqmConfig } from './config'
|
||||||
export { getConfig, isInitialized, setUserId, getUserId } from './config'
|
export { getConfig, isInitialized, setUserId, getUserId } from './config'
|
||||||
export { apiRequest, _getToken, _saveToken, _clearToken } from './http'
|
export { apiRequest, _getToken, _saveToken, _clearToken } from './http'
|
||||||
export { API_BASE_URL, IM_WS_URL } from './constants'
|
export { DEFAULT_TENANT_PLATFORM_URL, DEFAULT_IM_WS_URL } from './constants'
|
||||||
export { getDeviceId, getDeviceInfo, detectPushVendor } from './device'
|
export { getDeviceId, getDeviceInfo, detectPushVendor } from './device'
|
||||||
export type { DeviceInfo, PushVendor } from './device'
|
export type { DeviceInfo, PushVendor } from './device'
|
||||||
export { ScaledImage } from './components/ScaledImage'
|
export { ScaledImage } from './components/ScaledImage'
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
import { initConfigFromRemote, isInitialized, type XuqmInitOptions, setUserId as setCommonUserId, getUserId as getCommonUserId } from './config'
|
import { initConfigFromRemote, isInitialized, type XuqmInitOptions, setUserId as setCommonUserId, getUserId as getCommonUserId } from './config'
|
||||||
|
import { DEFAULT_IM_WS_URL, DEFAULT_TENANT_PLATFORM_URL } from './constants'
|
||||||
|
|
||||||
export const XuqmSDK = {
|
export const XuqmSDK = {
|
||||||
/**
|
/**
|
||||||
* Async initialize — fetches SDK config from the tenant platform.
|
* @param options.appKey - Your application key (from the tenant platform)
|
||||||
* Recommended for production use.
|
|
||||||
*
|
|
||||||
* @param options.appId - Your application ID (from the tenant platform)
|
|
||||||
* @param options.serverUrl - Base URL of the tenant platform, e.g. "http://192.168.116.9:8081"
|
|
||||||
* @param options.appKey - Optional; defaults to appId
|
|
||||||
* @param options.debug - Enable verbose logging
|
* @param options.debug - Enable verbose logging
|
||||||
*/
|
*/
|
||||||
async initialize(options: XuqmInitOptions): Promise<void> {
|
async initialize(options: XuqmInitOptions): Promise<void> {
|
||||||
if (isInitialized()) return
|
if (isInitialized()) return
|
||||||
const configUrl = `${options.serverUrl}/api/sdk/config?appId=${options.appId}`
|
const configUrl = `${DEFAULT_TENANT_PLATFORM_URL}/api/sdk/config?appId=${options.appKey}`
|
||||||
try {
|
try {
|
||||||
const res = await fetch(configUrl)
|
const res = await fetch(configUrl)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
@ -20,34 +16,29 @@ export const XuqmSDK = {
|
|||||||
initConfigFromRemote(options, {
|
initConfigFromRemote(options, {
|
||||||
imWsUrl: remote.imWsUrl,
|
imWsUrl: remote.imWsUrl,
|
||||||
fileServiceUrl: remote.fileServiceUrl,
|
fileServiceUrl: remote.fileServiceUrl,
|
||||||
apiBaseUrl: remote.imApiUrl ?? options.serverUrl,
|
apiUrl: remote.imApiUrl ?? DEFAULT_TENANT_PLATFORM_URL,
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Fallback: construct URLs from serverUrl
|
// Fallback: construct URLs from the built-in platform endpoint
|
||||||
initConfigFromRemote(options, {
|
initConfigFromRemote(options, {
|
||||||
imWsUrl: options.serverUrl.replace('https://', 'wss://').replace('http://', 'ws://') + '/ws/im',
|
imWsUrl: DEFAULT_IM_WS_URL,
|
||||||
fileServiceUrl: options.serverUrl,
|
fileServiceUrl: DEFAULT_TENANT_PLATFORM_URL,
|
||||||
apiBaseUrl: options.serverUrl,
|
apiUrl: DEFAULT_TENANT_PLATFORM_URL,
|
||||||
})
|
})
|
||||||
if (options.debug) console.warn('[XuqmSDK] Config fetch failed, using fallback URLs', e)
|
if (options.debug) console.warn('[XuqmSDK] Config fetch failed, using fallback URLs', e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync initialize — uses fallback URL construction from serverUrl.
|
* @param options.appKey - Your application key (from the tenant platform)
|
||||||
* Kept for backward compatibility; prefer initialize() for production use.
|
|
||||||
*
|
|
||||||
* @param options.appId - Your application ID (from the tenant platform)
|
|
||||||
* @param options.serverUrl - Base URL of the tenant platform, e.g. "http://192.168.116.9:8081"
|
|
||||||
* @param options.appKey - Optional; defaults to appId
|
|
||||||
* @param options.debug - Enable verbose logging
|
* @param options.debug - Enable verbose logging
|
||||||
*/
|
*/
|
||||||
init(options: XuqmInitOptions): void {
|
init(options: XuqmInitOptions): void {
|
||||||
if (isInitialized()) return
|
if (isInitialized()) return
|
||||||
initConfigFromRemote(options, {
|
initConfigFromRemote(options, {
|
||||||
imWsUrl: options.serverUrl.replace('https://', 'wss://').replace('http://', 'ws://') + '/ws/im',
|
imWsUrl: DEFAULT_IM_WS_URL,
|
||||||
fileServiceUrl: options.serverUrl,
|
fileServiceUrl: DEFAULT_TENANT_PLATFORM_URL,
|
||||||
apiBaseUrl: options.serverUrl,
|
apiUrl: DEFAULT_TENANT_PLATFORM_URL,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -9,13 +9,14 @@
|
|||||||
* Config: xuqm.config.json in the project root
|
* Config: xuqm.config.json in the project root
|
||||||
* {
|
* {
|
||||||
* "serverUrl": "https://update.dev.xuqinmin.com",
|
* "serverUrl": "https://update.dev.xuqinmin.com",
|
||||||
* "appId": "your-app-id",
|
* "appKey": "your-app-key",
|
||||||
* "apiToken": "your-api-token",
|
* "apiToken": "your-api-token",
|
||||||
* "rn": {
|
* "rn": {
|
||||||
* "modules": [
|
* "modules": [
|
||||||
* { "moduleId": "main", "entryFile": "index.js", "platforms": ["android", "ios"] }
|
* { "moduleId": "main", "entryFile": "index.js", "packageName": "com.example.app", "platforms": ["android", "ios"] }
|
||||||
* ],
|
* ],
|
||||||
* "bundleOutputDir": "/tmp/xuqm_rn_bundle"
|
* "bundleOutputDir": "/tmp/xuqm_rn_bundle",
|
||||||
|
* "publishImmediately": false
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
@ -36,13 +37,14 @@ if (!existsSync(CONFIG_FILE)) {
|
|||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
const cfg = JSON.parse(readFileSync(CONFIG_FILE, 'utf8'))
|
const cfg = JSON.parse(readFileSync(CONFIG_FILE, 'utf8'))
|
||||||
const { serverUrl, appId, apiToken, rn = {} } = cfg
|
const { serverUrl, appKey, apiToken, rn = {} } = cfg
|
||||||
if (!serverUrl || !appId || !apiToken) {
|
if (!serverUrl || !appKey || !apiToken) {
|
||||||
console.error('[xuqm] serverUrl / appId / apiToken are required in config')
|
console.error('[xuqm] serverUrl / appKey / apiToken are required in config')
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
const modules = rn.modules ?? [{ moduleId: 'main', entryFile: 'index.js', platforms: ['android', 'ios'] }]
|
const modules = rn.modules ?? [{ moduleId: 'main', entryFile: 'index.js', platforms: ['android', 'ios'] }]
|
||||||
const bundleOutputDir = rn.bundleOutputDir ?? '/tmp/xuqm_rn_bundle'
|
const bundleOutputDir = rn.bundleOutputDir ?? '/tmp/xuqm_rn_bundle'
|
||||||
|
const publishImmediately = rn.publishImmediately === true || rn.publishImmediately === 'true'
|
||||||
|
|
||||||
// ── Helpers ─────────────────────────────────────────────────────────────────
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@ -59,15 +61,16 @@ async function apiFetch(path, opts = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Multipart upload using FormData (Node 18+ has built-in FormData)
|
// Multipart upload using FormData (Node 18+ has built-in FormData)
|
||||||
async function uploadBundle(moduleId, platform, bundleFile, version, minVersion, note) {
|
async function uploadBundle(moduleId, platform, bundleFile, version, minVersion, note, packageName) {
|
||||||
const form = new FormData()
|
const form = new FormData()
|
||||||
const blob = new Blob([readFileSync(bundleFile)], { type: 'application/octet-stream' })
|
const blob = new Blob([readFileSync(bundleFile)], { type: 'application/octet-stream' })
|
||||||
form.append('appId', appId)
|
form.append('appId', appKey)
|
||||||
form.append('moduleId', moduleId)
|
form.append('moduleId', moduleId)
|
||||||
form.append('platform', platform.toUpperCase())
|
form.append('platform', platform.toUpperCase())
|
||||||
form.append('version', version)
|
form.append('version', version)
|
||||||
form.append('minCommonVersion', minVersion)
|
form.append('minCommonVersion', minVersion)
|
||||||
form.append('note', note)
|
form.append('note', note)
|
||||||
|
if (packageName) form.append('packageName', packageName)
|
||||||
form.append('bundle', blob, path.basename(bundleFile))
|
form.append('bundle', blob, path.basename(bundleFile))
|
||||||
|
|
||||||
const res = await fetch(`${serverUrl}/api/v1/rn/upload`, {
|
const res = await fetch(`${serverUrl}/api/v1/rn/upload`, {
|
||||||
@ -92,7 +95,7 @@ async function main() {
|
|||||||
// ── 2. Server latest ─────────────────────────────────────────────────────
|
// ── 2. Server latest ─────────────────────────────────────────────────────
|
||||||
let serverVersion = 'none'
|
let serverVersion = 'none'
|
||||||
try {
|
try {
|
||||||
const resp = await apiFetch(`/api/v1/rn/list?appId=${appId}`)
|
const resp = await apiFetch(`/api/v1/rn/list?appId=${appKey}`)
|
||||||
const published = (resp.data ?? []).filter(x => x.publishStatus === 'PUBLISHED')
|
const published = (resp.data ?? []).filter(x => x.publishStatus === 'PUBLISHED')
|
||||||
serverVersion = published[0]?.version ?? 'none'
|
serverVersion = published[0]?.version ?? 'none'
|
||||||
} catch { /* no bundles yet */ }
|
} catch { /* no bundles yet */ }
|
||||||
@ -113,6 +116,7 @@ async function main() {
|
|||||||
console.log('\n\x1b[36m--- Summary ---\x1b[0m')
|
console.log('\n\x1b[36m--- Summary ---\x1b[0m')
|
||||||
console.log(` Version: ${localVersion}`)
|
console.log(` Version: ${localVersion}`)
|
||||||
console.log(` Modules: ${modules.map(m => m.moduleId).join(', ')}`)
|
console.log(` Modules: ${modules.map(m => m.moduleId).join(', ')}`)
|
||||||
|
const publishNow = publishImmediately || await confirm('Publish uploaded bundles immediately?')
|
||||||
const ok = await confirm('Proceed?')
|
const ok = await confirm('Proceed?')
|
||||||
if (!ok) { console.log('Aborted.'); rl.close(); return }
|
if (!ok) { console.log('Aborted.'); rl.close(); return }
|
||||||
|
|
||||||
@ -139,12 +143,23 @@ async function main() {
|
|||||||
|
|
||||||
// Upload
|
// Upload
|
||||||
console.log('\x1b[36mUploading...\x1b[0m')
|
console.log('\x1b[36mUploading...\x1b[0m')
|
||||||
const resp = await uploadBundle(mod.moduleId, platform, bundleFile, localVersion, minVersion, note)
|
const resp = await uploadBundle(mod.moduleId, platform, bundleFile, localVersion, minVersion, note, mod.packageName)
|
||||||
const bundleId = resp.data?.id
|
const bundleId = resp.data?.id
|
||||||
console.log(`\x1b[32m✓ ${mod.moduleId}/${platform} uploaded, ID: ${bundleId}\x1b[0m`)
|
console.log(`\x1b[32m✓ ${mod.moduleId}/${platform} uploaded, ID: ${bundleId}\x1b[0m`)
|
||||||
|
if (publishNow) {
|
||||||
|
const publishResp = await fetch(`${serverUrl}/api/v1/rn/${bundleId}/publish`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: apiHeaders(),
|
||||||
|
})
|
||||||
|
if (!publishResp.ok) {
|
||||||
|
throw new Error(`Publish failed: ${publishResp.status} ${await publishResp.text()}`)
|
||||||
|
}
|
||||||
|
console.log(` Published immediately: POST ${serverUrl}/api/v1/rn/${bundleId}/publish`)
|
||||||
|
} else {
|
||||||
console.log(` Publish: POST ${serverUrl}/api/v1/rn/${bundleId}/publish`)
|
console.log(` Publish: POST ${serverUrl}/api/v1/rn/${bundleId}/publish`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rl.close()
|
rl.close()
|
||||||
console.log('\n\x1b[32m=== Release complete ===\x1b[0m')
|
console.log('\n\x1b[32m=== Release complete ===\x1b[0m')
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
export interface XuqmSDKConfig {
|
export interface XuqmSDKConfig {
|
||||||
appId: string
|
|
||||||
appKey: string
|
appKey: string
|
||||||
appSecret: string
|
appSecret: string
|
||||||
apiBaseUrl: string
|
|
||||||
imWsUrl: string
|
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage'
|
|||||||
import { getConfig } from './config'
|
import { getConfig } from './config'
|
||||||
|
|
||||||
const TOKEN_KEY = '@xuqm_sdk_token'
|
const TOKEN_KEY = '@xuqm_sdk_token'
|
||||||
|
const DEFAULT_API_URL = 'https://dev.xuqinmin.com'
|
||||||
|
|
||||||
export async function getToken(): Promise<string | null> {
|
export async function getToken(): Promise<string | null> {
|
||||||
return AsyncStorage.getItem(TOKEN_KEY)
|
return AsyncStorage.getItem(TOKEN_KEY)
|
||||||
@ -22,7 +23,7 @@ export async function apiRequest<T>(
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
const token = await getToken()
|
const token = await getToken()
|
||||||
|
|
||||||
let url = config.apiBaseUrl.replace(/\/$/, '') + path
|
let url = DEFAULT_API_URL.replace(/\/$/, '') + path
|
||||||
if (options.params) {
|
if (options.params) {
|
||||||
const qs = new URLSearchParams(options.params).toString()
|
const qs = new URLSearchParams(options.params).toString()
|
||||||
url += (url.includes('?') ? '&' : '?') + qs
|
url += (url.includes('?') ? '&' : '?') + qs
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { ImClient } from './imClient'
|
|||||||
import type { ChatType, ImEventListener, ImGroup, ImMessage, MsgType } from './types'
|
import type { ChatType, ImEventListener, ImGroup, ImMessage, MsgType } from './types'
|
||||||
|
|
||||||
let client: ImClient | null = null
|
let client: ImClient | null = null
|
||||||
|
const DEFAULT_IM_WS_URL = 'wss://dev.xuqinmin.com/ws/im'
|
||||||
|
|
||||||
export const ImSDK = {
|
export const ImSDK = {
|
||||||
async login(userId: string, nickname?: string, avatar?: string): Promise<void> {
|
async login(userId: string, nickname?: string, avatar?: string): Promise<void> {
|
||||||
@ -11,14 +12,14 @@ export const ImSDK = {
|
|||||||
const res = await apiRequest<{ token: string }>('/api/im/auth/login', {
|
const res = await apiRequest<{ token: string }>('/api/im/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
params: {
|
params: {
|
||||||
appId: config.appId,
|
appId: config.appKey,
|
||||||
userId,
|
userId,
|
||||||
...(nickname ? { nickname } : {}),
|
...(nickname ? { nickname } : {}),
|
||||||
...(avatar ? { avatar } : {}),
|
...(avatar ? { avatar } : {}),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
await saveToken(res.token)
|
await saveToken(res.token)
|
||||||
client = new ImClient(config.imWsUrl, res.token, config.appId)
|
client = new ImClient(DEFAULT_IM_WS_URL, res.token, config.appKey)
|
||||||
client.connect()
|
client.connect()
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ export const ImSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
const token = await getToken()
|
const token = await getToken()
|
||||||
if (!token) throw new Error('ImSDK: token not found')
|
if (!token) throw new Error('ImSDK: token not found')
|
||||||
client = new ImClient(config.imWsUrl, token, config.appId)
|
client = new ImClient(DEFAULT_IM_WS_URL, token, config.appKey)
|
||||||
client.connect()
|
client.connect()
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ export const ImSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
const res = await apiRequest<{ content?: ImMessage[] } | ImMessage[]>(`/api/im/messages/history/${encodeURIComponent(toId)}`, {
|
const res = await apiRequest<{ content?: ImMessage[] } | ImMessage[]>(`/api/im/messages/history/${encodeURIComponent(toId)}`, {
|
||||||
params: {
|
params: {
|
||||||
appId: config.appId,
|
appId: config.appKey,
|
||||||
page: String(page),
|
page: String(page),
|
||||||
size: String(size),
|
size: String(size),
|
||||||
},
|
},
|
||||||
@ -52,7 +53,7 @@ export const ImSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
return apiRequest<ImMessage>('/api/im/messages/send', {
|
return apiRequest<ImMessage>('/api/im/messages/send', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
params: { appId: config.appId },
|
params: { appId: config.appKey },
|
||||||
body: {
|
body: {
|
||||||
toId,
|
toId,
|
||||||
chatType,
|
chatType,
|
||||||
@ -67,7 +68,7 @@ export const ImSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
return apiRequest<ImMessage>(`/api/im/messages/${encodeURIComponent(messageId)}/revoke`, {
|
return apiRequest<ImMessage>(`/api/im/messages/${encodeURIComponent(messageId)}/revoke`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
params: { appId: config.appId },
|
params: { appId: config.appKey },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ export const ImSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
return apiRequest<ImMessage>(`/api/im/messages/${encodeURIComponent(messageId)}`, {
|
return apiRequest<ImMessage>(`/api/im/messages/${encodeURIComponent(messageId)}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
params: { appId: config.appId },
|
params: { appId: config.appKey },
|
||||||
body: { content },
|
body: { content },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -105,7 +106,7 @@ export const ImSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
return apiRequest<ImGroup>('/api/im/groups', {
|
return apiRequest<ImGroup>('/api/im/groups', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
params: { appId: config.appId },
|
params: { appId: config.appKey },
|
||||||
body: { name, memberIds },
|
body: { name, memberIds },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -113,7 +114,7 @@ export const ImSDK = {
|
|||||||
async listGroups(): Promise<ImGroup[]> {
|
async listGroups(): Promise<ImGroup[]> {
|
||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
const res = await apiRequest<ImGroup[] | { content?: ImGroup[] }>('/api/im/groups', {
|
const res = await apiRequest<ImGroup[] | { content?: ImGroup[] }>('/api/im/groups', {
|
||||||
params: { appId: config.appId },
|
params: { appId: config.appKey },
|
||||||
})
|
})
|
||||||
return Array.isArray(res) ? res : (res.content ?? [])
|
return Array.isArray(res) ? res : (res.content ?? [])
|
||||||
},
|
},
|
||||||
@ -124,7 +125,7 @@ export const ImSDK = {
|
|||||||
`/api/im/messages/history/${encodeURIComponent(groupId)}`,
|
`/api/im/messages/history/${encodeURIComponent(groupId)}`,
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
appId: config.appId,
|
appId: config.appKey,
|
||||||
page: String(page),
|
page: String(page),
|
||||||
size: String(size),
|
size: String(size),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export const PushSDK = {
|
|||||||
await apiRequest('/api/push/register', {
|
await apiRequest('/api/push/register', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
params: {
|
params: {
|
||||||
appId: config.appId,
|
appId: config.appKey,
|
||||||
userId,
|
userId,
|
||||||
vendor,
|
vendor,
|
||||||
token,
|
token,
|
||||||
@ -22,7 +22,7 @@ export const PushSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
await apiRequest('/api/push/unregister', {
|
await apiRequest('/api/push/unregister', {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
params: { appId: config.appId, userId },
|
params: { appId: config.appKey, userId },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,8 @@ export interface RnUpdateInfo {
|
|||||||
md5: string
|
md5: string
|
||||||
minCommonVersion: string
|
minCommonVersion: string
|
||||||
note: string
|
note: string
|
||||||
|
packageName?: string
|
||||||
|
packageMatched?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CachedRnBundle {
|
export interface CachedRnBundle {
|
||||||
@ -62,7 +64,7 @@ export const UpdateSDK = {
|
|||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
const result = await apiRequest<AppUpdateInfo>('/api/v1/updates/app/check', {
|
const result = await apiRequest<AppUpdateInfo>('/api/v1/updates/app/check', {
|
||||||
params: {
|
params: {
|
||||||
appId: config.appId,
|
appId: config.appKey,
|
||||||
platform: Platform.OS === 'android' ? 'ANDROID' : 'IOS',
|
platform: Platform.OS === 'android' ? 'ANDROID' : 'IOS',
|
||||||
currentVersionCode: String(currentVersionCode),
|
currentVersionCode: String(currentVersionCode),
|
||||||
},
|
},
|
||||||
@ -78,16 +80,23 @@ export const UpdateSDK = {
|
|||||||
if (url) await Linking.openURL(url)
|
if (url) await Linking.openURL(url)
|
||||||
},
|
},
|
||||||
|
|
||||||
async checkRnUpdate(moduleId: string, currentVersion: string): Promise<RnUpdateInfo> {
|
async checkRnUpdate(moduleId: string, currentVersion: string, packageName?: string): Promise<RnUpdateInfo> {
|
||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
const result = await apiRequest<RnUpdateInfo>('/api/v1/rn/update/check', {
|
const result = await apiRequest<RnUpdateInfo>('/api/v1/rn/update/check', {
|
||||||
params: {
|
params: {
|
||||||
appId: config.appId,
|
appId: config.appKey,
|
||||||
moduleId,
|
moduleId,
|
||||||
platform: Platform.OS === 'android' ? 'ANDROID' : 'IOS',
|
platform: Platform.OS === 'android' ? 'ANDROID' : 'IOS',
|
||||||
currentVersion,
|
currentVersion,
|
||||||
|
...(packageName ? { packageName } : {}),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
if (packageName && result.packageMatched === false) {
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
needsUpdate: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
downloadUrl: normalizeDownloadUrl(result.downloadUrl) ?? result.downloadUrl,
|
downloadUrl: normalizeDownloadUrl(result.downloadUrl) ?? result.downloadUrl,
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户