文章目录
- 前言
- 一、为什么有这么多"设备 ID"?
- 二、DeviceUtil 标识符相关方法源码
- 三、DeviceId 的特殊设计:卸载后不消失
- 四、Demo 完整演示代码
- 五、四种 ID 选择建议
- 六、小结
前言
近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦
案例demo导航展示
↓↓↓↓↓↓接下来言归正传 ↓↓↓↓
一、为什么有这么多"设备 ID"?
不同场景需要不同类型的设备标识符:
| 标识符 | 作用 | 特点 |
|---|---|---|
| DeviceId | 应用内持久化标识 | 卸载后不变(用 AssetUtil 存储) |
| ODID | 开发者匿名标识 | 同开发者的不同应用相同,用户可重置 |
| OAID | 广告标识 | 用于精准广告,用户可关闭 |
| AAID | 推送标识 | 用于消息推送(华为 Push),可删除重置 |
二、DeviceUtil 标识符相关方法源码
// DeviceUtil.ets(工具类源码)// 获取设备ID(卸载APP后依旧不变)// 需要权限:ohos.permission.STORE_PERSISTENT_DATAstaticgetDeviceId(rule:boolean=true,generateId?:string):string{letdeviceId=DeviceUtil.deviceId;if(StrUtil.isEmpty(deviceId)){// 优先从关键资产服务读取(持久化存储)if(AssetUtil.canIUse()){deviceId=StrUtil.toStr(AssetUtil.getSync(DEVICE_ID_KEY));}else{// 降级:使用 PreferencesdeviceId=StrUtil.toStr(PreferencesUtil.getStringSync(DEVICE_ID_KEY));}// 首次启动,生成新 IDif(StrUtil.isEmpty(deviceId)){deviceId=generateId||RandomUtil.generateRandomUUID(true);if(AssetUtil.canIUse()){AssetUtil.addSync(DEVICE_ID_KEY,deviceId);// 存入关键资产(卸载保留)}else{PreferencesUtil.putSync(DEVICE_ID_KEY,deviceId);}}DeviceUtil.deviceId=deviceId;}if(!rule){deviceId=deviceId.replace(/-/g,'');// 去除横线}returndeviceId;}// 移除设备IDstaticdeleteDeviceId():void{DeviceUtil.deviceId='';if(AssetUtil.canIUse()){AssetUtil.removeSync(DEVICE_ID_KEY);}else{PreferencesUtil.deleteSync(DEVICE_ID_KEY);}}// 获取开发者匿名设备标识符 ODIDstaticgetODID():string{returndeviceInfo.ODID;}// 获取开放匿名设备标识符 OAID(需权限)// @permission ohos.permission.APP_TRACKING_CONSENTstaticasyncgetOAID():Promise<string>{returnidentifier.getOAID();}// 获取 AAID(推送服务标识)staticasyncgetAAID():Promise<string>{returnAAID.getAAID();}// 删除 AAIDstaticasyncdeleteAAID():Promise<void>{returnAAID.deleteAAID();}三、DeviceId 的特殊设计:卸载后不消失
DeviceUtil.getDeviceId最特别的地方是:普通应用数据卸载后会清除,但它借助**关键资产服务(AssetUtil)**将 ID 存储在系统级存储区,即使卸载应用也不会丢失。
首次安装应用: 1. 读取 AssetUtil → 空 2. 生成 UUID (如 550e8400-e29b-41d4-a716-446655440000) 3. 存入 AssetUtil 4. 返回 UUID 卸载应用 → 重装: 1. 读取 AssetUtil → 550e8400-e29b-41d4-a716-446655440000 2. 直接返回(ID 不变!)四、Demo 完整演示代码
// DeviceUtilDemoPage.ets(Demo 源码)// 加载所有设备标识符loadDeviceId(){// DeviceId(带横线 vs 无横线)this.deviceIdResult=DeviceUtil.getDeviceId(true);// 带横线this.deviceIdRaw=DeviceUtil.getDeviceId(false);// 无横线this.addLog('DeviceId',`获取成功(带横线:${this.deviceIdResult.substring(0,20)}...)`,'info');// ODID(同步,直接返回)this.odidResult=DeviceUtil.getODID();this.addLog('ODID',`ODID:${this.odidResult}`,'info');// OAID(异步,需用户授权)DeviceUtil.getOAID().then((oaid:string)=>{this.oaidResult=oaid;this.addLog('OAID',`OAID:${oaid.substring(0,20)}...`,'success');}).catch((e:Error)=>{this.oaidResult=`获取失败:${e.message}`;this.addLog('OAID',`获取失败:${e.message}`,'error');});// AAID(异步)DeviceUtil.getAAID().then((aaid:string)=>{this.aaidResult=aaid;this.addLog('AAID',`AAID:${aaid}`,'success');}).catch((e:Error)=>{this.aaidResult=`获取失败:${e.message}`;this.addLog('AAID',`获取失败:${e.message}`,'error');});// Serial & Udid(系统应用专用)this.serialResult=DeviceUtil.getSerial();this.udidResult=DeviceUtil.getUdid();}// 删除并重新生成设备IDtestDeleteDeviceId(){DeviceUtil.deleteDeviceId();this.addLog('DeviceId','设备ID已删除,重新生成...','warn');this.loadDeviceId();// 删除后立即重新生成}// UI 展示Column(){Text('设备标识符').fontSize(13).fontColor('#666').fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:10})// Device ID(带横线)Column(){Text('Device ID(带横线)').fontSize(11).fontColor('#888').alignSelf(ItemAlign.Start)Text(this.deviceIdResult).fontSize(11).fontFamily('monospace').fontColor('#D63384').margin({top:2}).width('100%')}.width('100%').padding(10).backgroundColor('#F5F6FA').borderRadius(8).margin({bottom:6})// Device ID(无横线)Column(){Text('Device ID(无横线)').fontSize(11).fontColor('#888').alignSelf(ItemAlign.Start)Text(this.deviceIdRaw).fontSize(11).fontFamily('monospace').fontColor('#D63384').margin({top:2}).width('100%')}.width('100%').padding(10).backgroundColor('#F5F6FA').borderRadius(8).margin({bottom:6})Row(){Button('刷新 DeviceId').fontSize(12).height(34).backgroundColor('#4080FF').fontColor('#FFF').onClick(()=>{this.loadDeviceId();})Button('删除并重新生成').fontSize(12).height(34).margin({left:8}).backgroundColor('#FF5252').fontColor('#FFF').onClick(()=>{this.testDeleteDeviceId();})}.width('100%')}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)// OAID 展示(含权限提示)Column(){Text('OAID(开放匿名设备标识符)').fontSize(11).fontColor('#888').alignSelf(ItemAlign.Start)Text(this.oaidResult||'加载中...').fontSize(12).fontFamily('monospace').fontColor(this.oaidResult&&!this.oaidResult.startsWith('获取失败')?'#D63384':'#888').margin({top:4}).width('100%')Text('⚠️ 需要用户授权 ohos.permission.APP_TRACKING_CONSENT').fontSize(10).fontColor('#FF9800').margin({top:4})}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)五、四种 ID 选择建议
| 需求 | 推荐 ID | 权限要求 |
|---|---|---|
| 用户行为分析(不跨应用) | DeviceId | STORE_PERSISTENT_DATA(可选) |
| 同一开发者多应用打通 | ODID | 无 |
| 精准广告投放 | OAID | 用户授权 |
| 华为推送通知 | AAID | 无(Push 服务) |
| 设备序列号(系统应用) | getSerial/getUdid | 系统权限 |
六、小结
getDeviceId:首选方案,利用 AssetUtil 实现卸载后不变的持久化 IDgetODID:同一开发者下的多应用互通标识,无需权限getOAID:广告行业标准,需要用户明确授权getAAID:华为推送专用,可由用户删除重置