# Guideline 2.5.4 被拒：后台模式怎么处理

> Apple 会拒绝声明了却没有功能使用的后台模式。删掉这个键，或者把声音、定位、通话功能演示给审核员看。

原始页面：[Guideline 2.5.4 被拒：后台模式怎么处理](https://devoria.fr/zh-hans/blog/guideline-2-5-4-background-mode-rejection)
作者：[Mehdi Azizi](https://devoria.fr/zh-hans/mehdi-azizi)
发布：2026-11-04
内容最后修订：2026-11-04


Guideline 2.5.4 规定，后台模式只能用于它们的预定用途：音频、定位、VoIP 通话、任务收尾、本地通知。如果你的 Info.plist 声明了其中某个模式，而审核员找不到任何需要它的功能，就会被拒。**没有功能用到就删掉这个键，否则就让审核员在三十秒内看到这个功能。**

我用 Expo 发布自己的 iOS 应用。Solys 是我做的小游戏闹钟，它声明了 audio 模式：我删过一次，后来又因为另一个原因加了回来。这篇指南依据的是 Apple 的原文、其他开发者公开的被拒案例，以及我自己的项目。想了解各种被拒原因的全貌，可以看[Apple 为什么拒绝你的应用](https://devoria.fr/zh-hans/blog/apple-app-rejection-reasons-real-cases)。

## Guideline 2.5.4 说了什么？

这条规则只有一句话，位于 [App Review Guidelines](https://developer.apple.com/app-store/review/guidelines/#2.5.4) 第 2 节「Performance」的 2.5「Software Requirements」部分：“Multitasking apps may only use background services for their intended purposes: VoIP, audio playback, location, task completion, local notifications, etc.”

说白了：后台服务只能用来做它本来该做的事。所以被拒标题是“Guideline 2.5.4 - Performance - Software Requirements”。

默认情况下，应用进入后台就会被挂起。想继续运行，就要在 Info.plist 的 `UIBackgroundModes` 键里声明一个或多个模式。[Apple 关于后台模式的文档](https://developer.apple.com/documentation/xcode/configuring-background-execution-modes)要求出于电量考虑谨慎使用，有其他方案时优先用其他方案。**每声明一个模式，就是一个审核员可以核实的承诺。**

## 后台模式及其预定用途

| 模式                  | 键                    | 预定用途            |
| --------------------- | --------------------- | ------------------- |
| 音频、AirPlay、画中画 | `audio`               | 后台可听见的声音    |
| 定位                  | `location`            | 持续定位            |
| VoIP                  | `voip`                | 配合 CallKit 的通话 |
| 后台获取              | `fetch`               | 定期获取网络内容    |
| 后台处理              | `processing`          | 计划任务            |
| 远程通知              | `remote-notification` | 推送新内容          |

这张表总结自 Apple 的文档页面。在论坛公开的被拒案例里，最常出现的是 `audio`、`location` 和 `voip`。

## 2.5.4 被拒消息是什么意思？

消息里会点名出问题的模式。下面是开发者在 Apple 论坛上公开的两个例子：

- **音频**：“Your app still declares support for audio in the UIBackgroundModes key in your Info.plist but did not include features that require persistent audio.” 后文说明，`audio` 键是给在后台播放可听内容的应用用的，比如音乐播放器。它给出两条出路：加上这类内容，或者删掉这个键（[论坛帖子](https://developer.apple.com/forums/thread/95216)）。
- **定位**：在一个 [2024 年 12 月的帖子](https://developer.apple.com/forums/thread/771202)里，Apple 除了员工追踪之外，没找到任何需要持续定位的功能，并表示仅这一个用途并不合适。

我的理解是：**审核员不看你的代码，他找的是功能。** 他得能启动这个功能，把应用切到后台，然后确认它还在运行。

反过来的情况也有。在一个 [2026 年 5 月的帖子](https://developer.apple.com/forums/thread/826849)里，一款朗读应用确实在用 `audio` 模式，却被拒了好几次：审核员没能触发声音。另一位开发者在帖子里说，他认为是附上一段视频才让他的问题得到解决。这只是个人经验，不是 Apple 的规定。

## 你没加过这个键，它是从哪来的？

在 Expo 里，Info.plist 是由配置插件在 prebuild 时填写的。**所以一个后台模式可能在你没决定的情况下就进了你的二进制文件。**

### expo-audio 插件的默认设置

[expo-audio 文档](https://docs.expo.dev/versions/latest/sdk/audio/)写得很清楚：`enableBackgroundPlayback` 选项默认是 `true`，在 iOS 上会添加 `audio` 模式。所以只要用简写形式 `"expo-audio"` 声明插件，就等于声明了这个模式。

我在 TradaZen 首次提交前复查时就发现了这个问题：前台只有简短的界面音效，但插件是用简写形式声明的。修复只需改 `app.json`：

```json
{
  "expo": {
    "plugins": [["expo-audio", { "enableBackgroundPlayback": false }]]
  }
}
```

其他包也会用各自的方式添加模式。[expo-location](https://docs.expo.dev/versions/latest/sdk/location/) 的 `isIosBackgroundLocationEnabled` 选项只在你开启时才添加 `location`。而 [expo-background-task](https://docs.expo.dev/versions/latest/sdk/background-task/) 只要安装了，就会在 prebuild 时添加 `processing`。

### 保留旧键的 ios/ 文件夹

第二个坑，我在 2026 年 7 月的 Solys 上踩过。我已经从 `app.json` 里删掉了 `audio`，但这个键还留在之前生成的 `ios/Solys/Info.plist` 里。不带 `--clean` 的 prebuild 会修改这个项目而不是重新生成，插件只会添加键，从不删除。本地构建就会把它打包进去。当 `ios/` 被 git 忽略时，云端的 EAS 构建会从全新的 prebuild 开始，我就是这种情况。

每次构建前，我都会检查真正会打包进去的内容：

```bash
npx expo config --type introspect --json | grep -o '"UIBackgroundModes":\[[^]]*\]'
npx expo prebuild --clean --platform ios
```

第一条列出 prebuild 将写入 Info.plist 的模式。第二条会删除 `ios/` 文件夹，为本地构建重新生成原生项目。在 Solys 上，第一条输出 `"UIBackgroundModes":["audio"]`，在 TradaZen 上什么都没有：两者都符合预期。

添加或删除模式会修改 Info.plist，也就是修改二进制文件：**必须重新构建，远程更新不够。** [EAS Update 文档](https://docs.expo.dev/eas-update/introduction/)把这类改动归入需要新二进制文件的情况，和 [ITMS-90683](https://devoria.fr/zh-hans/blog/itms-90683-missing-purpose-string-expo) 一样。

## Solys：声明了 audio 模式，而且有真正的理由

Solys 是闹钟，但 `audio` 模式不是用来响铃的：**铃声走的是 AlarmKit**，即 Apple 从 iOS 26 起提供的闹钟服务（[AlarmKit 文档](https://developer.apple.com/documentation/alarmkit)）。响铃的是系统，即使在静音模式下也会响，而不是应用本身。

这个键的经历如下，因为推理过程比那一行配置更重要：

1. **2026 年 7 月底，我把它删了。** 当时没有任何东西在后台播放声音：小游戏的音效都在前台，闹钟也不依赖应用。
2. **两天后，我又把它加了回来**，因为加了夜间监听功能。这个选项用麦克风录下你夜里的声音，并在 iPhone 上本地分析。锁屏时录音必须继续，而 expo-audio 文档说明，后台录音选项同样会添加 `audio` 模式。

理由的性质变了：**这个模式是用来录音的，不是用来播放的。** 应用里能看到三道保护措施：

- 监听是默认关闭的选项，可以在设置或睡前流程里开启；
- 它有单独的同意界面，这是 [2.5.14 条](https://developer.apple.com/app-store/review/guidelines/#2.5.14)对所有录音的要求，而且数据不会离开手机；
- 麦克风会在闹钟响前十分钟关闭，让监听和铃声永远不会互相干扰。

我没法保证审核员每次都会接受这个声明。但每一项我都能说清楚它的用途，以及在哪里能看到。

### 让应用保持唤醒的闹钟

在 AlarmKit 之前，第三方闹钟应用没法像 Apple 闹钟那样响铃。于是一些库会让应用一直保持唤醒：Flutter 包 [alarm2](https://pub.dev/packages/alarm2) 的文档描述了一个一直运行到闹钟响起的静音音频播放器。可是静音的声音什么也听不到。**从 iOS 26 起，AlarmKit 让这种绕路做法不再必要。**

## 保留还是删除：决策表

| 你的情况       | 怎么做                  |
| -------------- | ----------------------- |
| 前台的简短音效 | 删除 `audio`            |
| 音乐或有声书   | 保留，并演示出来        |
| 长时间录音     | 保留 + 用户同意         |
| 闹钟或计时器   | AlarmKit（iOS 26）      |
| 偶尔需要定位   | 重大位置变化服务        |
| 不紧急的同步   | `fetch` 或 `processing` |
| 语音或视频通话 | `voip` 配合 CallKit     |

关于定位，Apple 文档把重大位置变化服务列为 `location` 模式的替代方案。

## 2.5 的其他条款：2.5.1 和 2.5.2

### 2.5.1：只用公开 API，框架各司其职

“Apps may only use public APIs and must run on the currently shipping OS.” 应用只能用公开 API，要能在当前系统版本上运行，并放弃已弃用的内容。和 2.5.4 一样，每个框架都要用于它的预定用途，并在描述里说明：HealthKit 用于健康，HomeKit 用于智能家居。如果某个库调用了私有 API，被拒的是你的应用。

### 2.5.2：不能下载改变应用的代码

应用必须在自己的包内自成一体。它不能“download, install, or execute code which introduces or changes features or functionality of the app”。只有教编程的教育类应用有有限的例外，且代码必须对用户完全可见、可修改。

在 Expo 里，这涉及 EAS Update，它的文档提醒更新必须遵守 App Store 规则。**远程更新只用来修 bug，绝不能用来上线审核员没见过的功能。** 与审核相关的修复要走新构建，我在 [guideline 2.1](https://devoria.fr/zh-hans/blog/app-store-guideline-2-1-rejection-fix) 的指南里讲过。

## 怎么回复 2.5.4 被拒？

沟通在你应用的 App Review 部分进行，你在那里[回复 App Review 的消息](https://developer.apple.com/help/app-store-connect/manage-submissions-to-app-review/reply-to-app-review-messages/)。分两种情况：

- **模式没有用处**：删掉它，重新构建，检查 introspect 输出，然后用两句话回复。
- **模式确实服务于某个功能**：回复时写清确切路径并附上短视频，之后每个版本的审核备注里都写上这段说明。

我会用的模板如下，请自行调整（如果你的应用没有闹钟，就删掉关于闹钟的那句）：

```text
Hello,

The "audio" background mode is used only by [feature], an
optional feature that [records / plays] audio while the
device is locked. It is off by default.

How to test:
1. Open [screen] and turn on [feature].
2. Accept the microphone permission if asked.
3. Tap [button], then lock the device.
   [What the reviewer will hear or see.]

Our alarm does not use this mode: it is scheduled with
AlarmKit and rings through the system.

Attached: a short screen recording of these steps.

Best regards,
```

## 提交前的 2.5.4 检查清单

- Expo 的 introspect 输出只包含你想要的模式，而且你能说出每个模式对应的功能。
- 凡是默认会添加模式的插件（比如 expo-audio），都没有用简写形式声明。
- 本地 `ios/` 文件夹里没有残留的旧键，或者你从干净的 prebuild 开始编译。
- 功能能快速触发，不需要隐藏设置，审核备注写明了每个模式的用途和测试方法。
- 所有录音都要求明确同意，并显示可见的指示。关于权限请求的规则，见 [guideline 5.1.1](https://devoria.fr/zh-hans/blog/guideline-5-1-1-app-store-rejection-fix) 的指南。
- 如果是闹钟，铃声走 AlarmKit，而不是由应用播放声音。

## 提交前检查你的材料

[Review Kit](https://devoria.fr/zh-hans/kits/app-review) 汇集了我的提交前检查清单、给测试员的备注模板，以及会审查你项目的 Claude Code skills。想要真人帮你看，可以[和我约一小时](https://devoria.fr/zh-hans/coaching)：我们视频通话，一起看 Apple 的消息和你的 Info.plist。完整流程见[应用被 Apple 拒绝](https://devoria.fr/zh-hans/expertise/app-rejected-by-apple)页面。

正在准备第一次上架？[做一次免费诊断](https://devoria.fr/zh-hans/diagnostic)：它会帮你理清步骤顺序，并发给你我的 Apple 防拒清单。

没人能保证 Apple 会通过你的应用。但一个理由充分的后台模式，三十秒就能讲清楚。

## 常见问题

### “Guideline 2.5.4 - Performance - Software Requirements”是什么意思？

这是 Apple 认为你 Info.plist 里的某个后台模式没有用于预定用途时的被拒标题。消息会点名该模式，并建议你演示使用它的功能，或者删掉这个键。

### 2.5.4 被拒后需要重新构建吗？

如果你删除或修改了模式，需要：这个键在 Info.plist 里，也就是在二进制文件里。如果模式有正当理由，回复确切路径并附上视频可能就够了。

### 能为几个界面音效保留 audio 模式吗？

不能。在前台播放的简短音效不需要它。在 Expo 里，把 expo-audio 插件的 `enableBackgroundPlayback` 设为 `false`。

### 闹钟应用需要 audio 模式吗？

如果用的是 iOS 26 起提供的 AlarmKit，响铃就不需要：闹钟由系统播放。在 Solys 上，`audio` 模式用于夜间监听，在锁屏时录音。

### 我什么都没声明，Apple 为什么还引用 2.5.4？

可能是某个插件替你声明了：expo-audio 默认添加 `audio` 模式，而旧的 `ios/` 文件夹可能保留了你已从配置中删除的键。用 `npx expo config --type introspect` 检查一下。


## 你的项目

[Review Kit](https://devoria.fr/zh-hans/kits/app-review)：我的 App Store 审核清单、我被 Apple 拒审后的修正方案、Google Play 审核清单，以及三个 Claude Code skill。¥369。

[iOS & Android Kit](https://devoria.fr/zh-hans/kits/ios)：用 Claude Code 打造你的 iPhone 和 Android 应用：我自己应用的起步代码、上架商店的完整流程，以及全部工具包。¥739。

[诊断：你离自己的 iPhone 应用还差什么](https://devoria.fr/zh-hans/diagnostic)：7 个问题，60 秒：看清真正阻碍你发布 iPhone 应用的原因，拿到你的 4 步路线和适合你的套件。
