当前位置: 首页 > news >正文

HarmonyOS 6.1.1 通知沙箱铃声:从资源落盘到可复核交付

企业项目要交付的不是一行 sound,而是一条能复核的链路

在企业应用里,自定义通知铃声经常来自后台下载、业务人员上传或租户配置。它与随安装包发布的固定提示音不同:文件何时到达、落在哪个安全区域、是否完整、通知权限是否开启、系统是否接受请求、终端是否真的发声,都可能在不同阶段失败。实施现场如果只留下“调用 publish 成功”的截图,验收人员仍无法回答铃声来自哪里、请求使用了哪个文件、失败后怎样回退,也无法把问题交给运维继续追踪。

HarmonyOS 6.1.1(24) 新特性页在 Beta1 段落说明,Notification Kit 新增支持使用应用沙箱内文件作为通知自定义铃声。官方自定义铃声指南进一步限定:API 24 起支持网络下载或用户生成等非预置音频,目标文件应位于应用 EL1 的files目录或子目录,最终请求值采用uri::{fileUri},路径不能包含..//..。这里需要特别纠正一个容易写错的版本结论:NotificationRequest.sound字段从 API 12 已存在,API 24 增强的是非预置音频进入通知链路,不是这一字段首次出现。

本文站在企业项目实施顾问的角度,只解决一个交付问题:怎样把外部音频从受控资源准备、完整性核对、授权、发布,一直推进到系统可见证据,并把实际发声保留为独立验收项。验证环境是 API 24 模拟器127.0.0.1:5555,不是华为真机。当前已完成构建、安装、EL1 写入、URI、授权、publish 返回和通知中心显示;模拟器日志处于静音提醒路径,实际声音仍待明日华为真机人工核对,所以文章状态只能是“证据待补”。

先把交付物拆成六个检查点

第一项是输入资产。项目必须记录音频来源、版权归属、格式、大小和用途,不能把网上临时下载的声音直接放进生产包。本次样本来自本机系统通知音,只用于技术验证,复制后的article11_notice.wav227372 bytes。这只能证明测试输入固定,不构成产品音频授权建议。

第二项是目标文件。非预置音频不是把resources/rawfile名称直接填进请求,而是先写入当前应用 EL1files目录。实施记录应同时保留目标路径和源、写入、目标三个字节数。只看到文件名而没有长度核对,不能排除写入中断、旧文件尾部残留或拿错环境。

第三项是请求值。fileUri.getUriFromPath()生成的是file://URI,通知请求还要在它前面增加uri::。实施人员需要同时展示二者,避免把“已生成 file URI”和“已形成合法 sound”混为一件事。

第四项是权限。应用是否有通知权限必须在发布前重新检查,不能只依赖首次安装时的假设。第五项是发布和系统可见性:publish Promise 返回只表示通知服务接受了调用,通知中心真实出现才证明用户界面层可见。第六项是听觉结果,它受静音、通知设置、勿扰策略、音量和设备能力影响,不能由前五项代替。

这张运行图把文件状态、沙箱路径、源/目标大小、授权和发布结果放在同一页面。它证明本轮模拟器确实完成了文件准备和请求发布,但页面上的绿色状态仍不是“已经听到声音”的证据。

资源准备要可重复执行,也要能发现脏文件

实施工具最怕第一次成功、第二次留下旧数据。页面每次准备文件都使用WRITE_ONLY | CREATE | TRUNC,目的不是追求代码形式,而是让重复部署和重复验证获得同一结果。若只用创建和写入而不截断,新的音频比旧文件短时,尾部可能残留,大小核对会暴露异常,播放器行为却未必容易解释。

constappContext=uiAbilityContext.getApplicationContext();appContext.area=contextConstant.AreaMode.EL1;consttargetPath=`${appContext.filesDir}/article11_notice.wav`;constsource=awaitresourceManager.getRawFileContent('article11_notice.wav');consttarget=fileIo.openSync(targetPath,fileIo.OpenMode.WRITE_ONLY|fileIo.OpenMode.CREATE|fileIo.OpenMode.TRUNC);letwritten=0;try{written=fileIo.writeSync(target.fd,source.bufferasArrayBuffer);}finally{fileIo.closeSync(target);}

