应用开发完了,本地测试跑了几遍,功能都正常,信心满满地提交应用市场。结果第二天收到驳回通知,原因写了一堆:隐私政策未覆盖全部收集行为、权限申请时机不符合规范、第三方 SDK 信息不完整。

这个问题对开发者来说最麻烦的地方,不是改代码本身,而是要把代码实际行为、权限声明、隐私政策、SDK 信息、用户授权时机全部对应起来。本地测试一般看不出来,但真正提审时特别容易暴露。

这篇就讲讲从第一次被驳回,到逐项排查整改,再到重新提审通过的全过程。重点不是介绍规则本身,而是提审前怎么检查、驳回后怎么定位、修改时哪些地方最容易漏。

一、应用能正常运行,不代表一定能过审

先说说为什么本地测试没问题,提审却被驳回。

审核查的不是"应用能不能跑",而是"应用收集了哪些数据、为什么收集、怎么保护、用户知不知道"。你本地测试的时候,自己点来点去,权限弹窗出来了就点同意,隐私政策也知道是自己写的,当然没问题。但审核员看到的是一个刚安装的应用,它一启动就弹一堆权限请求,隐私政策里没写清楚为什么要这些权限,用了哪些 SDK 也没列出来——这在审核眼里就是不合规。

常见的驳回原因就几类:隐私政策内容不完整或与实际行为不一致、敏感权限申请时机太早(启动就申请)、权限用途说明不清楚、第三方 SDK 信息遗漏或不准确。这几类问题本地测试很难暴露,因为你不会从一个"新安装、未授权"的状态去走完整流程。

我第一次被驳回的时候,驳回通知写得比较笼统,只说"隐私合规存在问题"。后来我才学会,收到驳回后第一件事不是急着改代码,而是逐条对照驳回原因,把代码里每一处权限申请、每一条数据收集、每一个 SDK 调用都列出来,和隐私政策、权限声明逐一核对。

二、先把隐私政策和实际代码对一遍

隐私政策是审核检查的第一道关。审核员会把你的隐私政策从头到尾读一遍,然后实际操作应用,看收集的数据和隐私政策里写的是否一致。

我一开始写隐私政策的时候,就是套了个模板,把常见的"收集设备信息、日志信息"列了一遍就提交了。结果审核发现,应用实际用了某个第三方统计 SDK,收集了设备标识和使用数据,但隐私政策里根本没提这个 SDK 的名字和收集的数据类型。

这就是最典型的问题:隐私政策和实际行为不一致。审核员不管你是不是故意的,只要你声明的和实际做的不一样,就是不合规。

我的做法是:把代码里所有用到权限、所有调用 SDK、所有收集用户数据的地方列一个清单,然后对照这个清单逐条检查隐私政策有没有覆盖。重点查这几项:

应用声明了哪些权限,隐私政策里有没有说明每个权限的用途;

第三方 SDK 有哪些,每个 SDK 的名称、提供方、收集的数据类型、用途,隐私政策里有没有写;

有没有收集用户位置、通讯录、相机、麦克风这些敏感信息,隐私政策里有没有说明收集目的和使用方式;

数据存储和删除有没有说明,用户有没有退出账号后删除数据的途径。

这里最容易漏的是第三方 SDK。很多开发者只关注自己代码里申请了什么权限,忽略了引入的 SDK 也会收集数据。但审核不管这些——只要是你的应用里收集的数据,不管是你自己的代码还是第三方 SDK,都必须在隐私政策里说明。

三、权限真正容易出问题的是申请时机

权限声明本身不是最大的问题,真正容易出问题的是申请时机。

HarmonyOS 的权限分普通权限和敏感权限。普通权限在配置文件里声明就行,不需要运行时申请用户授权。敏感权限(比如相机、麦克风、位置、存储)必须在运行时动态申请,而且必须在用户真正需要这个功能的时候才弹授权框。

我之前犯的错误是:应用启动后,在首页的初始化代码里一次性申请了相机、位置、存储三个权限。本地测试的时候觉得"提前申请好了,后面用的时候就不用再弹了",但审核看到的是一个刚打开的应用,什么都没干就弹三个权限请求——这就是典型的"启动即申请敏感权限",直接驳回。

正确的做法是:权限申请绑定到具体业务功能。用户点"拍照"按钮的时候才申请相机权限,用户进入"附近的人"页面的时候才申请位置权限,用户选择保存图片的时候才申请存储权限。用户拒绝了就降级处理,不让用这个功能,但不影响其他功能正常使用。

下面这段代码放在 PermissionManager.ets 里,封装了按业务场景申请权限的逻辑。它在用户点击"拍照"按钮时调用,先检查权限状态,没授权才弹请求,拒绝了就给出降级提示。

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

const PERMISSION_CAMERA = 'ohos.permission.CAMERA';

export class PermissionManager {
  private atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

