提交审核前明明测试得好好的,为什么一到应用市场就被驳回?更让人头疼的是,审核意见往往只有几句话:隐私不合规、功能不可用、权限申请不合理、元数据与实际不符……

别慌。这篇文章不堆政策原文,直接把常见审核意见翻译成“人话”,再告诉你应该查哪里、怎么改,以及如何避免二次驳回。


一、先搞明白:审核员到底在审什么?

很多开发者以为,审核就是“把 App 安装一遍,能打开就算通过”。实际上,应用上架审核至少会看下面几件事:

  1. 应用能不能正常使用:能否安装、启动、登录,核心流程有没有崩溃或卡死。
  2. 用户数据是否安全:有没有过度申请权限、提前采集信息、隐私政策是否完整。
  3. 页面和文案是否真实:应用名称、图标、截图、功能介绍和安装后的内容是否一致。
  4. 内容是否合规:是否包含违规内容、侵权素材、诱导下载、恶意广告等。
  5. 交易方式是否合规:虚拟商品、会员、充值等是否使用了符合要求的支付方式。
  6. 不同设备能否正常显示:手机、平板、折叠屏以及不同系统版本下有没有明显问题。

所以,“我自己的手机运行正常”并不能证明应用符合上架要求。开发者测试关注的是代码能不能跑,审核关注的是一个陌生用户能不能安全、完整、顺畅地使用

下面进入最实用的部分。

一分钟定位:看到审核意见,先查哪里?

审核意见关键词最可能的问题第一检查点
隐私、个人信息、SDK同意前采集或披露不完整首次启动顺序、SDK 初始化、隐私政策
权限与功能无关过度申请或申请过早module.json5、触发权限的页面
无法登录账号、验证码、风控或接口异常审核账号、服务端登录日志
功能不可用崩溃、白屏、空数据或超时Release 包、弱网和全新安装场景
描述与实际不符截图或文案不是当前版本商店资料与最终安装包逐项对照
诱导点击、影响使用广告不可关闭或遮挡内容开屏、插屏、退出和误触场景
购买流程异常商品配置、验单或权益发放失败正式环境完整支付链路
UI 显示异常大屏、大字体或深色模式未适配声明支持的全部设备类型

二、最常见的 10 类驳回原因,以及怎么改

1. 隐私政策不合规:出现频率最高

这是最容易踩坑,也最容易反复被驳回的一类问题。

常见审核意见
  • 隐私政策未说明收集的信息类型和使用目的;
  • 用户同意隐私政策前,应用已经开始采集设备信息;
  • 隐私政策页面打不开,或者链接不是 HTTPS;
  • 应用实际接入了第三方 SDK,但隐私政策中没有披露;
  • 隐私政策中的应用名称、开发者名称与上架信息不一致;
  • 没有提供注销账号或删除个人信息的方式。
为什么会被拒?

举个很常见的例子:应用一启动,就初始化统计、广告或推送 SDK;过了两秒,才弹出隐私政策对话框。虽然用户最后看到了弹窗,但数据采集已经发生了,这种做法仍然可能被判定为“未经同意收集个人信息”。

正确做法

应用首次启动时,先显示隐私说明。只有用户主动同意后,再初始化可能涉及个人信息处理的功能或 SDK。

下面是一个简化的 ArkTS 示例。重点不在弹窗样式,而在执行顺序:

@Entry
@Component
struct Index {
  @State privacyAgreed: boolean = false

  aboutToAppear(): void {
    this.privacyAgreed = this.readPrivacyConsent()

    if (this.privacyAgreed) {
      this.initAfterConsent()
    }
  }

  private initAfterConsent(): void {
    // 用户同意后,再初始化统计、广告、推送等 SDK
    // AnalyticsSDK.init()
    // PushSDK.init()
  }

  private readPrivacyConsent(): boolean {
    // 正式项目可通过 Preferences 持久化保存同意状态
    return false
  }

  build() {
    Column({ space: 16 }) {
      if (!this.privacyAgreed) {
        Text('请阅读《隐私政策》和《用户协议》,了解我们如何处理你的信息。')

        Row({ space: 12 }) {
          Button('不同意')
            .onClick(() => {
              // 可以退出应用,或进入不采集非必要信息的基础模式
            })

          Button('同意并继续')
            .onClick(() => {
              this.privacyAgreed = true
              // savePrivacyConsent(true)
              this.initAfterConsent()
            })
        }
      } else {
        Text('应用主页')
      }
    }
    .padding(24)
  }
}

