一次 iOS 真机签名 409 的完整排查:证书、设备、描述文件为什么总是"对不上"

0 阅读9分钟

现象:真机运行时报 A device with number 'xxx' already exists on this team,紧接着一串 provisioning profile doesn't include signing certificate / doesn't include the currently selected device / doesn't include the aps-environment entitlement。 折腾了半天,最后发现:设备被手动加到了另一个 Team 里。

本文记录了完整排查路径、Apple 的设备年度规则,以及"证书和设备不在同一个 Team"这类问题的判断与修复方法。 文中截图已做打码处理(团队名、证书名、设备号、日期均已模糊)。


一、现象

在 Xcode 的 Signing & Capabilities 面板点真机运行,红字报错(节选):

There is a problem with the request entity.
A device with number '00008030-XXXXXXXXXXXX' already exists on this team.

Provisioning profile "iOS Team Provisioning Profile: com.example.app" doesn't include signing certificate "Apple Development: <name> (<ID>)".
Provisioning profile "iOS Team Provisioning Profile: com.example.app" doesn't include the currently selected device "iPhone (00008030-XXXXXXXXXXXX)".
Provisioning profile "iOS Team Provisioning Profile: com.example.app" doesn't include the aps-environment entitlement.
No profiles for 'com.example.app' were found.

同时在 Xcode 设置里能看到团队、证书都在,看起来"什么都没问题"。这就是它难排查的地方——每一条报错都只是症状,真正的原因只有一个。


二、背景:iOS 真机签名到底要几样东西

真机跑 App,Apple 要求下面四件套全部对齐,任何一个换了(换电脑、换账号、删证书、换手机)都要重新走一遍。

组成作用归属
证书(Apple Development)证明"你是谁"属于某个 Team,且私钥必须在本机钥匙串
App ID标识这个 App属于某个 Team,Bundle ID 要匹配
设备允许安装到哪台手机注册在某个 Team 下,用 UDID 标识
描述文件(Provisioning Profile)把上面三者绑定在一起由 Team 签发,里面有:App ID + 证书 + 设备列表 + 权限

Xcode 的"自动管理签名"(Automatically manage signing)背后做的其实就是三步:

  1. 找/建一张属于当前选定 Team 的证书
  2. 把连接的手机注册到当前选定 Team 的设备列表
  3. 生成一个包含「证书 + 设备 + App ID + 权限」的描述文件,安装到手机上

关键在于第 2 步:设备必须注册在你签名用的那个 Team 里。注册到别的 Team,这里就永远走不通。


三、报错逐条翻译

报错真实含义
device already exists on this teamXcode 想"新增设备",但 Apple 说这台设备已有记录 → 冲突,流程中断
doesn't include signing certificate描述文件里没有你本机这把证书(证书重建过、或 profile 是旧的)
doesn't include the currently selected device描述文件不包含这台手机
doesn't include the aps-environment entitlement描述文件是通配符(*)的,没有推送权限 → 说明它退而求其次抓了个"凑数"的 profile
No profiles for 'xxx' were found本地一个可用描述文件都没有(清过缓存后常见)

⚠️ 第一条出现后,后面几条都是它的连带伤害:Xcode 在"注册设备"失败后会中断,然后抓一个通配符 profile 凑数,于是又冒出证书/设备/推送三连报错。所以先解决第一条。


四、排查用到的命令(可直接复制)

1. 看本机有哪些"可用身份"(证书 + 私钥)

security find-identity -v -p codesigning

只有"证书 + 私钥"都在的身份才会出现在这里。 列表里没有你的证书,就说明本机签不了——要么证书不在,要么私钥在别的电脑上。

2. 看证书属于哪个 Team

security find-certificate -c "Apple Development: <名字>" -Z
# 或者看全部证书的 OU(Team ID)
security find-certificate -a -p | openssl x509 -noout -subject | grep -o 'OU=[A-Z0-9]*'

3. 看本机装了哪些描述文件、它们属于谁

ls -lt "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"

4. 解码描述文件,确认"四件套"是否对齐

security cms -D -i "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles/<UUID>.mobileprovision" > /tmp/p.plist
plutil -p /tmp/p.plist | grep -E "Name|TeamIdentifier|ProvisionedDevices|aps-environment|application-identifier|ExpirationDate"

输出里要重点看四行:

