ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

【晨迹相机|20】HarmonyOS ArkTS AppGallery 发布复查实战:核对包名、版本、设备、素材和离线声明

【晨迹相机|20】HarmonyOS ArkTS AppGallery 发布复查实战:核对包名、版本、设备、素材和离线声明

发布前复查不是把 AGC 后台字段重新填一遍,而是把包内配置、入口代码、权限说明、视觉素材和实际运行路径放到同一张表里逐项对齐。晨迹相机这类本地打卡相机应用,看起来功能边界很清楚:启动后进入pages/Index,拍照或录像需要相机权限,录像需要麦克风权限,数据主要落在本地记录里。但一旦进入 AppGallery 发布流程,审核看到的不是开发者脑内的产品边界,而是包名、版本、设备类型、权限、截图、图标、隐私说明、应用介绍和安装启动表现共同组成的证据链。

这篇文章基于D:\huawei\one15的真实源码做一次发布前复查。目标不是讲“怎么点击后台按钮”,而是说明如何从 HarmonyOS 工程里提取可复核信息,避免出现常见的上架不一致:AGC 写了手机和平板,包里却没有平板适配;隐私材料说不采集声音,module.json5却声明了麦克风;截图展示了视频能力,权限原因却只写拍照;应用名、图标、启动页和包内资源不是同一套。发布复查的价值,就在于把这些问题提前挡住。

本文会解决五个具体问题:

  1. 从AppScope/app.json5核对包名、版本、图标和应用名。
  2. 从module.json5核对设备类型、入口 Ability、权限原因和备份能力。
  3. 从EntryAbility.ets核对启动页、系统栏、浅色模式和入口稳定性。
  4. 从资源目录核对封面截图、启动图标和 AGC 素材一致性。
  5. 把发布前复查整理成一张能直接执行的检查表。

一、先把“发布材料”还原成源码证据

发布材料最容易出问题的地方,是它们经常被当作运营文案处理。开发者会先写一个好看的应用介绍,再补截图和关键词;但 AppGallery 审核真正关心的是这些材料是否能被包内实现支撑。晨迹相机的复查应该从源码反推,而不是从文案反推。

源码里可以直接确认的第一组信息来自AppScope/app.json5:

{ "app": { "bundleName": "com.jiaweikan.one15", "vendor": "jiaweikan", "versionCode": 1000000, "versionName": "1.0.0", "icon": "$media:layered_image", "label": "$string:app_name" } }

这段配置给出四个发布字段的源头:包名、开发者标识、版本号和图标引用。AGC 后台里任何包名、应用版本、图标素材或应用名称的填写,都不能脱离这里。尤其是bundleName,它是平台识别应用身份的核心字段;如果后台选错应用,后面的截图、隐私、权限和包体再正确,也会变成另一个应用的材料。

发布复查时我会把这组字段拆成下面的表:

复查项源码证据发布侧含义风险
包名com.jiaweikan.one15AGC 应用、Profile、包体绑定必须一致传错包会导致无法选择或审核材料错位
版本名1.0.0用户可见版本更新说明必须匹配这个版本
版本号1000000平台升级判断低于已上架版本会被拒绝
图标$media:layered_image包内图标入口AGC 图标应与包内视觉一致

这里不需要发明额外能力。晨迹相机的文章、截图和介绍可以讲“本地相机打卡、日历记录、心情与水印”,因为这些能力能从页面和资源里继续验证;不能把它包装成云相册、多人同步、AI 图像识别或在线社区,因为当前源码没有这些链路。

二、设备范围要跟module.json5对齐

HarmonyOS 应用常见的发布风险之一,是设备范围填写过宽。AGC 选择了手机、平板、2in1,包里也声明了这些设备,但页面如果没有适配,审核时仍可能暴露截断、遮挡、系统栏不可读或横竖屏异常。

晨迹相机的module.json5明确声明了目标设备:

{ "module": { "deviceTypes": [ "phone", "tablet", "2in1" ], "pages": "$profile:main_pages", "abilities": [ { "name": "EntryAbility", "srcEntry": "./ets/entryability/EntryAbility.ets", "label": "$string:EntryAbility_label", "startWindowIcon": "$media:startIcon", "startWindowBackground": "$color:start_window_background" } ] } }

这段配置至少带来三条复查任务。

第一,AGC 设备类型不能少于真实包支持,也不能大于实际可验证范围。这里源码声明了phone、tablet和2in1,因此截图材料和发布说明最好覆盖这些形态下不会出问题的关键页面。如果 AGC 只选手机,可能浪费包内已声明的范围;如果页面没有实测平板和 2in1,就不能在介绍里强调“大屏深度适配”。