关闭文件句柄放在finally中,是为了把资源回收从成功分支中解耦。写入失败、状态更新失败或后续核对抛错时,句柄仍应关闭。企业项目还应在下载阶段增加最大文件大小、超时、格式白名单和哈希校验;本次 Demo 使用固定本地资源,重点验证 EL1 和通知请求链路,没有伪装成完整下载器。

写入后要立即核对三组数据:源资源长度、writeSync()返回值、stat()读取的目标大小。三者不一致就停止,不生成 URI,也不调用 publish。

consttargetStat=awaitfileIo.stat(targetPath);if(written!==source.byteLength||targetStat.size!==source.byteLength){thrownewError(`写入核对失败:source=${source.byteLength},`+`written=${written}, target=${targetStat.size}`);}

这项检查让实施人员拿到的是可复核数字,而不是一句“文件复制完成”。在批量租户配置场景中,还应把租户、资源版本和内容哈希写入受控配置表,文件名只作为定位信息,不能承担版本身份。

URI 合规检查应在发布前阻断错误请求

目标路径正确并不等于请求字符串正确。页面先调用fileUri.getUriFromPath(targetPath),再拼接uri::,随后检查前缀和路径穿越片段。这个检查不能替代系统权限验证,却能在应用侧提前阻止明显错误输入,并把失败原因保留在页面和日志中。

constconverted=fileUri.getUriFromPath(targetPath);constsound=`uri::${converted}`;constinvalid=!sound.startsWith('uri::')||sound.includes('../')||sound.includes('/..');if(invalid){thrownewError(`sound URI 不合规:${sound}`);}

本轮实际值为uri::file://com.csdn.harmonyos.featuredemos/data/storage/el1/base/files/article11_notice.wav。日志中的 URI 权限检查显示一个 URI、一个有效 URI,通知解析还出现customSound文件描述符。这组证据可以支持“通知服务已消费请求中的沙箱音频资源”,不能扩大成“扬声器已经播放”。

同屏展示 file URI 和NotificationRequest.sound能减少交接误判。运维看到问题时,可以先检查前缀、bundle、EL1 路径和文件名,再进入通知策略排查,而不是从一段业务代码猜测运行值。

授权与发布必须串行,但状态不能互相覆盖

通知权限可能被用户关闭,也可能因设备策略变化。发布前先调用isNotificationEnabled();未启用时请求授权,再次核对结果。只有最终状态为granted才发布。拒绝分支要明确记录“未调用 publish”,否则后台看到没有通知时,会误以为系统吞掉了请求。

constenabled=awaitnotificationManager.isNotificationEnabled();if(!enabled){awaitnotificationManager.requestEnableNotification(uiAbilityContext);}if(!awaitnotificationManager.isNotificationEnabled()){thrownewError('通知权限未授予,未调用 publish');}awaitnotificationManager.publish({id:11014,content:{contentType:notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal:{title:'Article 11 沙箱铃声验证',text:'API 24 · EL1 files · uri::fileUri'}},sound});

固定 ID11014便于重复发布时更新同一通知,适合演示和回归;生产项目应根据业务事件设计稳定 ID,避免不同事件意外覆盖。页面把权限状态、publish 状态和错误信息分别保存,权限失败不能写成发布失败,publish 返回也不能自动把系统可见性或听觉状态改为成功。

系统通知显示是独立验收层

页面显示published后,本轮继续下拉系统通知中心,真实看到标题“Article 11 沙箱铃声验证”和正文API 24 · EL1 files · uri::fileUri。这一步把“应用认为调用结束”和“系统界面真实可见”连接起来,也排除了只在 Demo 内部伪造成功标签的可能。

通知中心截图证明系统展示层已经收到结果,却不能证明当前展示一定伴随声音。实施报告应把“请求服务消费”“通知可见”“实际发声”分成三行,分别记录设备、时间和证据来源。只要听觉一行没有人工核对,就不能签署“铃声生效”。

异常处理要按阶段给出动作,不要只弹失败

资源读取失败时,应检查资源是否随 HAP 打包、文件名大小写是否一致,并停止后续流程。写入失败时,应保留源长度、已写入长度、目标 stat 结果和错误码,删除或覆盖不完整目标,不能让下一次发布继续使用残留文件。URI 失败时,应检查是否真的位于 EL1files,以及字符串是否包含路径穿越片段。