隐私政策至少要写清楚这些内容:

  • 收集哪些信息;
  • 为什么收集;
  • 在什么场景收集;
  • 保存多长时间;
  • 是否共享给第三方;
  • 用户如何查询、更正、删除个人信息;
  • 用户如何撤回授权、注销账号;
  • 开发者名称和联系方式;
  • 第三方 SDK 的名称、用途、收集信息类型及其隐私政策链接。

特别提醒:“我们非常重视用户隐私”不等于隐私政策。审核看的是具体说明,不是态度表达。


2. 权限申请过多,或者申请时机不对

不少应用刚打开,就连续弹出通知、定位、相机、麦克风、通讯录等授权请求。用户还没看到主页,先被弹窗“轰炸”一遍,审核体验自然不会好。

典型问题
  • 一个计算器应用申请定位权限;
  • 用户还没点击“拍照”,应用启动时就申请相机权限;
  • 只需要大概位置,却申请精确位置;
  • 权限被拒绝后反复弹窗,导致页面无法使用;
  • module.json5 声明了权限,但页面上没有说明使用目的。
整改原则:最小、必要、适时
  • 最小:能不用就不用,能申请低敏感权限就不要申请高敏感权限;
  • 必要:权限必须与当前功能直接相关;
  • 适时:用户主动触发功能时再申请;
  • 可拒绝:非核心权限被拒绝后,应用仍应尽量提供基础功能。

module.json5 中,权限声明可以这样写:

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

对应的原因文案不要只写“用于相机功能”,而要说清使用场景,例如:

{
  "string": [
    {
      "name": "camera_permission_reason",
      "value": "用于扫描二维码和拍摄头像,仅在你主动使用相关功能时调用"
    }
  ]
}

运行时也不要在首页直接申请,而是在用户点击“扫一扫”后再请求:

import { abilityAccessCtrl, common } from '@kit.AbilityKit'

async function requestCameraPermission(context: common.UIAbilityContext) {
  const manager = abilityAccessCtrl.createAtManager()
  const result = await manager.requestPermissionsFromUser(
    context,
    ['ohos.permission.CAMERA']
  )

  const granted = result.authResults.length > 0 && result.authResults[0] === 0

  if (granted) {
    // openScanner()
  } else {
    // 给出说明,并允许用户继续使用不依赖相机的功能
  }
}

不同 HarmonyOS API 版本的接口签名可能有差异,请以项目所用 SDK 的最新文档和类型提示为准。


3. 应用崩溃、白屏、卡死,或者核心功能不可用

这类问题听起来很基础,但在实际审核中非常常见。

开发者自己的测试环境通常具备这些“隐藏条件”:网络稳定、账号有数据、服务器在白名单中、设备型号固定、缓存已经生成。审核设备却是全新环境,这些条件一个都不一定有。

重点排查场景
  • 首次安装后启动;
  • 清除应用数据后重新打开;
  • 弱网、断网、接口超时;
  • 用户拒绝权限;
  • 登录账号没有历史数据;
  • 接口返回空数组、空字符串或缺少字段;
  • Token 过期;
  • 连续快速点击按钮;
  • 从后台恢复应用;
  • 深色模式、字体放大、横竖屏切换。

网络请求一定要处理失败和超时,别让一个接口把整个页面拖成白屏:

import { http } from '@kit.NetworkKit'

async function loadArticleList(): Promise<string> {
  const request = http.createHttp()

  try {
    const response = await request.request(
      'https://example.com/api/articles',
      {
        method: http.RequestMethod.GET,
        connectTimeout: 10000,
        readTimeout: 10000
      }
    )

    if (response.responseCode !== 200) {
      throw new Error(`server status: ${response.responseCode}`)
    }

    return String(response.result)
  } catch (error) {
    // 页面应展示“加载失败,点击重试”,不要一直转圈或直接白屏
    console.error(`loadArticleList failed: ${JSON.stringify(error)}`)
    return '[]'
  } finally {
    request.destroy()
  }
}

审核前建议准备一台“干净设备”或新建测试用户,完全按照普通用户路径走一遍。很多问题只有第一次使用时才会出现。


4. 审核员无法登录,测试账号形同虚设

如果核心功能必须登录,提交审核时通常要提供可用的测试账号。下面几种情况尤其容易翻车:

  • 密码过期或被临时修改;
  • 登录必须接收开发者自己的手机验证码;
  • 账号触发异地登录风控;
  • 账号没有权限,看不到需要审核的功能;
  • 测试服务器只允许公司内网访问;
  • 审核期间服务器正好停机维护。