第二,入口页面必须可达。pages指向$profile:main_pages,而main_pages.json只有一个页面:

{ "src": [ "pages/Index" ] }

这意味着发布复查的启动路径非常明确:安装后启动EntryAbility,加载pages/Index,再由Index.ets组合产品入口。审核人员不需要复杂账号或外部服务才能进入核心流程。发布说明也应该尽量写成“打开即用,本地记录”,而不是要求审核者先配置网络、登录或导入数据。

第三,启动图标和启动背景要一致。startWindowIcon使用$media:startIcon,startWindowBackground使用$color:start_window_background。资源里该颜色是#FBF4EA,与入口 Ability 里设置系统栏背景色保持一致。发布截图如果采用同一套暖色背景,包内启动体验和商店材料会更统一。

三、权限复查要写到“使用场景”而不是只写权限名

权限是 AppGallery 审核最敏感的材料之一。晨迹相机声明了两个权限:

{ "requestPermissions": [ { "name": "ohos.permission.CAMERA", "reason": "$string:camera_permission_reason", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } }, { "name": "ohos.permission.MICROPHONE", "reason": "$string:microphone_permission_reason", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } } ] }

对应的中文原因在string.json中:

{ "string": [ { "name": "camera_permission_reason", "value": "用于拍摄打卡照片和录制打卡视频" }, { "name": "microphone_permission_reason", "value": "用于录制打卡视频中的声音" } ] }

这两段信息决定了隐私政策、权限说明和审核备注的写法。不能只写“需要相机权限”,更不能把麦克风解释成“优化体验”。更稳妥的表达应该是:

权限真实触发场景用户可理解说明不应出现的说法
CAMERA拍摄打卡照片、录制打卡视频用户主动点击拍照或录像时使用后台拍摄、自动识别、持续采集
MICROPHONE录制打卡视频声音仅在录制视频时采集声音持续监听、语音识别、环境分析

如果应用描述里强调“本地打卡相机”,隐私材料就要继续说明照片、视频、心情和水印记录的处理边界。当前源码里没有看到账号、云同步、广告、推送或在线社区能力,发布材料就不要增加这些说法。权限材料的核心原则是:只解释真实功能需要的权限,只覆盖真实运行时会发生的数据行为。

四、入口 Ability 决定启动和系统栏复查点

发布审核不只看配置,也会实际安装启动。晨迹相机的入口能力在EntryAbility.ets:

export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { try { this.context.getApplicationContext().setColorMode( ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT ); } catch (err) { hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err)); } hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); } onWindowStageCreate(windowStage: window.WindowStage): void { AppStorage.setOrCreate<common.UIAbilityContext>('abilityContext', this.context); windowStage.loadContent('pages/Index', (err) => { if (err.code) { hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); return; } const mainWindow = windowStage.getMainWindowSync(); mainWindow.setWindowSystemBarEnable(['status', 'navigation']); mainWindow.setWindowSystemBarProperties({ statusBarColor: '#FBF4EA', statusBarContentColor: '#2A1B0E', navigationBarColor: '#FBF4EA', navigationBarContentColor: '#2A1B0E' }); }); } }

这段代码给发布复查提供了几个明确结论。

首先,应用主动锁定浅色模式。发布材料里如果展示深色模式截图,就需要额外证明深色适配;当前更合理的做法,是截图保持浅色视觉,并在发布复查中确认系统深色模式下不会出现反色、低对比或系统栏不可读。这里代码设置了状态栏和导航栏颜色,背景#FBF4EA与文字#2A1B0E对比明确,适合在手机、平板和 2in1 上检查顶部和底部系统区域。

其次,入口页面失败会记录日志并停止加载。发布前烟测要覆盖安装、启动、进入首页、切换核心 Tab、触发拍照权限、返回、退出和卸载。仅仅能构建 HAP 或 APP 不代表发布可用;如果loadContent('pages/Index')失败,用户看到的就是启动异常。

再次,AppStorage保存了abilityContext。这个上下文被相机服务或数据服务使用时,发布复查要确认没有在后台静默触发敏感能力。对于晨迹相机,合理路径是用户点击拍照或录像后请求权限,而不是启动即申请权限。

五、应用名、图标、启动图和截图必须是一套视觉

