/** * 设备指纹(spec §9.1 v2.3 限流维度 — X-Device-Fingerprint) * * 为什么不复用 push cid(uni.getPushClientId 拿到的 cid): * - push cid 在推送 SDK 升级 / 推送通道重连时会变 → 限流计数被误清零 * - 小程序/H5 端无 push 概念,多端不统一 * * 方案:App 启动时生成一次 UUID v4,持久化到 storage: * - 跨重启 / 跨账号 / 推送 SDK 升级 → 稳定不变 * - 卸载重装后才会变(storage 一起被清,业界无解) * * 自包含:第一次调用时自动 bootstrap,无需外部初始化。 * 三端统一(App / 小程序 / H5),不依赖 plus.* 等平台 API。 */ const STORAGE_KEY = 'deviceFp' /** * 获取当前设备的稳定指纹;首次调用时自动生成并写入 storage。 * @returns {string} UUID v4 格式字符串 */ export function getDeviceFingerprint() { let fp = '' try { fp = uni.getStorageSync(STORAGE_KEY) } catch (e) { // storage 读取失败时降级:本次返回临时值,下次调用会重试 } if (!fp) { fp = generateUuidV4() try { uni.setStorageSync(STORAGE_KEY, fp) } catch (e) { // storage 写入失败不影响本次使用(仅会下次重新生成) console.warn('[deviceFingerprint] setStorageSync failed', e) } } return fp } /** * 生成 RFC4122 v4 格式 UUID。 * 使用 Math.random()(uni-app 三端通用),不引入第三方库。 * 设备指纹场景对密码学强度无要求,唯一性即可。 */ function generateUuidV4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0 const v = c === 'x' ? r : (r & 0x3) | 0x8 return v.toString(16) }) }