权限拒绝时,不要循环弹授权窗口。页面可以展示前往系统设置的入口,后台任务则应降级为无声通知或业务内消息,并记录本次降级原因。publish 抛出BusinessError时,日志至少包含错误码、消息、通知 ID 和阶段,但不应记录用户上传文件的敏感业务名称。

系统通知不可见时,排查重点转向通知总开关、应用通知设置、通知折叠、设备策略和固定 ID 覆盖。通知可见但没有声音时,才进入声音策略:设备是否静音、通知声音是否开启、勿扰是否生效、音量是否为零,以及系统日志是否走了静音路径。分阶段排查能避免开发、测试和运维围绕同一“没响”反复互相转交。

本轮模拟器日志明确显示isSoundEnable:falsereminderFlags:0No need to remind, isSilence。所以正确结论不是功能失败,也不是铃声已生效,而是通知链路前五层通过,声音执行被当前提醒策略阻止。这个边界必须保留到明日真机复核。

回滚不是删掉 sound,而是恢复可预测通知

企业项目上线自定义铃声前,应保留三档配置:启用沙箱铃声、使用包内预置声音、无声通知。出现文件损坏、授权争议、批量噪声投诉或系统兼容问题时,可以按租户或业务事件回退,而不是紧急发版删除代码。

回滚动作至少包括停止下发新资源、把配置切回已验证的预置方案、清理无引用沙箱文件、保留失败版本元数据,以及重新发布一条可见通知确认基本通道仍正常。回滚后不能只看配置值,还要再次验证通知中心和目标真机。若业务对声音没有强依赖,无声但可见通常比持续失败或重复扰民更可控。

配置变更需要审计。谁上传了音频、谁审批、在哪些租户启用、何时回退、哪个版本生效,都应可查询。对于高优先级告警,还要防止普通运营人员随意替换声音,避免把提示策略变成绕过组织规范的通道。

运维观测要围绕阶段,而不是围绕一条成功率

建议建立文件准备成功率、URI 校验失败率、授权可用率、publish 成功率、系统可见抽检率和真机听觉抽检率。前四项可以通过应用和系统日志持续观测,后两项需要自动化界面检查与人工设备抽检结合。把它们合并成一个“通知成功率”,会掩盖真正的故障位置。

日志字段可包括通知 ID、资源版本、文件大小、哈希摘要、权限状态、发布耗时和错误阶段。URI 如果包含业务敏感信息应脱敏;用户上传的音频内容不得被上传到普通日志平台。沙箱文件还需要生命周期策略,按引用关系或版本保留,不能无限累积。

告警阈值也要分层。URI 校验突然升高通常是配置或路径问题,应该阻止新版本扩散;授权率下降可能来自用户设置变化,适合引导而不是强制;publish 正常但听觉投诉上升,则要检查设备策略、音频响度和使用频率。不同信号对应不同责任人,才能形成有效运维闭环。

一份可以直接进入项目验收表的清单

交付前确认官方版本依据指向 6.1.1(24) Beta1,而不是误写成 Release 段落新增;确认sound字段旧版本边界与 API 24 非预置资源增强已分开说明;确认音频有版权、格式和大小记录;确认目标位于 EL1files;确认写入使用覆盖语义并核对字节数;确认fileUriuri::值均被记录;确认权限拒绝不会继续 publish;确认固定 ID 的覆盖策略符合业务;确认 publish、系统可见和听觉是三项独立结果;确认失败时有降级与回滚;确认日志脱敏和文件清理策略已落地。

本次 Demo 已完成除实际发声外的所有技术项。明日真机验证必须记录设备型号、系统版本、通知声音设置、静音与勿扰状态、媒体及通知音量、第一次发布和同 ID 更新的听觉结果。任何一项环境信息缺失,听到一次声音也不足以形成可复现结论。

多租户项目还要解决资源隔离与版本一致性

如果一个应用服务多个客户或业务组织,不能让所有铃声平铺在同一个目录并依赖原始文件名区分。不同租户可能都上传notice.wav,后写入的文件会覆盖前一个;运维只看到文件名,也无法判断它属于哪个配置版本。更稳妥的目录可以按租户内部标识和资产版本组织,但路径片段必须由应用生成,不能直接接受外部输入。