源码里label和EntryAbility_label都指向资源字符串,值为“晨迹相机”。图标侧则使用layered_image、startIcon.png和一批页面内素材。发布材料应维持三个一致:

材料源码位置复查方法
应用名称string.json的EntryAbility_labelAGC 名称、截图标题、文章标题一致
包内图标AppScope/app.json5的$media:layered_image检查透明背景、暗色可读性、启动页一致性
启动图标module.json5的$media:startIcon安装启动时与商店图标不冲突
截图素材resources/base/media展示真实页面和真实能力

晨迹相机的资源目录包含img_camera_hero.png、img_camera_preview.png、img_home_daily.png、img_memory_cover.png、img_watermark_life.png等真实业务图片,也包含ic_tab_home.png、ic_tab_camera.png、ic_profile_album.png等功能图标。AGC 截图应该优先来自真实页面或忠实复现的页面状态,而不是用外部模板图代替。原因很简单:截图一旦展示了不存在的入口、活动、云同步或 AI 能力,审核和用户都会认为应用过度宣传。

封面截图也要遵循同一原则。本文发布到 CSDN 草稿时使用当前文章目录的media/cover.png,但 AppGallery 上架材料不能直接拿技术文章封面当应用截图。应用商店截图应展示晨迹相机真实 UI:首页打卡、相机入口、日历记录、心情统计、水印选择或回收站等页面。技术文章封面适合社区内容,商店截图适合产品展示,两者不能混用。

六、备份能力和本地数据声明要一起看

module.json5声明了一个备份扩展能力:

{ "extensionAbilities": [ { "name": "EntryBackupAbility", "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", "type": "backup", "exported": false, "metadata": [ { "name": "ohos.extension.backup", "resource": "$profile:backup_config" } ] } ] }

而backup_config.json中写的是:

{ "allowToBackupRestore": true }

这会影响隐私和数据声明。晨迹相机可以被描述为以本地记录为主,但不能简单写成“不会发生任何备份或恢复相关处理”,因为包内存在备份恢复配置。更准确的复查方式是区分三类数据:

数据类型源码表现发布材料写法
打卡记录页面和数据服务维护本地记录说明用于本机打卡记录展示
拍照/录像权限用户触发拍摄或录像时使用说明权限触发场景和用途
备份恢复allowToBackupRestore: true隐私材料需覆盖系统备份恢复场景

如果后续决定把应用定位为完全本地离线,就要继续检查是否存在网络权限、HTTP 请求、账号、统计 SDK、推送 SDK 或 Web 组件。当前已经看到的module.json5没有声明 INTERNET 权限,这支持“本地为主”的发布描述;但备份能力仍然应纳入材料,而不是忽略。

七、发布前检查不能跳过安装启动烟测

AppGallery 复查最终要落到可执行动作。基于当前源码,晨迹相机的发布前烟测可以写成下面这组步骤:

1. 使用 release 配置构建 HAP 或 APP。 2. 确认包名为 com.jiaweikan.one15,版本为 1.0.0 / 1000000。 3. 安装到目标设备或模拟器,覆盖 phone、tablet、2in1 中实际发布范围。 4. 启动 EntryAbility,确认进入 pages/Index。 5. 检查状态栏和导航栏颜色是否可读。 6. 点击拍照入口,确认只在用户动作后请求 CAMERA。 7. 点击录像入口,确认 MICROPHONE 说明只对应录像声音。 8. 取消授权、取消拍摄、返回首页,确认页面不崩溃。 9. 查看日历、记忆、个人页等核心页面,确认截图展示的能力真实存在。 10. 卸载应用,确认没有异常残留流程阻塞。

这组步骤不需要把所有业务细节测完,但要覆盖审核最关心的稳定性入口:安装、启动、权限、核心功能、返回和卸载。尤其是权限弹窗,必须确认触发时机与材料一致。如果应用一启动就弹相机或麦克风权限,而文案说“仅在拍摄时使用”,这就是材料和行为不一致。

八、把 AGC 字段做成可追溯清单

实际发布时,我建议为每个版本保留一张复查表。晨迹相机这一版可以这样填写:

AGC 字段建议值或证据复查状态
应用名称晨迹相机,来自EntryAbility_label待后台核对
包名com.jiaweikan.one15源码已确认
版本1.0.0/1000000源码已确认
设备类型phone、tablet、2in1包内已声明,需真机或预览验证
权限CAMERA、MICROPHONE源码已声明,需隐私材料覆盖
权限原因拍照/录像、录像声音资源字符串已确认
图标$media:layered_image、startIcon.png需视觉检查透明度和一致性
启动页pages/Index源码已确认,需启动烟测
数据说明本地打卡记录,备份恢复开启需隐私材料同步
网络能力未见 INTERNET 权限不能宣传云能力

