1. 为什么需要获取设备唯一标识?
在移动应用开发中,设备唯一标识是许多业务场景的基础需求。比如用户行为分析、设备风控、精准推送等都需要可靠的设备识别方案。对于uni-app开发者来说,由于跨平台特性,获取设备ID的方式与原生开发有所不同。
安卓平台常见的设备标识包括:
- IMEI(国际移动设备识别码):传统手机的唯一硬件标识
- OAID(匿名设备标识符):国内移动安全联盟推出的替代方案
- Android ID:系统级别的设备标识
- 序列号:设备制造商分配的硬件标识
特别注意:从Android 10开始,普通应用已无法直接获取IMEI等持久性设备标识,这是谷歌加强隐私保护的重要举措。开发者需要适配新的标识获取方案。
2. uni-app获取设备标识的核心方法
2.1 使用uni-app原生API
uni-app提供了uni.getSystemInfo接口,可以获取部分设备信息:
uni.getSystemInfo({ success: function (res) { console.log(res.deviceId); // 设备标识 console.log(res.model); // 设备型号 console.log(res.system); // 系统版本 } });但需要注意:
- 不同平台返回的deviceId含义不同
- iOS平台返回的是identifierForVendor
- 部分安卓设备可能返回空值
2.2 使用原生插件获取IMEI/MEID
对于需要获取IMEI的场景,可以通过原生插件实现:
- 安装cordova插件:
cordova plugin add cordova-plugin-imei- 在uni-app中使用:
document.addEventListener('deviceready', function() { window.imei.get(function(imei) { console.log(imei); }, function(err) { console.error(err); }); }, false);重要提示:从Android 6.0开始,获取IMEI需要READ_PHONE_STATE权限,且需要动态权限申请。
2.3 获取OAID的实践方案
OAID(Open Anonymous Device Identifier)是国内移动安全联盟推出的设备标识解决方案,适用于无法获取IMEI的场景。
实现步骤:
- 集成移动安全联盟的SDK
- 在manifest.json中添加权限声明:
<uses-permission android:name="com.asus.msa.SupplementaryDID.ACCESS" /> <uses-permission android:name="com.huawei.hms.ppskit.permission.PPS_GET_ADID" />- 调用获取接口:
// 在原生代码中 MSAHelper.getOAID(this, new IIdentifierListener() { @Override public void OnOAIDGetComplete(String oaid) { // 获取到OAID } });3. 各方案对比与选型建议
| 方案 | 适用场景 | 优点 | 缺点 | 兼容性 |
|---|---|---|---|---|
| IMEI | 需要硬件级唯一标识 | 唯一性强 | 高版本受限 | Android 9及以下 |
| OAID | 国内合规方案 | 符合监管要求 | 需要集成SDK | 主流国产厂商 |
| Android ID | 简单易用 | 无需额外权限 | 恢复出厂设置会变化 | 全版本支持 |
| 自定义ID | 应用内标识 | 完全可控 | 无法跨应用 | 全平台支持 |
选型建议:
- 国内应用优先考虑OAID
- 海外应用可考虑Android ID+广告ID组合
- 需要硬件级标识的特定场景可尝试IMEI(需说明必要性)
4. 实际开发中的注意事项
4.1 权限处理最佳实践
从Android 6.0开始,敏感权限需要动态申请:
// 检查权限 uni.authorize({ scope: 'scope.record', success() { // 已授权 }, fail() { // 未授权,引导用户开启 uni.showModal({ content: '需要设备信息权限才能正常使用', confirmText: '去设置', success(res) { if (res.confirm) { uni.openSetting(); } } }); } });4.2 多平台兼容处理
uni-app需要处理各平台的差异:
let deviceId = ''; // #ifdef APP-PLUS deviceId = plus.device.imei || plus.device.uuid; // #endif // #ifdef H5 deviceId = localStorage.getItem('deviceId') || generateDeviceId(); // #endif4.3 数据安全合规
- 收集用户设备信息需在隐私政策中明确说明
- 敏感信息传输必须加密
- 欧盟GDPR等法规有特殊要求,海外发布需特别注意
5. 常见问题解决方案
5.1 获取不到IMEI的情况排查
- 检查Android版本是否≥10
- 确认已添加READ_PHONE_STATE权限
- 检查是否在后台线程调用(部分设备要求主线程)
- 某些定制ROM可能屏蔽了IMEI获取
5.2 OAID获取为空的处理
- 确认已集成最新版MSA SDK
- 检查设备是否支持(华为、小米等主流品牌支持)
- 部分模拟器可能不支持OAID
- 尝试延迟获取(某些设备需要时间初始化)
5.3 备用方案设计
建议采用分级获取策略:
async function getDeviceId() { try { // 优先尝试获取OAID const oaid = await getOAID(); if(oaid) return oaid; // 次选Android ID const androidId = await getAndroidId(); if(androidId) return androidId; // 最后使用随机生成的UUID return generateUUID(); } catch(e) { console.error(e); return generateUUID(); } }6. 性能优化建议
- 缓存设备标识:首次获取后存储在本地,避免重复获取
- 延迟加载:非必要不提前获取
- 失败重试机制:网络请求失败时自动重试
- 数据压缩:传输时对设备信息进行编码压缩
// 缓存示例 const deviceId = uni.getStorageSync('deviceId') || await fetchDeviceId(); uni.setStorageSync('deviceId', deviceId);7. 最新技术动态追踪
随着隐私保护要求提高,设备标识方案也在不断演进:
- Android 11进一步限制了非重置性标识的获取
- 国内各大厂商正在推进CAID等新标准
- 苹果在iOS 14.5引入了ATT框架
- 谷歌计划推出Privacy Sandbox方案
建议开发者:
- 保持对政策变化的关注
- 定期更新SDK版本
- 设计灵活的标识方案架构
- 为未来可能的变更预留接口
在实际项目中,我通常会创建一个DeviceInfoManager类来统一管理各种标识获取逻辑,并通过接口隔离具体实现,这样当政策或技术方案变化时,只需修改具体实现类即可。