资源映射表至少保存租户标识、业务事件、资产版本、内容摘要、本地相对路径、审核状态和更新时间。通知触发时先从已发布配置读取资产版本,再解析本地文件;若文件缺失或摘要不一致,立即走默认声音或无声降级,不在业务线程临时下载后阻塞发布。这样同一事件的配置和本地资源有明确对应关系,也能解释“为什么这个租户听到的是上一版”。

缓存更新需要原子切换。新文件先写入临时受控名称,完成大小和哈希核对后再登记为可用版本,最后切换事件配置。不能先改配置再慢慢下载,否则窗口期内请求会指向不存在的文件。旧版本至少保留到新版本通过真机抽检和观察期,随后按引用关系清理,而不是用“保留最近三个文件”这类与业务无关的规则。

租户删除或合同终止时,也要清理对应声音资源和配置记录。删除动作需要审计,并避免误删仍被其他事件引用的共享资产。若产品允许总部模板下发到多个租户,共享的是经过审核的资产版本,不应共享某个租户私有上传的物理路径。

变更窗口内要把技术动作和业务确认排成顺序

上线自定义铃声不适合只安排一次应用发布。实施计划应把客户端版本、策略配置、音频资产和业务启用拆成可控制的四步。先发布具备能力但默认关闭的客户端,确认旧通知行为不受影响;再上传并审核资产,在小范围设备完成落盘和真机播放;随后启用单一低风险事件;最后才扩大租户和事件范围。

每一步都要有暂停条件。客户端基线构建或签名失败时不进入部署;资产核对失败时不允许绑定事件;publish 或系统可见性异常时停止灰度;声音投诉、重复提醒或听觉不一致超过阈值时立即回退策略。暂停不是宣布整个功能失败,而是把问题固定在当前层,避免错误扩散后难以归因。

本次构建使用 unsigned HAP 安装到模拟器,能够证明 ArkTS 编译和模拟器运行链路,但构建日志同时提示没有配置正式signingConfigs。正式交付必须在客户或发布环境使用受控签名完成安装升级测试,不能把模拟器可安装结论写成应用市场或企业分发已经就绪。升级还要验证旧版本留下的沙箱文件是否兼容、是否需要迁移或清理。

变更记录应包括实施人、审批人、客户端版本、策略版本、资产摘要、目标租户、开始和结束时间、验证设备以及回滚点。发生问题后,团队需要根据这些字段还原当时组合,而不是只根据最新后台配置猜测。

真机验证要覆盖策略矩阵,而不是只听一次

“按下发布后听到声音”只能覆盖一格。最小矩阵应包含通知权限开启与关闭、设备正常与静音、勿扰开启与关闭、通知声音音量正常与为零、应用前台与后台、首次通知与同 ID 更新。每个组合分别记录 publish、系统可见和听觉结果,不符合系统策略的组合应得到预期静默,而不是一律追求发声。

还要覆盖资源异常:文件不存在、零字节、格式伪装、大小超过限制、摘要不一致、URI 缺少前缀、路径含穿越片段,以及资产版本已回滚但旧通知仍被更新。测试目标是确认错误在应用侧被阻断并触发降级,不让无效请求进入无限重试。

设备矩阵至少选择项目实际支持的一个低版本边界机型、一个主流机型和一个高分辨率或不同音频硬件机型。若 API 24 是功能最低版本,低于该版本的客户端应走预置声音或静默兼容路径,并通过编译和运行条件保护,不能只在文案上说明“不支持”。

人工听觉记录也需要结构化。测试人员说明环境是否安静、设备距离、音量档位、声音是否完整、是否延迟、是否与预期资产一致,以及连续多次通知是否被系统聚合。对声音质量有严格要求的客户,还要测量时长和响度,避免样本在开发设备正常、在实际终端过轻或失真。

回滚演练要在上线前真实执行一次

纸面回滚方案常在紧急时暴露依赖:配置平台能关闭策略,但客户端仍缓存旧值;资产已经替换,却找不到上一版;固定通知 ID 更新后,通知中心还保留旧内容。上线前应真实执行一次启用、发布、关闭、回退资产和再次发布,记录各阶段系统通知与文件状态。

