必须首次启动时生成并持久化UUID——plus.device.uuid不稳定、uni.getSystemInfoSync()不提供、Android 10+ IMEI失效,唯一可靠路径是自己造一个、存三份、用链式fallback。

不能直接“获取”UUID,必须首次启动时生成并持久化——plus.device.uuid不稳定、uni.getSystemInfoSync()不提供、Android 10+上IMEI已失效,唯一可靠路径是自己造一个、存三份、用链式 fallback。
plus.device.uuid为什么不能当设备唯一标识用
它由 5+ Runtime 动态生成,不是系统级 ID;应用卸载重装后必然变化;部分 Android 12+ 厂商定制 ROM(如 realme、vivo 某些版本)返回空或固定值;iOS 上行为更不可控。实测中 plus.device.uuid 在华为鸿蒙 4.2 和小米 HyperOS 2.0 上约有 30% 概率返回 "" 或 "00000000-0000-0000-0000-000000000000"。
列表里不要把它当主标识,只可作临时会话 ID 使用。
Android 10+ 必须用 OAID → android_id → 本地 UUID 链式 fallback
单一 API 在当前安卓生态里注定失败。真正落地的方案是分层兜底:
- 第一层:
plus.device.getOAID—— 仅限 App 平台,需自定义基座启用 MSA 插件,首次调用延迟 200–500ms,返回空或"00000000-0000-0000-0000-000000000000"时立即降级 - 第二层:
android_id—— 用原生桥接获取:Settings.Secure.getString(cr, "android_id"),兼容 Android 5.0+,无需权限,但部分 vivo/Funtouch OS 和华为鸿蒙 3.0+ 会返回固定值,需拼接Build.SERIAL提升区分度 - 第三层:本地生成 v4 UUID 并三重落盘 —— 必须在首次启动检测
uni.getStorageSync('device_id')是否存在,不存在则生成并同步写入:plus.storage.setItem、uni.setStorageSync、以及文件系统(防清缓存)
本地 UUID 生成和存储必须避开三个坑
很多人用 Math.random().toString(36) 拼接,熵太低,多设备并发生成时易撞车;也有人只存 uni.setStorageSync,但在 iOS 17+ 沙盒收紧后偶发写失败;还有人忽略首次启动时机,在登录页才触发,导致冷启无 ID。
正确做法:
- 生成必须用标准 v4 UUID 格式:
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0; return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); }) - 存储必须三路并行:先写文件(
uni.getFileSystemManager().writeFile),再写plus.storage.setItem('device_id', id),最后补uni.setStorageSync('device_id', id) - 触发时机必须在
App.vue的onLaunch中,且加防抖(避免多进程重复生成)
iOS 上没有 OAID,只能靠本地 UUID + 服务端绑定
iOS 完全不提供类似 OAID 的系统级匿名 ID;deviceToken 是 APNs 推送专用凭证,每次重装 App 都会变;aliyunpush.getDeviceId() 等 SDK 自建 ID 仅限该通道内有效,换推送服务就失效。
所以 iOS 唯一可行路径是:首次启动生成 v4 UUID,三重落盘,然后和服务端建立「设备 ID ↔ 用户账号」绑定关系。注意两点:
- 别把 UUID 当作用户身份直接透传,必须经服务端校验并签发 token
- 若用户主动注销或清除 App 数据,应主动通知服务端解绑该 device_id,否则会堆积僵尸设备记录
最常被忽略的一点:所有前端生成的设备标识(包括 OAID、android_id、本地 UUID)都属于《个人信息保护法》定义的“设备标识信息”,必须单独弹窗授权,不能混在隐私协议里默认勾选。没做这步,上线审核大概率被拒。


