怎么改?

准备一个长期有效、数据完整、不会触发二次验证的专用审核账号,并在审核备注中写明:

测试账号:[填写专用审核账号]
测试密码:[填写该账号的临时密码]

主要测试路径:
1. 登录后点击底部“服务”;
2. 进入“会员中心”;
3. 点击“体验功能”即可查看完整流程。

说明:该账号无需短信验证码,不会触发设备绑定。

如果应用必须使用验证码登录,可以提供审核专用的固定验证码机制,但必须只对审核账号生效,并做好服务端隔离,不能给正式用户留下安全后门。


5. 应用介绍、截图和实际功能对不上

审核中的“元数据”可以简单理解为:用户在应用市场看到的所有资料,包括名称、副标题、介绍、图标、截图、视频、分类、关键词等。

常见驳回点
  • 截图来自设计稿,实际版本中根本没有这个页面;
  • 介绍写着“完全免费”,应用内却有付费功能;
  • 宣称“官方”“第一”“最好”,但无法提供证明;
  • 手机截图里套了其他品牌手机外框;
  • 截图出现测试数据、测试域名、内部账号或个人手机号;
  • 应用图标、安装后的名称与提交资料不一致;
  • 更新说明只写“修复已知问题”,但实际增加了重要能力或权限。

整改其实不难:**用本次提交的正式安装包重新截图,文案只描述当前已经上线的功能。**没有做完的功能,不要为了宣传效果提前写进去。

一个更可信的应用介绍应该是这样的:

不推荐:
全网最好用的学习软件,永久免费,拥有最先进的 AI 技术!

推荐:
一款帮助用户整理学习笔记和复习计划的工具,支持标签分类、全文搜索、
每日提醒和多设备同步。部分云端功能需要登录后使用。

前者看起来很“会营销”,但容易引出夸大宣传、功能真实性和付费说明等问题;后者反而更清楚、更容易通过审核。


6. 强制登录,或者注销账号藏得太深

如果用户只是浏览公开内容、查看商品或体验不依赖身份的基础功能,一打开应用就强制注册登录,可能带来不必要的合规风险。

更合理的设计是:

  • 基础浏览允许游客使用;
  • 收藏、同步、评论、下单等确实需要身份的功能,再引导登录;
  • 清楚说明登录的必要性;
  • 在常见入口提供账号注销能力;
  • 注销条件、处理时限和结果提示要明确;
  • 不要用“联系客服后人工申请”代替本可以在应用内完成的流程。

可以采用这种交互逻辑:

function openFavorites(isLoggedIn: boolean): void {
  if (!isLoggedIn) {
    // 弹出说明:收藏内容需要绑定账号,以便在不同设备间同步
    // 用户可以选择“去登录”或“暂不登录”
    return
  }

  // router.pushUrl({ url: 'pages/Favorites' })
}

关键点是:不要只告诉用户“必须登录”,还要解释为什么这个功能需要登录


7. 广告影响使用,甚至出现诱导点击

广告不是不能接,但不能让用户分不清哪里是内容、哪里是广告。

下面这些设计比较危险:

  • 开屏广告没有清晰可见的跳过按钮;
  • 关闭按钮特别小,或者点击关闭却跳转广告;
  • 广告遮挡“返回”“提交”等核心操作;
  • 用“领取奖励”诱导用户点击,实际直接打开其他应用;
  • 应用退出时突然弹出广告;
  • 广告内容与应用年龄分级明显不匹配;
  • 隐私政策没有披露广告 SDK 的数据处理情况。

整改时记住三句话:**广告要能识别、能关闭、不误导。**同时检查广告 SDK 的权限、数据采集行为和隐私披露,不要只检查自己写的代码。


8. 会员、充值或虚拟商品的支付方式不合规

课程会员、游戏道具、电子书、付费内容、云端权益等虚拟商品,通常需要按照应用市场规则接入相应的应用内支付能力。常见问题包括:

  • 在应用内引导用户去网页、公众号或其他平台购买;
  • 按钮写“联系客服开通会员”;
  • 商品价格、有效期、自动续费规则没有说清楚;
  • 支付成功后权益不到账;
  • 恢复购买、退款或订单查询流程不可用;
  • 测试环境与正式环境商品配置不一致。

提交审核前,至少完整测试一次:

进入商品页 → 查看价格和协议 → 下单 → 支付 → 服务端验单
→ 发放权益 → 重启应用 → 权益仍然有效 → 可以查询订单