演练首先把事件从自定义声音切到系统默认,确认新请求不再引用沙箱 URI;随后切回上一资产版本,核对内容摘要和目标文件;再停用整个能力,确认通知仍可见且不会因缺少 sound 阻塞。最后清理无引用测试文件,并验证当前版本文件仍然存在。任何一步需要重新发版才能完成,都应在风险评估中明确恢复时间。

回滚完成不等于事件结束。运维还要统计受影响通知、失败原因、实际降级比例和用户反馈,判断是资产问题、策略问题、系统环境还是代码缺陷。修复版本重新上线时使用新的资产或策略版本,不覆盖原失败记录,保证后续审计能区分两次变更。

小结

API 24 的价值不是让项目多一个字符串参数,而是让下载或用户生成的非预置音频能够在明确约束下进入通知请求。对企业交付而言,真正重要的是把输入资产、EL1 文件、URI、授权、publish、系统可见和实际发声逐层分开,每一层都有证据、错误和回滚动作。

当前模拟器已经证明227372 bytes文件写入 EL1、uri::fileUri合规、通知服务消费请求、固定 ID 发布成功且通知中心可见。由于日志走静音路径,本文没有把这些事实写成“铃声已播放”。保持这条边界,才是可复核交付,而不是为了赶发布把未验证结论补成成功。

附录:HarmonyOS 6.1.1 新特性开发环境与真机验证准入

1. 版本硬基线

本批新特性统一以 HarmonyOS 6.1.1 API 24 为目标版本。项目sourceproject/build-profile.json5必须保持:

{ "compatibleSdkVersion": "6.1.1(24)", "targetSdkVersion": "6.1.1(24)", "runtimeOS": "HarmonyOS" }

开发者不得为了绕过构建错误,把项目静默改为 API 26 或其他版本。版本变化会同时改变 API 声明、兼容设备、文章结论和文章事实范围。

2. 编译环境准入

在 DevEco Studio 的 SDK Manager 中,必须选择与项目一致的 HarmonyOS6.1.1(API 24)SDK。仅有system-image只能启动模拟器,不能证明 ArkTS 项目可以编译。至少应核对以下编译组件:

IDE 配置截图占位,发布前替换为真实截图:插入 DevEco Studio 的SDK Manager页面,画面必须同时显示 HarmonyOS6.1.1、API24与已安装的etsnativetoolchainspreviewer组件。该图只证明 IDE 的 SDK 配置,不证明工程已经编译或特性已经调试成功。

组件作用准入要求
hms/etsArkTS/ETS API 声明与编译目录存在,元数据与 Hvigor 兼容
hms/nativeNative 编译支持目录存在,元数据与 Hvigor 兼容
hms/toolchains编译、签名和设备工具链目录存在,hdc可执行
hms/previewer预览与设计期支持目录存在,版本与 SDK 对齐
openharmony/toolchains设备安装、启动与调试hdc.exe可调用

硬性判定不是“SDK Manager 显示了 API 24”,而是构建已经越过 SDK 扫描并进入CompileArkTS。本项目曾遇到组件metaVersion: 3.1.0与项目自带 Hvigor 扫描器不兼容,最终报00303168 SDK component missing;此时不能进入特性 API 编码和文章结论阶段。

3. 推荐构建链路

当前已验证可用的是 DevEco Studio 内置 Hvigor 与 DevEco JBR,而不是项目自带的旧/不兼容 Hvigor 组合:

