# iOS 开发者证书与描述文件：Expo 签名指南

> 证书证明是谁签名了你的 App，描述文件说明是哪个 App、能装在哪些 iPhone 上。用 Expo 的话，EAS 会帮你创建并续期这两者。

原始页面：[iOS 开发者证书与描述文件：Expo 签名指南](https://devoria.fr/zh-hans/blog/ios-certificate-provisioning-profile-expo)
作者：[Mehdi Azizi](https://devoria.fr/zh-hans/mehdi-azizi)
发布：2026-11-04
内容最后修订：2026-11-04


iOS 开发者证书用来证明是谁签名了你的 App。描述文件（provisioning profile）则把这张证书和某个具体的 App 绑定起来，并说明它可以在哪里运行。**用 Expo 的话，你几乎不用手动制作它们：每次你发起构建，EAS 都会自动创建、保存并续期。**

但搞懂每个文件是干什么的，仍然很有用。哪天构建装不上，或者上传卡住了，正是这些知识能帮你省下一整天。这篇指南会逐一讲解四个要素、它们的有效期、Apple 的各种限制，以及常见错误和对应的解决办法。

我用 Expo 和 EAS 发布自己的 iOS App，其中包括 Solys 和 TradaZen。完整流程见[没有 Mac 也能发布 iOS App](https://devoria.fr/zh-hans/blog/publish-ios-app-without-mac-expo-eas)。这篇我们来拆开签名的“引擎盖”看看。

## 为什么 Apple 要求签名

iOS App 必须签名，才能安装到 iPhone 上，或者上传到 App Store Connect。签名保证 App 来自 Apple 认识的开发者，而且之后没有被任何人改动过。

对 App Store 来说，有个细节可以让你放心。根据 [Apple 技术说明 TN3161](https://developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates)，App Store 会在你上传时检查分发证书是否有效，然后对 App 重新签名，之后 App 就不再依赖你证书的过期时间。**所以你的证书只需要在上传那一刻有效，不需要在 App 的整个生命周期里都有效。**

## 你需要了解的四个要素

[Expo 关于凭据的文档](https://docs.expo.dev/app-signing/app-credentials/)列出了 iOS 的三项：分发证书、描述文件和推送通知密钥。我再加上 App ID，没有它，任何描述文件都不存在。

### 分发证书

这是你作为开发者的签名。[Apple 关于证书的帮助文档](https://developer.apple.com/help/account/certificates/certificates-overview)区分了两类：

- **Apple Development** 用于开发期间在你自己的设备上运行 App。它属于个人。
- **Apple Distribution** 用于分发到指定的测试设备，或上传到 App Store Connect。它属于团队，只有账户持有人或管理员才能创建。

分发证书不针对某个特定的 App：同一张证书可以签名你所有的 App。它配有一把私钥，真正用来签名的就是这把私钥。根据 TN3161，Apple 证书一般自创建之日起有效一年。

### App ID

App ID 在描述文件里标识你的 App。它就是你的 Bundle ID，比如 `com.example.myapp`（虚构示例）。根据 [Apple 的帮助文档](https://developer.apple.com/help/account/identifiers/register-an-app-id)，它还带有允许使用的功能列表：推送通知、App Groups、Sign in with Apple……

在 Expo 里，它对应配置中的 `ios.bundleIdentifier` 字段。**一次定好，别再改**：它在任何地方都必须一致，配置里和 App Store Connect 里都一样。App ID 不会过期。而且根据 [Expo 关于 iOS 功能的文档](https://docs.expo.dev/build-reference/ios-capabilities/)，EAS 每次构建都会把它的功能和你的配置同步。

### 描述文件

描述文件负责把东西连起来。它包含一个 App ID、一张证书，以及（视类型而定）一份允许的设备列表。和你相关的有三种：

- **开发（Development）**：在你已注册的设备上运行测试版 App。
- **Ad hoc**：可以安装到一份指定设备列表上的构建，每台设备用 UDID 标识。这就是 EAS 的“内部分发”。
- **App Store**：用于 App Store Connect 和 TestFlight。[技术说明 TN3125](https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles) 解释说，它不包含任何设备列表。

每个描述文件都有过期时间：Apple 说一般不超过一年，Expo 说是 12 个月。

### 推送通知密钥（APNs）

APNs 密钥允许你的服务器（或 Expo 的服务器）向你的 App 发送通知。它是一个 .p8 文件，只能下载一次：[Apple 不会在你的账户里保留它](https://developer.apple.com/help/account/keys/create-a-private-key)。同一把密钥可以用于你所有的 App，而且[它永远不会过期](https://developer.apple.com/support/expiration/)。

## 汇总表

| 要素               | 用途              | 有效期       | 用 Expo 时由谁管理 |
| ------------------ | ----------------- | ------------ | ------------------ |
| 分发证书           | 签名你的构建      | 一般一年     | EAS，登录后        |
| App ID             | 标识你的 App      | 不过期       | 你，然后是 EAS     |
| App Store 描述文件 | 上传给 Apple      | 最长 12 个月 | EAS                |
| Ad hoc 描述文件    | 安装到你的 iPhone | 最长 12 个月 | EAS 和你的设备     |
| APNs 推送密钥      | 发送通知          | 不过期       | EAS 或你           |
| 免费账户描述文件   | 通过 Xcode 测试   | 7 天         | Xcode，不是 EAS    |

“你，然后是 EAS”：Bundle ID 由你来定，功能由 EAS 处理。“EAS 和你的设备”：每台测试 iPhone 由你注册，描述文件由 EAS 生成。最后一行说的是免费 Apple 账户：根据 [Apple 关于账户的帮助文档](https://developer.apple.com/help/account/basics/about-your-developer-account)，它的描述文件在创建 7 天后过期。

## 你需要知道的 Apple 限制

- **分发证书**：每个账户很少。Apple 帮助文档说每个团队每种分发类型只能有一张，Expo 的表格写的是上限 2 张。记住这条规则：**不要每次构建或每换一台电脑就新建一张证书。**
- **APNs 密钥**：根据 Expo，每个账户最多 2 把。
- **描述文件**：根据 Expo，没有上限。
- **设备**：根据 [Apple 关于设备的帮助文档](https://developer.apple.com/help/account/devices/devices-overview)，每个产品系列每个会员年度最多 100 台。停用设备不会腾出名额。如果你移除了设备，计数会在下一个会员年度开始时重置为 100。

## EAS 帮你做了什么

根据 [Expo 关于托管凭据的页面](https://docs.expo.dev/app-signing/managed-credentials/)，你第一次做 iOS 构建时，它会提议生成缺少的东西。你登录 Apple Developer 账户，EAS 就会创建分发证书、描述文件和推送密钥，并保存在它的服务器上。之后的构建会复用它们。

三个有用的点：

- **你的 Apple 密码只留在你的电脑上。** [Expo 的安全页面](https://docs.expo.dev/app-signing/security/)说明，密码不会发送到它的服务器，存储的凭据也是加密的。
- **`eas credentials` 能让你看到一切**：证书、描述文件、推送密钥。这个命令还可以替换或移除它们。
- **在 EAS 里删除，不等于在 Apple 那边删除。** 想腾出名额，得去 Apple 开发者门户吊销。

你也可以用本地凭据自己掌控：一个 `credentials.json` 文件指向你的证书（.p12）和描述文件（.mobileprovision）。Expo 要求把这些文件加进 `.gitignore`。这和 [Expo App 的 API 密钥](https://devoria.fr/zh-hans/blog/expo-api-secret-key-security)是同一条规则：秘密永远不能进代码仓库。

## 常见错误及解决办法

### 描述文件过期

Ad hoc 构建自带描述文件：一旦过期，App 在你的测试 iPhone 上就打不开了。而在 App Store 上，Expo 确认过期对线上 App 没有任何影响。**解决办法：重新构建一次。** EAS 会生成新的描述文件，或者你自己用 `eas credentials` 来做。然后把新构建重新装到你的设备上。

别和 TestFlight 搞混：TestFlight 构建 90 天后过期，跟你的证书无关。详情见[用 TestFlight 测试你的 iPhone App](https://devoria.fr/zh-hans/blog/testflight-guide-test-iphone-app)。

### 证书过期或被吊销

Apple 说得很清楚：只要你的会员资格有效，已经上架 App Store 的 App 不受影响。但你不能再上传用这张证书签名的构建。已上传但尚未提交审核的构建，如果证书被吊销，可能会被标记为 Invalid Binary。而且[包含已吊销证书的描述文件会失效](https://developer.apple.com/help/account/certificates/revoke-a-certificate)。

**解决办法：通过 `eas credentials` 或在下次构建时创建一张新证书**，然后让 EAS 重新生成描述文件。还有，千万别条件反射地去吊销一张正常工作的证书。

### 设备不在 Ad hoc 描述文件里

安装链接在你这边能用，在某个测试者的 iPhone 上却不行。原因：[Expo 关于内部分发的文档](https://docs.expo.dev/build/internal-distribution/)解释，只有构建时已在描述文件中的设备才能安装 App。

解决办法：

1. 用 `eas device:create` 注册设备。
2. 以交互模式重新构建，并登录你的 Apple 账户，让 EAS 更新描述文件。或者用 `eas build:resign` 给现有构建重新签名，不用全部重新编译。
3. 在持续集成中，非交互模式会复用描述文件但不更新设备列表。加上 `--refresh-ad-hoc-provisioning-profile` 选项。

在新账户或刚续费的账户上，Apple 处理一台新设备可能需要 24 到 72 小时。所以包含它的第一次构建可能会失败：等一等，再重新构建。

### 证书数量达到上限

Apple 拒绝创建新的分发证书。通常是有旧证书还留着：在另一台 Mac 上用 Xcode 创建的，或者由别的构建服务创建的。**如果你有现有证书的 .p12 文件，就复用它。否则，去 Apple 开发者门户吊销不再使用的那张。** 吊销不会影响你已经上线的 App，但会让包含它的描述文件失效。

### “Provisioning profile doesn't include signing certificate”

Xcode 的这条消息意思是：描述文件里没有那张私钥在你电脑上的证书。典型原因：混用了 Xcode 的自动签名和 EAS 的凭据。**只选一个唯一的来源**：要么用托管凭据的 EAS 构建，要么用本地凭据，不要两者混用。

### 吊销密钥后通知中断

如果你吊销了 APNs 密钥，Expo 提醒说，所有使用它的 App 都会收不到通知。创建一把新密钥，用 `eas credentials` 上传。你用户的 Expo Push 令牌不会改变。

### 新增功能后描述文件失效

启用推送通知或 App Groups 这类服务，[会让描述文件失效](https://developer.apple.com/help/account/provisioning-profiles/edit-download-or-delete-profiles)：必须重新生成。用 EAS 的话，每次构建都会同步功能。如果描述文件仍然被拒，可以用 `eas credentials` 生成一个新的。

## 签名之后的下一步

签好名的构建只是其中一步。商店页面、截图、隐私信息和提交审核，都整理在[在 App Store 上发布应用](https://devoria.fr/zh-hans/expertise/publish-an-app-on-the-app-store)里。如果你还没加入开发者计划，先看[Apple 开发者账户](https://devoria.fr/zh-hans/blog/apple-developer-account-price-free-or-99)。想知道我为什么推荐新手用 Expo，读读[用 React Native 和 Expo 做移动 App](https://devoria.fr/zh-hans/expertise/react-native-expo-mobile-app)。

## 如果你正在准备第一次发布

第一次上传前，先做一下[免费诊断](https://devoria.fr/zh-hans/diagnostic)：它会告诉你项目里真正卡住的是什么，并把我的防 Apple 拒审清单发给你。

想把 App 做出来、接入订阅、顺利发布而不用跟签名死磕，[iOS & Android Kit](https://devoria.fr/zh-hans/kits/ios) 按四个步骤带你走完全程，附带我自己 App 的起步代码，按你自己的节奏来。

## 常见问题

### 什么是描述文件（provisioning profile）？

它是允许你的 App 运行或提交给 Apple 的文件。它把 App ID、证书以及（视类型而定）一份设备列表连接起来。App Store 描述文件不含任何设备，Ad hoc 描述文件则列出若干台设备。

### iOS 开发者证书免费吗？

它没有单独的价格：分发证书包含在 Apple Developer Program 里，每年 99 美元。用免费 Apple 账户，Xcode 允许你在最多 3 台设备上测试，但描述文件 7 天后就过期，而且无法发布。

### Apple 分发证书有效期多久？

根据 Apple，一般自创建之日起一年。描述文件最长也是 12 个月。推送通知密钥则永远不会过期。

### 我的分发证书过期了会怎样？

只要你的会员资格有效，已经上架 App Store 的 App 不受任何影响。你只是不能再上传用这张证书签名的新构建。用 EAS 的话，下次构建时或用 `eas credentials` 就能创建一张新证书。

### 创建 iOS 证书需要 Mac 吗？

如果用 EAS，就不需要。你在命令行里登录 Apple 账户，EAS 就会生成证书和描述文件，Windows 和 Linux 上都可以。不用 EAS 的话，传统方法要通过 Mac 上的 Xcode 或钥匙串访问。

### 一个 Ad hoc 描述文件能包含多少台设备？

你的账户每个会员年度最多可以注册 100 台 iPhone，其他每个设备系列也各有同样的额度。停用的设备仍然计数。想让更多人测试，就用 TestFlight。


## 你的项目

[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 步路线和适合你的套件。
