HarmonyOS Next中关键资产存储操作实战指南

162 阅读7分钟

本文旨在深入探讨华为鸿蒙HarmonyOS Next系统(截止目前 API12)在开发多语言电商平台方面的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。

(一)引言

在上一篇博客中,我们深入了解了HarmonyOS Next系统中Asset Store Kit的基础知识,包括其在关键资产存储和管理方面的重要地位、关键资产存储原理、访问控制机制以及各种关键资产属性等。这些基础知识为我们进一步探索关键资产存储操作奠定了坚实的基础。在本篇博客中,我们将深入实战,详细讲解如何在HarmonyOS Next中进行关键资产的存储操作,包括新增、查询、更新和删除等关键操作,帮助开发者更好地掌握这一重要功能。

(二)新增关键资产

  1. 流程和注意事项

   - 新增关键资产的流程主要包括准备关键资产属性、调用新增接口以及处理可能出现的错误。首先,开发者需要根据业务需求确定关键资产的各项属性,如密码(SECRET)、别名(ALIAS)、访问控制等级(ACCESSIBILITY)等。其中,密码是必选属性,且长度应在1 - 1024字节之间,而别名也是必选属性,用于唯一标识关键资产,其长度为1 - 256字节。在设置属性时,需注意属性的合法性和合理性,例如,访问控制等级应选择合适的值(如开机后可访问、首次解锁后可访问或解锁时可访问)。同时,如果需要在应用卸载时保留关键资产,可设置IS_PERSISTENT属性为true,但需提前申请ohos.permission.STORE_PERSISTENT_DATA权限。

   - 另外,关键资产以业务身份 + 别名作为唯一索引,因此必须保证每条关键资产的别名唯一,否则可能导致新增失败或数据混乱。

  1. 代码示例(ArkTS)

import { asset } from '@kit.AssetStoreKit';

import { util } from '@kit.ArkTS';

import { BusinessError } from '@kit.BasicServicesKit';

function stringToArray(str: string): Uint8Array {

    let textEncoder = new util.TextEncoder();

    return textEncoder.encodeInto(str);

}

// 新增一个关键资产,包含密码和别名等属性

let attr: asset.AssetMap = new Map();

attr.set(asset.Tag.SECRET, stringToArray('newPassword123')); // 假设密码为"newPassword123"

attr.set(asset.Tag.ALIAS, stringToArray('newAssetAlias')); // 设置别名为"newAssetAlias"

attr.set(asset.Tag.ACCESSIBILITY, asset.Accessibility.DEVICE_FIRST_UNLOCKED); // 设置为首次解锁后可访问

try {

    asset.add(attr).then(() => {

        console.info('Key asset added successfully.');

    }).catch((err: BusinessError) => {

        console.error('Failed to add key asset. Code is ${err.code}, message is ${err.message}');

    });

} catch (error) {

    let err = error as BusinessError;

    console.error('Failed to add key asset. Code is ${err.code}, message is ${err.message}');

}

  1. 代码示例(C/C++)

#include <string.h>

#include "asset/asset_api.h"

void AddAsset() {

    static const char *SECRET = "newPassword123";

    static const char *ALIAS = "newAssetAlias";

    Asset_Blob secret = { (uint32_t)(strlen(SECRET)), (uint8_t *)SECRET };

    Asset_Blob alias = { (uint32_t)(strlen(ALIAS)), (uint8_t *)ALIAS };

    Asset_Attr attr[] = {

        {.tag = ASSET_TAG_SECRET,.value.blob = secret },

        {.tag = ASSET_TAG_ALIAS,.value.blob = alias },

        {.tag = ASSET_TAG_ACCESSIBILITY,.value.uint32 = ASSET_ACCESSIBILITY_DEVICE_FIRST_UNLOCKED }

    };

    int32_t ret = OH_Asset_Add(attr, sizeof(attr) / sizeof(attr[0]));

    if (ret == ASSET_SUCCESS) {

        // Asset added successfully.

    } else {

        // Failed to add Asset.

    }

}

(三)查询关键资产

  1. 多种查询方式

   - 按属性查询:可以根据关键资产的各种属性(如别名、访问控制等级等)进行精确查询。例如,通过指定别名来查找特定的关键资产,或者根据访问控制等级筛选出在特定锁屏状态下可访问的关键资产。

   - 分批查询:由于批量查询出的关键资产需要通过IPC通道传输给业务,受IPC缓冲区大小限制,当查询结果可能超过40条时,建议进行分批查询,且每次查询数量不超过40条。分批查询可以通过设置RETURN_OFFSET和RETURN_LIMIT参数来实现,RETURN_OFFSET指定从第几个关键资产开始返回,RETURN_LIMIT指定返回的关键资产数量。

  1. 查询参数含义和用法

|查询参数|含义|用法示例|

|---|---|---|

|ALIAS(别名)|用于唯一标识关键资产的字符串|查询别名为"specificAlias"的关键资产:query.set(asset.Tag.ALIAS, stringToArray('specificAlias'));|

|ACCESSIBILITY(访问控制等级)|基于锁屏状态的访问控制设置|查询首次解锁后可访问的关键资产:query.set(asset.Tag.ACCESSIBILITY, asset.Accessibility.FIRST_UNLOCKED);|

|RETURN_TYPE(查询返回类型)|指定查询返回结果的类型|查询返回所有类型的关键资产:query.set(asset.Tag.RETURN_TYPE, asset.ReturnType.ALL);|

|RETURN_LIMIT(查询返回数量限制)|限制查询返回的关键资产数量|查询最多返回10个关键资产:query.set(asset.Tag.RETURN_LIMIT, 10);|