$env:DEVECO_SDK_HOME='D:\Program Files\Huawei\DevEco Studio\sdk'$env:JAVA_HOME='D:\Program Files\Huawei\DevEco Studio\jbr'$env:Path="$env:JAVA_HOME\bin;$env:Path"&'D:\Program Files\Huawei\DevEco Studio\tools\hvigor\bin\hvigorw.bat'`--no-daemon--mode module-p module=entry@default-p product=default assembleHap--stacktrace

准入日志必须至少出现:

Finished :entry:default@CompileArkTS Finished :entry:default@PackageHap BUILD SUCCESSFUL

如果失败停在 SDK 扫描、依赖解析或 ArkTS 编译之前,结论只能写“环境未解锁”。不要根据 IDE 能打开项目、预览器能显示页面或旧 HAP 仍能安装,推导新特性 API 可用。

4. HAP 安装与启动环境

安装验证至少记录设备、包名、HAP 来源和结果。当前项目基线如下:

项目要求/已验证值
包名com.csdn.harmonyos.featuredemos
项目 APIcompatibleSdkVersion=6.1.1(24)targetSdkVersion=6.1.1(24)
设备 API与项目兼容范围匹配,当前 API 24
releaseType项目、SDK、设备保持一致,当前为Release
设备形态本批 Demo 以横向 Pad 为主要截图形态;手机需单独复核
HAP 来源当前 SDK 重新构建的产物,不沿用旧 HAP
$hdc='D:\Program Files\Huawei\DevEco Studio\sdk\default\openharmony\toolchains\hdc.exe'&$hdcinstall-r'sourceproject\entry\build\default\outputs\default\entry-default-unsigned.hap'&$hdcshell aastart-a EntryAbility-b com.csdn.harmonyos.featuredemos

install bundle successfully只证明 HAP 与设备的安装条件匹配;start ability successfully只证明应用可以启动。两者均不证明 Map、Camera、Notification 听觉、AI 字幕或通行证识别已经成功。

参考资料

  • HarmonyOS 6.1.1 新增和增强特性:https://developer.huawei.com/consumer/cn/doc/harmonyos-releases/os-new-feature-611
  • 为通知添加自定义铃声:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/notification-customized-ringtone
  • NotificationRequest API:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-inner-notification-notificationrequest
  • fileUri API:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fileuri
http://www.cnnetsun.cn/news/3956738.html

相关文章:

  • Unity跨平台实时画面同步:Socket混合协议与状态同步实战
  • 构建个人项目脚手架:告别一次性脚本,打造可持续开发工作流
  • Buck 电源电感选型实战:4020 封装 1μH 屏蔽电感 MVL4020-1R0M 与 XFL4020-102MEC 参数与电路适配分析
  • STM32多模通信物联网系统设计:Lora、WiFi与GPS集成实践
  • 后缀树:原理、构建与应用详解
  • SpringBoot共享单车定位停放管理系统设计与实践
  • Python数据采集与分析实战:构建本地生活市场机会分析工具
  • 游戏出海场景推荐用什么数据库?阿里云 PolarDB 全球数据库网络 GDN 解析
  • csharp自定义异常与异常设计建议
  • 2024学术写作工具全测评:从文献管理到格式优化
  • 杰理之开了大于15段的EQ功能后卡音变音的问题【篇】
  • 旁挂负载分担组网场景_分析报告
  • 基于STM32与LoRa的物联网环境检测系统:从硬件选型到低功耗设计
  • 类似WorkBuddy的企业Agent有哪些?主流办公AI Agent选型与深度对比
  • SKILL SELF-EVOLUTION — MICROSOFT SKILLOPT PRINCIPLES (TRAIN SKILLS LIKE WEIGHTS)
  • [VirtualLab] VirtualLab Fusion 中的参数耦合
  • 如何免费让Windows资源管理器拥有毛玻璃效果:ExplorerBlurMica终极美化指南
  • 3个专业技巧让OBS Studio直播画面实现电影级质感:免费色彩校正完整指南
  • 【具身智能】VLA大模型和世界模型有什么区别?
  • 化工AI网:构建产业智能中枢,驱动化工行业数字化转型
  • 不会SQL也能改数据库?我用NocoDB把MySQL变成了表格界面
  • FinalBurn Neo终极指南:轻松打造完美街机模拟体验
  • TRAE Work 与 WorkBuddy 选型决策:基于工作流形态与任务组织的深度对比指南
  • 算力租赁,真正稀缺的到底是什么?
  • 革命性iOS激活锁绕过:applera1n一站式解决方案深度解析
  • 企业智能设备运维管理系统:靠飞算 JavaAI,告别 Java 低效搬砖日常
  • Adobe-GenP:Adobe CC全系列软件激活工具使用指南
  • 社交推荐为什么慢?三度人脉查询的性能排查与图数据库实战
  • 电动汽车参与运行备用的能力评估及其仿真分析(Matlab代码实现)
  • FAQPage Schema 机制分析与 AI 引用率实证研究:5 段问答结构化如何撬动 27.8% 的引用增量