"application-identifier" => "<TeamID>.com.example.app"     ← App ID 属于哪个 Team
"aps-environment" => "development"                          ← 权限有没有
"ProvisionedDevices" => [ ... 设备 UDID 列表 ... ]          ← 有没有你的手机
"TeamIdentifier" => [ "<TeamID>" ]                          ← 哪个 Team 签的

5. 看工程实际用的是哪个 Team

grep -n "DEVELOPMENT_TEAM" YourApp.xcodeproj/project.pbxproj

⚠️ 这里经常有坑:Debug / Release 两个配置可能是不同的 Team(比如换团队时只在 Xcode 里改了一次),Project 级还可能残留第三个值。Debug 能跑不代表 Release 能打包。

6. 看连接的真机

xcrun devicectl list devices
# 或
xcrun xcdevice list | grep -E "name|identifier"

7. 看 Xcode 里登录了哪些 Team、各自有几台设备

Xcode → Settings → Accounts → 点开对应 Team,会显示 N Provisioned Devices。


五、真凶:设备注册在"哪个 Team"

这是本次排查最关键的发现。同一个 Apple ID 登录了两个 Team,各自设备数完全不同:

Team A(公司 Team):6 台设备

team-company-masked.png

Team B(个人 Team):15 台设备 team-individual-masked.png

而手机只被手动注册进了 Team A,工程的 DEVELOPMENT_TEAM 却指向 Team B。于是:

Xcode 用 Team B 去签名
  → 检查 Team B 的设备列表
  → 没有这台手机(它加在 Team A 里)
  → 尝试注册到 Team B
  → Apple 返回"设备已存在,无法新增"(因为它已经存在于你的账号体系里)
  → Xcode 报 409 并中断
  → 生成不了 profile → 后面 4 条报错全部跟着出现

最反直觉的地方在于报错文案:already exists on this team 中的 "this team" 指的是 Xcode 正在签名的那个 Team,而你手动加设备时很可能加在了另一个 Team。文案不会告诉你"你加错团队了",只会说"已存在",非常容易误判成"Apple 后台有僵尸记录,删不掉"。

怎么快速确认

把这三个值摆在一起对比,不一致就是问题:

1. 工程里的 DEVELOPMENT_TEAM(命令 5)
2. 证书的 OU / TeamIdentifier(命令 2)
3. 手机注册在哪个 Team(Xcode Accounts 里看 "N Provisioned Devices",或 portal 里切 Team 看 Devices)

三个一致 → 自动签名基本能过;有一个不同 → 必然报错。


六、Apple 的设备年度规则:为什么有时候"删不掉"

排查过程中很容易卡在"想删掉那条冲突的设备记录,但只有 Disable 按钮"。这不是权限问题,是 Apple 的设备年度规则:

规则说明
每类设备上限 100 台iPhone/iPad 等各算一类,每个会员年度统计一次
删除名额不返还当年删掉设备,名额也不会释放,要等年度重置
只有"本会员年度内新增"的设备可以删除往年注册的设备只能 Disable,不能 Delete
会员到期/续费后年度重置新年度开始,上一年的设备记录才会变成"可删除"

续费前后的差别

续费到期前(当前年度内):

  • 今年新注册的设备 → 可以 Delete,也可以 Disable
  • 往年注册的设备 → 只能 Disable,Delete 按钮不出现
  • 想"删掉重加"旧设备 → 做不到,只能等年度重置

续费之后(新年度开始):

  • 上一年度的设备记录全部进入可删除状态
  • 可以清掉历史记录,重新注册,避免"设备记录僵住"
  • 100 台的名额也重新计算

所以遇到"设备删不掉"时

  1. 先确认是不是在正确的 Team 页面(多 Team 账号经常切错,公司 Team 里看到的旧设备本来就不能删)
  2. 确认这台设备是不是本年度新增的(portal 列表里有"注册日期"这一列)
  3. 都不是 → 只能 Disable,或者等年度重置后删除
  4. 最快的绕法:不要去删记录,而是让「签名 Team」和「设备所在 Team」对齐(见下一节)

七、证书与设备不一致的五种典型场景