支付逻辑千万不要只相信客户端返回的“成功”。更稳妥的做法是由服务端校验订单状态,再发放会员或虚拟权益,避免丢单和伪造订单。

支付能力和适用范围可能随地区、商品类型及最新政策变化,提交前应再次核对 AppGallery Connect 和对应服务的最新要求。


9. UI 适配有问题:按钮点不到、文字被截断

HarmonyOS 设备形态比较丰富。只在一台直板手机上看起来正常,并不代表平板、折叠屏或大字体模式下也正常。

审核中容易出现的问题包括:

  • 固定宽高导致平板页面缩在左上角;
  • 底部按钮被系统导航区域遮挡;
  • 折叠或旋转后页面状态丢失;
  • 用户把字体调大后,协议勾选框或提交按钮消失;
  • 深色模式下文字和背景颜色几乎一样;
  • 键盘弹出后遮住验证码输入框。

少写死尺寸,多使用自适应布局。例如:

@Component
struct AdaptiveCard {
  build() {
    Column({ space: 12 }) {
      Text('今日学习计划')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .maxLines(2)

      Text('完成 3 个章节,并复习昨天的错题。')
        .fontSize(16)
        .maxLines(4)

      Button('开始学习')
        .width('100%')
    }
    .width('100%')
    .padding(16)
  }
}

审核前至少覆盖:常见手机尺寸、横竖屏、深浅色、大字体、平板或折叠屏中的一种大屏形态。具体范围以应用声明支持的设备类型为准。


10. 安装包、签名、版本号或配置填错

有些应用代码没有任何问题,却倒在了发布配置上。

常见失误
  • 上传了 Debug 包,而不是正式 Release 包;
  • 包名与创建的应用不一致;
  • 签名证书或 Profile 配置错误、过期;
  • 新版本的 versionCode 没有递增;
  • 声明支持的设备类型与实际能力不符;
  • 正式包仍连接测试服务器;
  • Release 构建时资源混淆或裁剪,导致图片、字体丢失;
  • 安装包中包含调试入口、测试账号或内部日志。

提交前可以先做一轮“发布包验收”:

1. 从 Release 流程重新构建安装包;
2. 在未安装旧版本的设备上安装;
3. 再覆盖安装一次,检查升级是否正常;
4. 确认包名、版本号、图标和应用名称;
5. 确认接口全部指向正式环境;
6. 确认日志中没有 Token、手机号等敏感信息;
7. 用最终上传的同一个包完整走一遍核心流程。

最后一条尤其重要。不要测试 A 包、上传 B 包,然后相信“它们应该一样”。


三、审核意见太短,看不懂怎么办?

审核意见经常只有一句话,先别急着改代码,可以按下面四步定位。

第一步:提取四个信息

从审核意见和附件中找到:

  • 出问题的页面;
  • 操作路径;
  • 设备或系统版本;
  • 审核截图、录屏或错误码。

例如:

审核意见:应用存在无法登录的问题。

翻译成人话:
审核员打开应用后,使用你提供的账号,没有完成登录流程。

优先检查:
测试账号 → 验证码 → 风控 → 网络区域 → 服务端日志 → Token 接口。

第二步:按审核路径复现,不要凭感觉猜

使用同一个正式包、同一个测试账号、尽量相同的设备条件,完全按照审核员给出的路径操作。

第三步:同时看客户端和服务端日志

只盯着 UI 很容易误判。登录失败可能不是按钮的问题,而是审核设备触发了服务端风控;页面白屏也可能不是渲染问题,而是接口返回了一个没有兼容的新字段。

第四步:修完后做关联检查

比如因为“相机权限申请过早”被拒,不能只把弹窗挪到下一个页面,还要一起检查:

  • 隐私政策里是否说明相机用途;
  • 权限拒绝后是否还能返回;
  • 二次使用时会不会重复申请;
  • 系统设置中关闭权限后会不会崩溃;
  • module.json5 中是否还残留其他无用权限。

审核整改最怕“只改截图中的一个点”,结果下一次又暴露出同一问题的另一种表现。


四、申诉或重新提交时,备注应该怎么写?

不要只写“已修改,请审核”。审核员不知道你改了什么,也不知道怎么验证。

推荐使用下面这个模板:

问题说明:
上一版本在应用首次启动时提前申请了相机权限。

整改内容:
1. 已移除首页的相机权限申请;
2. 调整为用户点击“扫一扫”后再申请;
3. 增加权限用途说明;
4. 用户拒绝权限后可正常返回首页,不影响其他功能;
5. 已同步更新隐私政策中的权限说明。