|RETURN_OFFSET(查询返回偏移量)|指定从第几个关键资产开始返回|从第20个关键资产开始查询,最多返回10个:query.set(asset.Tag.RETURN_OFFSET, 20);|

|RETURN_ORDERED_BY(查询结果排序依据)|按照附属信息排序查询结果|按照DATA_LABEL_NORMAL_1属性排序:query.set(asset.Tag.RETURN_ORDERED_BY, asset.Tag.DATA_LABEL_NORMAL_1);|

  1. 代码示例(根据条件查询关键资产)

import { asset } from '@kit.AssetStoreKit';

import { util } from '@kit.ArkTS';

import { BusinessError } from '@kit.BasicServicesKit';

function stringToArray(str: string): Uint8Array {

    let textEncoder = new util.TextEncoder();

    return textEncoder.encodeInto(str);

}

// 查询别名为"searchAlias"且首次解锁后可访问的关键资产

let query: asset.AssetMap = new Map();

query.set(asset.Tag.ALIAS, stringToArray('searchAlias'));

query.set(asset.Tag.ACCESSIBILITY, asset.Accessibility.FIRST_UNLOCKED);

try {

    let res: Array<asset.AssetMap> = await asset.query(query);

    for (let i = 0; i < res.length; i++) {

        // 处理查询结果

        console.log('Found asset:', res[i]);

    }

} catch (error) {

    let err = error as BusinessError;

    console.error('Failed to query asset. Code is ${err.code}, message is ${err.message}');

}

(四)更新关键资产

  1. 步骤和限制

   - 更新关键资产的步骤包括构建查询条件以确定要更新的关键资产,然后设置要更新的属性值,最后调用更新接口。需要注意的是,更新操作只能更新部分属性,如关键资产明文(SECRET)、普通附属信息(DATA_LABEL_NORMAL_1 - 4等),而对于具有完整性保护的属性(如DATA_LABEL_CRITICAL_1 - 4),写入后不支持更新。同时,查询条件中的别名(ALIAS)是必选属性,用于准确找到要更新的关键资产。

  1. 代码示例(更新关键资产属性)

import { asset } from '@kit.AssetStoreKit';

import { util } from '@kit.ArkTS';

import { BusinessError } from '@kit.BasicServicesKit';

function stringToArray(str: string): Uint8Array {

    let textEncoder = new util.TextEncoder();

    return textEncoder.encodeInto(str);

}

let query: asset.AssetMap = new Map();

query.set(asset.Tag.ALIAS, stringToArray('updateAlias')); // 根据别名找到要更新的关键资产

let attrsToUpdate: asset.AssetMap = new Map();

attrsToUpdate.set(asset.Tag.SECRET, stringToArray('newUpdatedPassword')); // 更新密码

attrsToUpdate.set(asset.Tag.DATA_LABEL_NORMAL_1, stringToArray('newUpdatedInfo')); // 更新普通附属信息

try {

    asset.update(query, attrsToUpdate).then(() => {

        console.info('Key asset updated successfully.');

    }).catch((err: BusinessError) => {

        console.error('Failed to update key asset. Code is ${err.code}, message is ${err.message}');

    });

} catch (error) {

    let err = error as BusinessError;

    console.error('Failed to update key asset. Code is ${err.code}, message is ${err.message}');

}

(五)删除关键资产

  1. 方法和注意点

   - 删除关键资产可以通过指定关键资产的属性(如别名)来确定要删除的目标。如果不指定别名,则会删除多条符合其他条件(如果有设置)的关键资产。在执行删除操作时,需要谨慎操作,确保删除的是正确的关键资产,因为一旦删除,数据将无法恢复。

  1. 代码示例(删除指定关键资产)

import { asset } from '@kit.AssetStoreKit';

import { util } from '@kit.ArkTS';

import { BusinessError } from '@kit.BasicServicesKit';

function stringToArray(str: string): Uint8Array {

    let textEncoder = new util.TextEncoder();

    return textEncoder.encodeInto(str);

}

let query: asset.AssetMap = new Map();

query.set(asset.Tag.ALIAS, stringToArray('deleteAlias')); // 指定要删除的关键资产的别名

try {

    asset.remove(query).then(() => {

        console.info('Key asset deleted successfully.');

    }).catch((err: BusinessError) => {

        console.error('Failed to delete key asset. Code is ${err.code}, message is ${err.message}');

    });

} catch (error) {

    let err = error as BusinessError;

    console.error('Failed to delete key asset. Code is ${err.code}, message is ${err.message}');

}

(六)总结与实践建议

  1. 关键资产存储操作要点总结

   - 新增关键资产时要确保属性设置正确且别名唯一,注意密码长度和权限要求。查询关键资产时要根据需求选择合适的查询方式和参数,合理利用分批查询避免IPC缓冲区问题。更新关键资产时需明确可更新的属性范围,通过别名准确定位要更新的资产。删除关键资产时要谨慎确认删除目标,避免误删重要数据。

  1. 实际应用建议

   - 在实际应用开发中,首先要根据业务场景规划好关键资产的结构和属性设置。例如,对于高安全性需求的金融类应用,应严格设置访问控制等级和密码策略,定期更新密码等关键资产。在进行查询操作时,尽量优化查询条件,减少不必要的查询开销,提高性能。对于更新和删除操作,要做好数据备份和日志记录,以便在出现问题时能够追溯和恢复数据。同时,要密切关注HarmonyOS Next系统的更新和优化,及时调整应用中的关键资产存储操作,以适应新的系统特性和安全要求。