  async checkPermission(permission: string): Promise<boolean> {
    const tokenId = getContext().applicationInfo.accessTokenId;
    const status = await this.atManager.checkAccessToken(tokenId, permission);
    return status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  }

  async requestCameraForBusiness(businessName: string): Promise<boolean> {
    const granted = await this.checkPermission(PERMISSION_CAMERA);
    if (granted) return true;

    try {
      const result = await this.atManager.requestPermissionsFromUser(
        getContext() as common.UIAbilityContext,
        [PERMISSION_CAMERA]
      );
      const isGranted = result.authResults[0] === 0;
      if (!isGranted) {
        console.warn(`[PermissionManager] camera denied, degrade ${businessName}`);
      }
      return isGranted;
    } catch (e) {
      console.error(`[PermissionManager] request camera failed: ${JSON.stringify(e)}`);
      return false;
    }
  }
}

这段代码要解决的审核问题:权限不是在应用启动时申请,而是在用户触发拍照这个具体业务时才检查和申请;先查权限状态,已授权就直接用,没授权才弹窗;用户拒绝后返回 false,业务层降级处理,不崩溃不阻塞其他功能。

实际运行时要注意:requestPermissionsFromUser 的具体用法和返回值结构需要对照当前 API 版本确认。另外,用户拒绝授权后,不要立刻反复弹窗请求——那样体验很差,审核也会认为你在骚扰用户。正确的做法是降级提示"需要相机权限才能拍照,您可以在设置中开启",让用户自己决定要不要去设置里开。

四、第三方 SDK 也是审核检查的一部分

第三方 SDK 的问题比权限更容易被忽略,因为开发者可能根本没意识到 SDK 里偷偷收集了什么。

审核会检查应用里集成了哪些第三方 SDK,每个 SDK 的名称、提供方、收集的数据类型、用途是什么。这些信息必须在隐私政策里列明。如果隐私政策里没写某个 SDK,但应用里实际集成了,就是不合规。

我的做法是:把项目里所有 build 配置和依赖文件翻一遍,列出所有引入的第三方库。然后逐个查每个 SDK 的隐私说明文档,确认它收集了哪些数据。最后把这些信息整理成清单,和隐私政策逐条对照。

这里最容易踩的坑是:有些 SDK 是通过 AAR 或者间接依赖引入的,你可能根本不知道它在收集数据。比如集成了一个推送 SDK,它可能自带了设备标识收集功能;集成了一个图片加载库,它可能内置了统计模块。这些间接依赖的 SDK 最容易被漏掉。

另外,SDK 的版本也要注意。同一个 SDK 的不同版本,收集的数据可能不一样。升级 SDK 以后要重新核对它的隐私说明,确认隐私政策里的描述还是准确的。

五、收到驳回以后不要直接盲改

收到驳回通知后,最忌讳的就是看到"隐私政策问题"就去改隐私政策,看到"权限问题"就去改权限代码——改完就重新提交,结果又被驳回。

正确的做法是先把驳回原因拆开,逐项定位。驳回通知里通常会写明具体问题,比如"应用启动后立即申请相机权限"或者"隐私政策未包含某某 SDK 的信息"。根据这些描述,回到代码里找对应的位置。

我的排查流程是这样的:先列一个问题清单,把驳回通知里的每条问题都记下来;然后逐条在代码里搜索对应实现——搜权限名、搜 SDK 类名、搜数据收集逻辑;确认问题确实存在后,再制定修改方案;修改完以后,从一个"刚安装、未授权"的全新状态走一遍完整流程,确认权限申请时机和数据收集行为都改对了。

不要漏掉任何一条驳回原因。我之前有一次驳回通知写了三条问题,我改了两条就重新提交了,结果第三条没改,又被驳回一次。浪费了一轮审核时间。

六、重新提审前我会再做一遍这张检查表

重新提交之前,我会做一轮完整的自查。这个检查表是我被驳回几次以后总结出来的:

隐私政策是否覆盖了所有实际收集的数据类型;

每个声明的权限在隐私政策里都有用途说明;

敏感权限是否只在业务触发时申请,不是启动即申请;

用户拒绝权限后,对应功能有降级处理,不影响其他功能;

第三方 SDK 列表完整,每个 SDK 的名称、用途、数据类型都在隐私政策里列明;

从全新安装状态走一遍核心流程,确认没有意外的权限弹窗或数据收集;

权限配置文件里声明的权限和代码里实际申请的权限一致,不多不少。

这个检查表不需要很复杂,关键是每一项都要实际验证,不能凭印象觉得"应该没问题"。我现在每次提审前都会花半小时走一遍这个清单,比提交以后被驳回再改要省时间得多。

应用上架这件事,技术开发只占一半,另一半是合规和审核。把隐私政策、权限申请时机、SDK 信息这几块理清楚,大部分驳回问题都能提前发现。真正麻烦的不是某个 API 怎么调,而是把代码行为和对外声明一一对应起来——这个工作没有捷径,只能逐条核对。

Logo

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

更多推荐