验证路径:
首页 → 右上角“扫一扫” → 查看权限用途说明 → 点击“继续”

测试结果:
已在首次安装、拒绝授权、再次授权三种场景下验证通过。

这段备注有三个优点:说明了原因、列出了改动、给出了验证路径。审核员不需要重新“猜谜”。

如果你确认功能符合要求,而审核结果可能源于账号、网络或理解偏差,也可以客观说明证据,不要带情绪:

经复查,审核反馈页面需要先完成资料创建才会展示数据。
我们已在空状态页面增加操作提示,并提供预置数据的审核账号。
测试账号和操作路径如下……

五、提交前 15 分钟自检清单

如果时间紧,至少把下面这张表走一遍。

检查项必查内容
安装启动首次安装、覆盖升级、冷启动无崩溃和白屏
核心功能登录、搜索、提交、支付等主流程可完成
测试账号长期有效,无短信验证、风控和设备限制
隐私弹窗同意前不初始化非必要 SDK,不默认勾选同意
隐私政策名称、主体、权限、SDK、注销方式和联系方式完整
权限只申请必要权限,在功能触发时申请,拒绝后可继续操作
网络异常断网、超时、空数据时有提示和重试入口
元数据名称、图标、截图、介绍与实际版本一致
广告可识别、可关闭、不遮挡、不诱导误触
交易价格和规则清楚,购买、验单、发货、订单查询正常
UI 适配大字体、深色模式、横竖屏及声明支持的设备可用
发布配置Release 包、正式环境、签名、包名、版本号正确
安全无测试后门,无明文密钥,日志不输出敏感信息
注销账号入口可找到,流程可完成,规则说明清楚
审核备注写明账号、功能路径、特殊操作和本次整改点

建议把这张表放进团队的发布流程中,每次提审由开发、测试和产品分别确认。审核不是开发一个人的事:隐私文案可能归法务,商店截图可能归运营,测试账号可能归服务端。只要有一环没对齐,都可能被打回来。


六、几个特别容易被忽略的细节

1. 第三方 SDK 也算你的应用行为

“不是我采集的,是 SDK 自己采集的”通常不能成为免责理由。接入前要看清 SDK 获取了哪些权限、收集了哪些信息、什么时候开始初始化,并在隐私政策中准确披露。

2. 审核通过不代表以后永远没问题

政策会更新,SDK 会升级,服务端功能也会变化。每次发版都应该重新检查隐私、权限、支付和内容,而不是复制上一次的材料直接提交。

3. 删除代码不等于删除权限

你可能已经删掉扫码功能,但 module.json5 中仍然保留相机权限;也可能移除了某个 SDK,却忘了删除它的初始化代码、配置和隐私声明。审核前最好做一次依赖与权限盘点。

4. 截图里出现的内容同样要合规

哪怕应用本身没有问题,如果商店截图里用了未经授权的影视海报、明星照片、品牌 Logo 或用户头像,也可能引发审核或版权问题。

5. 不要频繁提交“碰运气”

同一个问题没有真正解决就反复提交,只会浪费时间。拿到驳回意见后,先完成复现、定位、关联检查和回归测试,再提交新版本。


七、总结:审核通过靠的不是运气,而是发布工程

HarmonyOS 应用被驳回,最常见的原因并不神秘,基本集中在四类:

  • 不能用:崩溃、白屏、登录失败、核心流程走不通;
  • 不透明:隐私政策不完整,用户同意前就采集信息;
  • 不一致:应用介绍、权限用途、截图与真实功能对不上;
  • 不友好:强制登录、频繁要权限、广告误触、异常状态没有提示。

真正有效的解决办法,也不是背审核条款,而是站在一个第一次使用应用的陌生用户角度,把整个流程重新走一遍:

我为什么要给这个权限?不给还能不能用?我的数据去了哪里?页面失败后该怎么办?这个商品到底收多少钱?账号不想用了能不能注销?

如果这些问题都能在应用里得到清楚、诚实、可操作的回答,通过审核通常就不会是一件很玄学的事。

最后提醒一句:应用市场规则、系统 API 和服务能力会持续更新。本文适合用来建立排查思路,正式提交前仍应以 AppGallery Connect 中展示的最新审核要求、HarmonyOS 开发文档以及项目实际目标 API 版本为准。

如果这篇文章帮你少走了一次审核弯路,欢迎点赞、收藏。也可以把你遇到的审核意见发在评论区,我们一起把那句“官方话”翻译成人话。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