ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

AppGallery Connect × Sharp on HarmonyOS 7:多终端商店截图矩阵与本地化素材门禁【鸿蒙心迹】

AppGallery Connect × Sharp on HarmonyOS 7:多终端商店截图矩阵与本地化素材门禁【鸿蒙心迹】 应用包能构建成功不代表发布素材已经准备好。商店截图常见的问题并不复杂分辨率错一档、某个语言少一张、横竖图混放、文件超过限制。麻烦在于这些问题分散在不同目录里人工检查很容易漏。这篇文章用StoreAssetGate演示怎样把 AppGallery Connect 的素材规格转成一段可执行的门禁。文章中的审核页和日志是演示配图不冒充真实 AGC 后台也不虚构已经通过正式审核。规则以官方“Asset Specifications”页面 2026 年 1 月 20 日更新内容为依据提交前仍应复核当前页面。一、发布前最后半小时最容易把素材目录当成普通文件夹代码进入发布分支后团队通常会把注意力放在 HAP、签名和版本号。截图由设计或运营补齐开发者只确认“目录里有图”。等到上传时才发现中文竖图是 1080×1920英文第三张却从设计源稿直接导出了 1170×2532另一张中文横图尺寸正确但 PNG 达到 5.7 MB。这类问题看上去只是素材返工实际上会打断整个发布节奏。更隐蔽的是本地化错位zh-CN有三张竖图en-US只有两张文件名都叫01.png画面里却保留了另一种语言。尺寸检查通过也不能证明语言矩阵完整。官方素材规格页面对 HarmonyOS 手机和平板截图给出了明确约束横图为 16:9、1920×1080数量 35竖图为 9:16、1080×1920数量 35PNG、JPG 或 JPEG 单张最大 5 MB。这里把这几项转成机器可读规则检查范围限定为手机/平板商店截图不擅自扩展到其他终端的素材要求。演示批次编号是ASSET-0055包含zh-CN与en-US两种语言每种语言各三张竖图和三张横图总计 12 张。第一次扫描发现 2 个错误en-US/phone/portrait/03.png为 1170×2532zh-CN/phone/landscape/02.png为 5.7 MB。替换后第二次扫描为12 / 12 PASS。二、规则文件先表达“我们准备发布什么”脚本不应该从目录结构猜业务意图。一个项目只准备竖图和一个项目忘记横图在文件系统里可能完全相同。门禁需要一份清单明确本批次的语言、终端、方向、数量、尺寸、格式和体积上限。这段代码解决什么问题把官方页面中的手机/平板截图要求落成项目级规则避免扫描器自行猜测。exporttypeOrientationportrait|landscapeexportinterfaceScreenshotRule{device:phoneorientation:Orientation width:numberheight:numberminCount:numbermaxCount:numbermaxBytes:numberformats:Arraypng|jpeg}exportconstreleasePlan{batchId:ASSET-0055,locales:[zh-CN,en-US],rules:[{device:phone,orientation:portrait,width:1080,height:1920,minCount:3,maxCount:5,maxBytes:5*1024*1024,formats:[png,jpeg]},{device:phone,orientation:landscape,width:1920,height:1080,minCount:3,maxCount:5,maxBytes:5*1024*1024,formats:[png,jpeg]}]asScreenshotRule[]}为什么把规则写在代码里而不是散落在命令参数中因为它需要跟发布分支一起评审。以后官方规格变化修改记录能说明从哪一版开始调整也能让历史版本继续使用当时的规则。这里把.jpg和.jpeg都归一为jpeg并没有把 WebP 纳入演示清单。官方页面还列出 WebP 的单独体积要求如果项目需要使用应增加独立格式规则不能沿用 PNG/JPEG 的 5 MB 上限。实际项目容易犯的错误是把 5 MB 写成 5,000,000 字节。平台页面通常以 MB 表达脚本采用5 * 1024 * 1024时应在团队内确认口径并保留接近边界的安全余量。演示把 5 MB 视为硬门槛但建议设计导出目标控制在 4.5 MB 以下减少重新编码差异带来的边缘问题。三、Sharp 只负责读证据门禁逻辑留在业务层Sharp 的metadata()可以返回格式、宽高、页数等信息文件体积则从文件系统读取。它不需要修改原图。发布门禁的第一原则是“检查和修复分开”脚本发现 1170×2532 后应阻止提交而不是静默拉伸成 1080×1920。静默修图看起来省事实际会把新的风险带进来。截图中的文字可能被缩放发虚安全区可能被裁掉横竖构图也可能改变。工具可以生成修复建议但最终素材应回到设计源文件重新导出。这段代码解决什么问题读取每张图片的真实格式、尺寸和体积输出稳定的错误码。importsharp,{Metadata}fromsharpimport{stat}fromnode:fs/promisesexportinterfaceAssetEvidence{file:stringformat:stringwidth:numberheight:numberbytes:numbererrors:string[]}exportasyncfunctioninspectAsset(file:string,rule:ScreenshotRule):PromiseAssetEvidence{constmetadata:Metadataawaitsharp(file,{animated:false,limitInputPixels:40_000_000}).metadata()constinfoawaitstat(file)constformatmetadata.formatjpg?jpeg:(metadata.format??)consterrors:string[][]if(!rule.formats.includes(formataspng|jpeg)){errors.push(FORMAT:${format||UNKNOWN})}if(metadata.width!rule.width||metadata.height!rule.height){errors.push(SIZE:${metadata.width}x${metadata.height})}if(info.sizerule.maxBytes){errors.push(BYTES:${info.size})}if((metadata.pages??1)1){errors.push(ANIMATED:${metadata.pages})}return{file,format,width:metadata.width??0,height:metadata.height??0,bytes:info.size,errors}}limitInputPixels是工具自身的防御边界防止异常大图消耗过多内存不是 AppGallery Connect 的素材规格。animated: false只读取静态页面但我们仍检查pages避免动画资源误入截图目录。状态变化很简单文件从PENDING进入READING读取成功后根据errors.length进入PASS或FAIL。读取异常要单独记为UNREADABLE不能等价为尺寸错误。批量任务结束后再汇总否则一个损坏文件抛异常会让后续 11 张图都没有报告。易错点是方向判断。脚本不根据width height猜landscape而是由目录和规则共同决定。如果一张 1920×1080 的图被放进portrait它应该报告与目标规则不匹配而不是被自动移动。DevEco 风格演示图中左侧是scripts/store-asset-gate目录中间显示inspectAsset()右侧模拟器展示AssetAuditPage底部日志对应两条失败记录。图用于解释工程结构不是实际 IDE 截屏。四、真正容易漏的是“矩阵缺口”不是单张图片单张图片全部通过后还要检查目录是否完整。zh-CN/phone/portrait有 3 张en-US/phone/portrait也必须达到计划数量不能因为总目录凑够了 12 张就把某个语言的缺口掩盖掉。目录约定为store-assets/{locale}/phone/{orientation}/。例如中文竖图放在zh-CN/phone/portrait/01.png ... 03.png英文横图放在en-US/phone/landscape/01.png ... 03.png其余两个组合遵循相同规则。文件名使用两位数字是为了让运营、脚本和上传顺序看到同一套排序。门禁还应检查重复序号、非连续序号和隐藏临时文件。03-final-v2.png对人类很熟悉对自动上传流程却容易造成顺序不稳定。这段代码解决什么问题逐个检查语言 × 方向组合的数量和编号防止总数正确但局部缺失。import{readdir}fromnode:fs/promisesimport{join}fromnode:pathinterfaceMatrixResult{key:stringfiles:string[]errors:string[]}exportasyncfunctioninspectMatrix(root:string,locale:string,rule:ScreenshotRule):PromiseMatrixResult{constdirjoin(root,locale,rule.device,rule.orientation)constnames(awaitreaddir(dir)).filter((name:string)/^(0[1-9]|[1-9][0-9])\.(png|jpe?g)$/i.test(name)).sort()consterrors:string[][]if(names.lengthrule.minCount||names.lengthrule.maxCount){errors.push(COUNT:${names.length},EXPECTED:${rule.minCount}-${rule.maxCount})}names.forEach((name:string,index:number){constexpected${String(index1).padStart(2,0)}.if(!name.startsWith(expected)){errors.push(ORDER:${name},EXPECTED_PREFIX:${expected})}})return{key:${locale}/${rule.device}/${rule.orientation},files:names.map((name:string)join(dir,name)),errors}}这段实现故意没有吞掉readdir异常。目录不存在不是“数量为 0”的普通情况而是发布计划没有落地报告中应标成MISSING_DIRECTORY。完整实现可在调用层捕获并归类但不能静默创建空目录后继续通过。实际项目还应核对语言内容。纯脚本难以可靠判断画面中文字属于哪种语言可以在素材旁放置manifest.json记录页面名、语言、来源设计稿版本和导出时间再对文件摘要做绑定。OCR 只能作为辅助提示不能替代设计与运营复核。五、把失败报告做成“能马上返工”的页面门禁页不需要展示几十个图表。AssetAuditPage顶部只放批次、规则日期和总状态中间按语言与方向列出 4 个矩阵底部给出具体文件与修复建议。第一次扫描结果为zh-CN / portrait3/3通过zh-CN / landscape3/3其中02.png为 5.7 MB失败en-US / portrait3/3其中03.png为 1170×2532失败en-US / landscape3/3通过。手机运行图时间为 03:15批次ASSET-0055总计10 / 12 PASS状态BLOCKED。红色标注分别指向错误尺寸与超限体积。它让读者看到门禁结果怎样映射到文件而不是只展示一个漂亮的“审核失败”页面。设计重新导出素材后第二次扫描显示12 / 12 PASS但脚本仍不会声称“审核通过”。它只能证明当前目录满足已编码的素材规则。应用内容合规、隐私声明、截图真实性和其他审核项仍由正式发布流程判断。六、退出码要服务发布流水线也要保留人工确认门禁最终需要给构建流程一个明确结果。演示约定全部通过返回 0规则或素材错误返回 2脚本自身异常返回 3。这样 CI 可以区分“素材不合格”和“检查器坏了”。这段代码解决什么问题把扫描结果收口为报告文件与稳定退出码并确保异常不会误报通过。import{writeFile}fromnode:fs/promisesasyncfunctionmain():Promisevoid{constreportawaitrunAudit(store-assets,releasePlan)awaitwriteFile(build/reports/store-assets-ASSET-0055.json,JSON.stringify(report,null,2),utf8)if(report.internalErrors.length0){process.exitCode3return}if(report.failedAssets0||report.failedMatrices0){process.exitCode2return}process.exitCode0}main().catch((error:Error){console.error([StoreAssetGate] INTERNAL${error.message})process.exitCode3})为什么不直接在第一处错误process.exit(2)因为发布前最怕一轮只修一个问题。完整扫描一次给出两条证据设计可以同时返工减少来回次数。状态上批次从SCANNING进入BLOCKED或READY_FOR_MANUAL_REVIEW即使退出码为 0仍然保留人工确认步骤。脚本需要在package.json或流水线中固定 Sharp 和 Node.js 的运行环境避免不同机器对图片元数据处理不一致。若要接入 Hvigor可在打包前任务中调用脚本但应避免把商店素材强行放进 HAP 资源目录。它们属于发布资产不应增加应用包体。七、诊断页比“全部通过”更值得保留第二次扫描后诊断页记录两项变化1170×2532 → 1080×19205.7 MB → 4.3 MB。矩阵仍是 12 张错误从 2 变为 0状态从BLOCKED变为READY_FOR_MANUAL_REVIEW。这张图与运行页明显不同它展示修复前后、规则快照、报告路径和退出码而不是重复列缩略图。红圈标注用于说明为什么状态改变。报告保留rulesUpdatedAt2026-01-20提醒发布者下一次提审前重新核对官方页面。如果官方规格发生变化旧报告不能自动代表新版本仍然有效。规则文件应带版本或更新时间并让 CI 在规则过期时给出提示而不是自行抓取网页后静默改动门槛。自动更新规则虽然省事却会让同一提交在不同时间得到不同结果。八、把工具停在正确的边界上StoreAssetGate的价值是把可机械判断的内容提前数量、尺寸、方向、格式、体积、命名和语言目录。它不会判断截图是否真实反映应用也不会判断文案是否合规更不会替代 AppGallery Connect 的正式审核。这条边界很重要。工具脚本最容易从“减少低级错误”滑向“替团队做发布决定”。当报告为绿色时最合适的状态名不是APPROVED而是READY_FOR_MANUAL_REVIEW。它说明机器检查已完成接下来仍要核对画面、语言、功能和隐私信息。如果继续扩展我会优先增加三项对manifest.json与图片摘要做绑定为不同终端建立独立规则组在拉取请求中输出差异报告。不会优先加入自动裁切因为自动改变商店画面带来的风险通常高于节省的那几分钟。参考资料华为开发者AppGallery Connect 素材规格页面标注 2026-01-20 更新https://developer.huawei.com/consumer/es/doc/app/agc-help-app-visual-asset-spec-0000002277607976华为开发者华为应用市场上架流程与基础信息设置https://developer.huawei.com/consumer/cn/appgallerySharp 官方文档输入元数据metadata()https://sharp.pixelplumbing.com/api-input/
返回列表