Android 10+推荐首选OAID:需启用MSA SDK插件、在onLaunch提前初始化;fallback用android_id(兼容5.0+、无需权限、不随卸载重置);兜底自生成v4 UUID并三端持久化,禁用plus.device.uuid等不可靠方案。

Android 10+ 系统下,getIMEI 已不可用,调用会返回 "" 或抛出 SecurityException;plus.device.uuid 不稳定(卸载重装即变),也不能直接从 uni.getSystemInfoSync() 拿到。真要设备级唯一 ID,得靠组合策略+持久化,而不是依赖单个 API。
Android 10+ 怎么安全获取 OAID(推荐首选)
OAID 是目前合规、可重置、且无需敏感权限的替代方案,但必须满足三个前提:
- 仅在 App 平台(非 H5/小程序)可用
- 自定义基座或标准基座需启用 MSA SDK 插件(打包时勾选“OAID 支持”)
- 首次调用有初始化延迟,不能等到登录页才触发
实操建议:
- 在
App.vue的onLaunch中提前调用:uni.getOAID({ success: res => uni.setStorageSync('oaid', res.oaid) }) - 调试时检查控制台日志是否含
oaid:字段及真实值(不是空字符串或00000000-0000-0000-0000-000000000000) - 若返回空,先确认插件已集成、基座已重打,再查 Android 日志中是否有
MSA SDK init failed类错误
OAID 不可用时 fallback 到 android_id
android_id 是系统级标识,兼容 Android 5.0+,无需运行时权限,稳定性远高于 UUID,且不会因应用卸载重置(仅恢复出厂或刷机会变)。
实操建议:
- 用
plus.android.importClass('android.provider.Settings$Secure')+getString获取,不要用过时的plus.device.androidId(部分基座已弃用) - 注意:某些厂商定制 ROM(如小米 EU 版)可能返回 null,需加空值判断
- 建议拼接
Build.SERIAL(需plus.android.importClass('android.os.Build'))作为二级特征,增强区分度
本地生成并持久化 UUID(全平台兜底方案)
当 OAID 和 android_id 都失败(比如用户拒绝所有权限、低端机 ROM 问题),就该自己生成 UUID 并存三处:
- 优先写入
uni.setStorageSync(最常用) - 同步写入
plus.storage.setItem(兼容老基座) - 额外落盘到文件(
uni.getFileSystemManager().writeFile)防极端清缓存场景
生成方式别用 Math.random() 拼接——用标准 v4 UUID 格式:
function generateUUID() {
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)
})
}首次启动检测 uni.getStorageSync('device_id') 是否存在,不存在则生成并存三份。
为什么不能直接用 plus.device.uuid 或 uni.getPushClientId
plus.device.uuid 在多数基座中实际是取自 ANDROID_ID,但部分版本会退化为随机值;更关键的是,它不持久——应用卸载后重装,值就变了,无法支撑设备绑定类逻辑。
uni.getPushClientId 依赖 uni-push2.0,且只在开启推送服务后才可用;它本质是厂商通道分配的 token,可能随推送服务开关、token 过期而刷新,也不适合做设备主键。
真正容易被忽略的点是:服务端必须校验前端传来的 ID 是否“可信”。哪怕你拿到了 OAID,也要在服务端比对历史请求中的 UA、IP、时间戳等上下文,防止客户端伪造。纯前端生成的 ID,永远需要服务端兜底验证。


