场景表现原因
多 Team 混用证书 Team ≠ 设备 Team手动加设备时选错了 Team,或工程 Team 被改过
证书重建后 profile 未重建doesn't include signing certificateprofile 里记录的是旧证书 ID
证书被吊销0 valid identities found,钥匙串里显示 CSSMERR_TP_CERT_REVOKED同 Team 证书超限(新建自动吊销旧的)、或被人手动 Revoke、或会员状态变更
新设备未进 profiledoesn't include the currently selected device设备是新的,profile 是旧的
Debug/Release Team 不一致模拟器/Debug 正常,Archive 报签名错误只在 Xcode 里改过一次 Team,另一个配置没同步

还有一个隐蔽的:证书在、私钥不在。别的电脑生成的证书下载到本机后,security find-identity 里根本不会出现——因为私钥不在本机。这种只能让生成证书的那台机器导出 .p12,或者直接在本机重建证书。


八、解法(按推荐顺序)

方案一:让 Team 对齐(最优,能保住自动签名)

  1. 确定手机注册在哪个 Team(portal 里切 Team → Devices 查找 UDID)
  2. 把工程的 DEVELOPMENT_TEAM 改成那个 Team(Debug/Release 都要改)
  3. Xcode → Signing → 重新勾 Automatically manage signing → Try Again

Team 对齐后,Xcode 发现"设备已在列表中",就不会再走"注册设备"这一步,409 自然消失,managed profile 自动生成。

方案二:手动 profile(最稳,绕开所有自动流程的坑)

  1. portal → Profiles → + → iOS App Development
  2. 选 App ID、勾当前 Team 的证书、勾目标设备(能勾就行,不用删除记录)
  3. Generate → Download → 双击安装
  4. Xcode → Signing → 取消 Automatically manage signing,改为 Manual,选刚安装的 profile

优点:完全绕开 Xcode 的"注册设备"动作,不受 409 影响。描述文件通常一年有效,到期前重新生成即可。

方案三:清理本地状态(前面都失败时再试)

# 退出 Xcode 后执行
defaults delete com.apple.dt.Xcode DVTDeveloperAccountManagerAppleIDLists
defaults delete com.apple.dt.Xcode IDEProvisioningTeamByIdentifier
rm -rf "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"/*

然后重新登录 Apple ID,让 Xcode 重新拉取团队~设备列表。

⚠️ 两个提醒:

  • 重登基本一定会要双重认证验证码,本地清不掉
  • 清缓存不会删掉 Apple 后台的设备记录,所以只有"本来就是缓存问题"时才有效

关于命令行

xcodebuild -workspace App.xcworkspace -scheme App \
  -destination 'platform=iOS,id=<UDID>' \
  -allowProvisioningUpdates build

注意 -allowProvisioningUpdates 和 -allowProvisioningDeviceRegistration 的区别:

  • 前者:允许更新/生成 profile(不新增设备)
  • 后者:允许把新设备注册到 Team

两个都加时,还是会去注册设备,仍可能撞 409。命令行报 No Accounts 通常不是没登录,而是跑命令的终端拿不到钥匙串里的账号会话(比如在受限环境里执行)。


九、一页速查清单

排查真机签名问题时,按这个顺序走,基本 5 分钟定位:

# ① 有没有可用证书(证书+私钥)
security find-identity -v -p codesigning

# ② 工程用的是哪个 Team(注意 Debug/Release 可能不同)
grep -n "DEVELOPMENT_TEAM" *.xcodeproj/project.pbxproj

# ③ 本地有哪些 profile,解一个看内容
ls -lt "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
security cms -D -i <profile> | plutil -p - | grep -E "TeamIdentifier|ProvisionedDevices|aps-environment|application-identifier"

# ④ 手机 UDID
xcrun devicectl list devices

对照检查:

  • ☐ 证书的 Team = 工程的 DEVELOPMENT_TEAM
  • ☐ 手机的注册 Team = 工程的 DEVELOPMENT_TEAM
  • ☐ profile 里有这台手机
  • ☐ profile 里有当前这把证书
  • ☐ profile 有 aps-environment(用到推送时)
  • ☐ Debug / Release 两个配置的 Team 一致

三句话总结:

  1. already exists on this team 八成是设备加错了 Team,不要一上来就怀疑 Apple 后台有僵尸记录
  2. 设备删不掉通常是年度规则(只有本年度新增的设备可删),不是权限问题
  3. 对齐 Team 能保住自动签名;实在不行用手动 profile,绕开 Xcode 的设备注册逻辑

排查环境:Xcode 26.6 / macOS,双团队(公司 Team + 个人 Team)共用同一个 Apple ID。