这张表的作用是防止发布阶段靠记忆。只要后来改了版本号、权限、设备类型或截图,就必须同步更新这张表。否则很容易出现“包里已经改了,后台没改”或“后台补了新能力,源码没实现”的问题。

九、常见问题和处理方式

问题可能原因处理方式
AGC 无法选择新包包名、证书、Profile 或版本号不匹配先核对bundleName、versionCode、签名 Profile 绑定关系
审核认为权限说明不足权限原因写得太泛按拍照、录像声音等真实场景改写隐私和权限说明
平板截图被退回包声明了 tablet/2in1,但截图或布局未覆盖补充目标设备截图,或缩小发布设备范围
启动页和商店图标不一致layered_image、startIcon、AGC 图标不是同一设计统一图标来源并重新检查亮暗背景
说明中出现云同步或 AI 能力运营文案超过源码事实删除未实现能力,只保留源码可复核功能
深色模式下系统栏不可读应用锁浅色但系统栏/背景没同步检查setWindowSystemBarProperties和页面根背景

这些问题的共同点是:它们通常不是代码编译错误,而是“材料和包内行为不一致”。发布复查的目标就是把这种不一致提前发现。

十、可以直接复用的发布前复查函数

如果团队里有多个 HarmonyOS 应用,可以把发布复查固化成一个轻量脚本或人工清单。下面是一个伪代码版本,表达检查思路:

interface ReleaseProfile { bundleName: string; versionName: string; versionCode: number; deviceTypes: string[]; permissions: string[]; entryPage: string; appLabel: string; } function assertReleaseMaterial(profile: ReleaseProfile): string[] { const problems: string[] = []; if (profile.bundleName.length === 0) { problems.push('缺少 bundleName,无法确认 AGC 应用身份'); } if (profile.versionCode <= 0) { problems.push('versionCode 不合法,可能无法升级发布'); } if (!profile.deviceTypes.includes('phone')) { problems.push('未声明 phone,需要确认发布设备范围'); } if (profile.permissions.includes('ohos.permission.MICROPHONE') && !profile.permissions.includes('ohos.permission.CAMERA')) { problems.push('录像类能力通常需要同时复查相机与麦克风说明'); } if (profile.entryPage !== 'pages/Index') { problems.push('入口页与 main_pages 配置不一致'); } return problems; }

这段代码不是要替代 AGC 后台校验,而是提醒团队把发布复查变成稳定输入。发布前只要能把ReleaseProfile填出来,就能马上发现字段缺失、权限不成对、入口页不一致等基础问题。

十一、验证清单

发布前我会按下面的顺序验证晨迹相机:

验证项方法通过标准
本地构建执行项目构建命令无编译错误,生成目标包
包名版本读取AppScope/app.json5与 AGC 应用和版本一致
入口页面启动EntryAbility正常进入首页,无白屏
权限弹窗手动触发拍照/录像权限只在用户动作后出现
设备适配phone/tablet/2in1 预览或真机无截断、错位、系统栏不可读
图标素材检查 package 图标和 AGC 图标同一设计,非透明风险可控
隐私材料对照权限和备份配置不遗漏 CAMERA、MICROPHONE、备份恢复
截图材料对照真实页面不展示未实现功能

这个清单里有些项可以从源码静态确认,有些必须靠真机或模拟器验证。比如包名版本可以读 JSON,入口页可以读配置,但系统栏可读性、权限弹窗时机、平板布局和卸载表现必须实际运行。

十二、总结

晨迹相机这次 AppGallery 发布复查的核心结论是:源码已经提供了足够清晰的发布证据。AppScope/app.json5给出包名、版本和图标;module.json5给出设备范围、权限、入口 Ability 和备份扩展;EntryAbility.ets给出启动页、浅色模式和系统栏配置;资源目录给出图标、页面图片和截图素材来源。真正需要控制的风险,是不要让 AGC 材料超过这些证据。

更稳的发布方式,是把“应用描述、权限说明、隐私政策、截图、图标、设备范围、版本号”都回到源码逐项核对。这样做虽然比直接填后台慢一点,但能减少审核阶段的返工。发布复查不是最后的形式流程,而是 HarmonyOS 应用从工程代码走向真实用户前的一次一致性校验。

部分内容由AI辅助生成

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进