1. 背景
在HarmonyOS NEXT中,想要获取设备ID,有3种方式
UDID: deviceinfo.udid ,仅限系统应用使用
AAID: aaid.getAAID(),然而卸载APP/恢复设备出厂设置/后会发生变化
OAID:identifier.getOAID,同一台设备上不同的App获取到的OAID值一样,但是用户如果关闭跟踪开关,该应用仅能获取到全0的OAID。且使用该API,需要申请申请广告跟踪权限ohos.permission.APP_TRACKING_CONSENT,触发动态授权弹框,向用户请求授权,用户授权成功后才可获取。
2. 问题
从上述三种方法中我们发现,无法实现 不需要申请动态权限,且App卸载后不变的设备ID。但是天无绝人之路,有一种取巧的办法可以实现。下面是具体办法。
3. 解决办法
在HarmonyOS NEXT中,有一个 ****@ohos.security.asset (关键资产存储服务) ****的API【类似于iOS中的Keychain services】,有一个特殊属性 IS_PERSISTENT,该特性可实现,在应用卸载时保留关键资产,利用该特性,我们可以随机生成一个32位的uuid,存储到ohos.security.asset中。
4. 源码实现
4.1. 封装AssetStore
import {
asset } from '@kit.AssetStoreKit';
import {
util } from '@kit.ArkTS';
import {
BusinessError } from '@kit.BasicServicesKit';
import {
hilog } from '@kit.PerformanceAnalysisKit';
/// AssetStore 操作结果
export interface AssetStoreResult {
isSuccess: boolean;
error?: BusinessError;
data?: string;
}
/// AssetStore query 操作结果
export interface AssetStoreQueryResult {
res?: asset.AssetMap[];
error?: BusinessError;
}
/**
* 基于 @ohos.security.asset 的封装。可以保证『重装/删除应用而不丢失数据』。
* @author Tanranran
* @date 2024/5/14 22:14
* @description
* 关键资产存储服务提供了用户短敏感数据的安全存储及管理能力。
* 其中,短敏感数据可以是密码类(账号/密码)、Token类(应用凭据)、其他关键明文(如银行卡号)等长度较短的用户敏感数据。
* 可在应用卸载时保留数据。需要权限: ohos.permission.STORE_PERSISTENT_DATA。
* 更多API可参考https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-asset-0000001815758836-V5
* 使用例子:
* // 增。
const result = await AssetStore.set('key', 'value');
if (result.isSuccess) {
console.log('asset add succeeded')
}
// 删。
AssetStore.remove('key');
if (result.isSuccess) {
console.log('asset remove succeeded')
}
// 改
const result = await AssetStore.update('key', 'value');
if (result.isSuccess) {
console.log('asset update succeeded')
}
// 读取。
const result = (await AssetStore.get('key'));
if (result.isSuccess) {
console.log('asset get succeeded, value == ', result.data)
}
*/
export class AssetStore {
/**
* 新增数据
* 添加成功,会通过 AppStorage 传值值变更,外部可通过 @StorageProp(key) value: string 观察值变化。
* @param key 要添加的索引
* @param value 要添加的值
* @param isPersistent 在应用卸载时是否需要保留关键资产,默认为 true
* @returns Promise<AssetStoreResult> 表示添加操作的异步结果
*/
public static async set(key: string, value: string, isPersistent: boolean = true): Promise<AssetStoreResult> {
let attr: asset.AssetMap = new Map();
if (canIUse("SystemCapability.Security.Asset")) {
// 关键资产别名,每条关键资产的唯一索引。
// 类型为Uint8Array,长度为1-256字节。
attr.set(asset.Tag.ALIAS, AssetStore.stringToArray(key));
// 关键资产明文。
// 类型为Uint8Array,长度为1-1024字节
attr.set(asset.Tag.SECRET, AssetStore.stringToArray(value));
// 关键资产同步类型>THIS_DEVICE只在本设备进行同步,如仅在本设备还原的备份场景。
attr.set(asset.Tag.SYNC_TYPE, asset.SyncType.THIS_DEVICE);
//枚举,新增关键资产时的冲突(如:别名相同)处理策略。OVERWRITE》抛出异常,由业务进行后续处理。
attr.set(asset.Tag.CONFLICT_RESOLUTION,asset.ConflictResolution.THROW_ERROR)
// 在应用卸载时是否需要保留关键资产。
// 需要权限: ohos.permission.STORE_PERSISTENT_DATA。
// 类型为bool。
if (isPersistent) {
attr.set(asset.Tag.IS_PERSISTENT, isPersistent);
}
}
let result: AssetStoreResult
if ((await AssetStore.has(key