HarmonyOS鸿蒙Next应用如何获取设备唯一标识(如 IMEI、OAID)?
HarmonyOS鸿蒙Next应用如何获取设备唯一标识(如 IMEI、OAID)? 需要做设备风控,传统方案是读 IMEI,但现在隐私政策越来越严。鸿蒙还允许获取硬件 ID 吗?有没有替代方案?
鸿蒙禁止普通应用获取 IMEI、MAC、Serial Number 等硬件标识。
更多关于HarmonyOS鸿蒙Next应用如何获取设备唯一标识(如 IMEI、OAID)?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
目前可以获取到软件版本号、硬件版本号、Build版本号等
这个里面的UDID好像能满足你的需求:如何通过API获取常见设备标识符并实现标识符不发生变化,你看看对你有没有帮助。
可以参考文档,ohos.deviceInfo (设备信息),看可有帮助:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-device-info
参考其它示例代码,https://developer.huawei.com/consumer/cn/blog/topic/03189375471183037:
import { BusinessError, deviceInfo } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { AAID } from '@kit.PushKit';
import { abilityAccessCtrl, bundleManager, common } from '@kit.AbilityKit';
import { identifier } from '@kit.AdsKit';
export default class DeviceIdTest {
// Get ODID.
getOdId(): string {
let odId = deviceInfo.ODID;
console.info(`getOdId: ${odId}`);
return odId;
}
// Get AAID.
async getAaId(): Promise<string> {
let aaId = '';
await AAID.getAAID().then((data: string) => {
aaId = data;
console.info(`getAAID: ${aaId}`);
}).catch((err: BusinessError) => {
console.error('Failed to get AAID', err.code, err.message);
})
return aaId;
}
// Get OAID.
getOaId() {
let hasPermission = false;
let tokenId: number = 0;
try {
// Obtain the current application's BundleInfo based on the given BundleFlags using synchronous methods.
let bundleInfo: bundleManager.BundleInfo =
bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
tokenId = appInfo.accessTokenId;
} catch (error) {
const err = error as BusinessError;
hilog.error(0x0000, 'testTag', '%{public}s',
`Failed to query Asset. Code: ${err.code}, message: ${err.message}`);
}
try {
let atManager = abilityAccessCtrl.createAtManager();
// Verify whether the application has been granted permissions through tokenID and permissionName.
let access = atManager.checkAccessTokenSync(tokenId, 'ohos.permission.APP_TRACKING_CONSENT');
hasPermission = access === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
} catch (error) {
const err = error as BusinessError;
hilog.error(0x0000, 'testTag', '%{public}s',
`Failed to check access token. Code: ${err.code}, message: ${err.message}`);
}
if (hasPermission) {
this.rquestOAID();
} else {
this.requestPermissions();
}
}
private rquestOAID() {
// The API is not supported on all devices. Use the canIUse condition to determine whether the API is supported.
if (canIUse('SystemCapability.Advertising.OAID')) {
try {
// Obtain open anonymous device identifiers.
identifier.getOAID().then((data) => {
hilog.info(0x0000, 'testTag', '%{public}s', `Success getting OAID by promise, OAID:', ${data}`);
}).catch((err: BusinessError) => {
hilog.error(0x0000, 'testTag', '%{public}s',
`get oaid by promise failed, code: ${err.code}, message: ${err.message}`);
})
} catch (err) {
hilog.error(0x0000, 'testTag', '%{public}s',
`Failed to get oaid by promise, catch error: ${err.code}, ${err.message}`);
}
} else {
hilog.info(0x0000, 'testTag', '%{public}s', 'Advertising not by this device.');
}
}
// Request Permissions.
private requestPermissions() {
let atManager = abilityAccessCtrl.createAtManager();
try {
atManager.requestPermissionsFromUser(getContext(this) as common.UIAbilityContext,
['ohos.permission.APP_TRACKING_CONSENT']).then((data) => {
hilog.info(0x0000, 'testTag', '%{public}s', `requestPermissionsFromUser: ${JSON.stringify(data)}`)
if (data.authResults[0] === -1 && data.dialogShownResults && !data.dialogShownResults[0]) {
// User not authorized.
this.openPermissionsSetting();
}
if (data.authResults[0] !== 0) {
// No permission obtained.
hilog.info(0x0000, 'testTag', 'No permission obtained');
return;
}
this.rquestOAID();
}).catch((err: Error) => {
hilog.error(0x0000, 'testTag', '%{public}s', `requestPermissionsFromUser err: ${JSON.stringify(err)}`);
})
} catch (err) {
hilog.error(0x0000, 'testTag', '%{public}s', `requestPermissionsFromUser err: ${JSON.stringify(err)}`);
}
}
// Open permissions setting.
private openPermissionsSetting() {
let atManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionOnSetting(getContext(this) as common.UIAbilityContext, ['ohos.permission.APP_TRACKING_CONSENT'])
.then((data: Array<abilityAccessCtrl.GrantStatus>) => {
if (data[0] === -1) {
hilog.info(0x0000, 'testTag', 'not access');
return;
}
this.rquestOAID();
}).catch((err: BusinessError) => {
hilog.error(0x0000, 'testTag', '%{public}s', `requestPermissionOnSetting err: ${JSON.stringify(err)}`);
})
}
}
在HarmonyOS Next中,获取设备唯一标识需使用@ohos.deviceInfo模块。
通过deviceInfo.getDeviceId()可获取设备标识符,该标识符在设备生命周期内保持唯一。
对于OAID等广告标识符,需使用@ohos.identifier.oaid模块的getOAID()方法获取。
注意:IMEI等敏感信息需系统权限,普通应用无法直接获取。
在HarmonyOS Next中,直接获取IMEI等硬件级设备唯一标识已被严格限制,这是遵循当前隐私保护强化的必然趋势。
对于设备风控场景,推荐使用以下替代方案:
-
OpenHarmony DeviceIdentifier(首选方案) 这是系统提供的标准设备标识符,旨在平衡标识唯一性与用户隐私。其特性包括:
- 重置敏感性:设备恢复出厂设置后标识符会改变。
- 应用独立性:同一设备上不同应用获取的值相同,可用于跨应用协作(需各自声明权限)。
- 权限控制:需要申请
ohos.permission.DISTRIBUTED_DATASYNC权限。
核心代码示例(ArkTS):
import deviceInfo from '@ohos.deviceInfo'; try { let deviceId: string = deviceInfo.deviceId; // 获取DeviceIdentifier console.log('Device ID: ' + deviceId); } catch (err) { console.error('Failed to get device ID. Code: ' + err.code + ', message: ' + err.message); } -
应用级实例标识(AAID) 如果风控逻辑可限定在应用内,可使用
getUdid方法生成一个应用实例唯一的标识符。该标识符:- 在应用卸载重装后会改变。
- 适用于跟踪单应用内的独立实例。
-
结合多维度软硬件信息(非唯一标识) 可安全采集多项非敏感、非唯一的信息进行组合计算,生成一个高概率唯一的设备指纹,例如:
- 设备型号 (
deviceInfo.model) - 系统版本 (
deviceInfo.osFullName) - 屏幕分辨率
- 时区、语言设置
- 设备基础能力列表 (
deviceInfo.capabilities)
注意:此方案生成的标识不具备系统级绝对唯一性,且随设备配置改变可能变化,适用于辅助风险评估而非绝对标识。
- 设备型号 (
总结与建议:
对于HarmonyOS Next的设备风控,应优先采用系统提供的 deviceInfo.deviceId (DeviceIdentifier)。它提供了当前系统环境下最佳的标识能力。请务必在应用的 module.json5 配置文件中声明所需权限,并在应用中向用户清晰说明标识符的用途。
在架构设计时,建议将设备标识与用户账号体系结合,并准备应对标识符因系统重置而变更的情况,以构建更健壮的风控逻辑。


