# ITMS-90034 錯誤修正：簽署遺失或無效

> ITMS-90034 代表你的 build 沒有用有效的發佈憑證簽署。先用 codesign 檢查簽署，再用 EAS 重新產生 store build。

原始頁面：[ITMS-90034 錯誤修正：簽署遺失或無效](https://devoria.fr/zh-hant/blog/itms-90034-missing-invalid-signature-fix)
作者：[Mehdi Azizi](https://devoria.fr/zh-hant/mehdi-azizi)
發布日期：2026-11-04
內容最後修訂：2026-11-04


ITMS-90034 會在你把 build 上傳到 App Store Connect 時出現。它的意思是：你的 app，或其中某個元件，沒有用 Apple 的提交憑證簽署，也就是沒有用有效的發佈憑證（distribution certificate）簽署。**修正方法：找出哪個 bundle 簽錯了、為什麼簽錯，然後重新產生一個為 App Store 簽署的 build。**

這篇指南只專注在這個錯誤。如果你對憑證和描述檔還不太熟，先看[iOS 開發者憑證與 provisioning profile](https://devoria.fr/zh-hant/blog/ios-developer-certificate-provisioning-profile-expo)。在這裡，你會看到該怎麼讀錯誤訊息、一張決策表、檢查 IPA 的指令，以及用 EAS 管理的憑證來修正的方法。EAS 的部分，我讀過 EAS CLI 24.10.0 中挑選憑證的程式碼。

## ITMS-90034 錯誤是什麼意思？

這是它的典型樣子，名稱為範例：

> ITMS-90034: Missing or invalid signature. The bundle 'com.example.myapp' at bundle path 'Payload/MyApp.app' is not signed using an Apple submission certificate.

2026 年在 Apple 的論壇上，它也會以「Validation failed (409) Missing or invalid signature」的形式出現，後面接著同樣的文字和「(ID: 90034)」。

「提交憑證」指的就是發佈憑證。[Apple 關於憑證的說明](https://developer.apple.com/help/account/certificates/certificates-overview)寫得很清楚：開發憑證用來在你自己的裝置上執行 app，發佈憑證則用來發佈 app，或上傳到 App Store Connect。

**看清楚訊息裡的路徑：它指出的就是出問題的 bundle。** `Payload/MyApp.app` 指的是 app 本身。以 `.appex` 結尾的路徑指的是擴充功能，例如 widget。以 `.framework` 結尾的路徑指的是內嵌的函式庫。

這不是審查人員的拒絕。驗證是在上傳時或 build 處理期間失敗的，發生在 TestFlight 之前：這個 build 永遠到不了你的測試人員手上。

## 決策表：從錯誤訊息到修正

每一列對應一個線索，你會在錯誤訊息、下一節的指令或 EAS 的日誌中看到。請依序比對：第一個符合的就是你的方向。

| 你看到的現象                | 可能原因             | 修正方式              |
| --------------------------- | -------------------- | --------------------- |
| 路徑以 `.appex` 結尾        | 擴充功能簽署錯誤     | 宣告擴充功能          |
| `Signature=adhoc`           | build 未簽署         | 用 store 設定檔 build |
| `Apple Development`         | 開發用 build         | 用 store 設定檔 build |
| 讀得到 `ProvisionedDevices` | 內部 build（ad hoc） | 用 store 設定檔 build |
| `sealed resource`           | IPA 事後被修改       | 重新 build            |
| EAS：「no longer valid」    | 憑證已撤銷           | 建立新憑證            |
| 全部都有效                  | Apple 端的問題       | 重新上傳，再回報      |

## 用四個指令檢查你的 IPA

從 expo.dev 上的 build 頁面下載 IPA，然後在 Mac 上開啟終端機。

**1. 是誰簽署了這個 app？**

```bash
unzip -q MyApp.ipa -d ipa
codesign -dv --verbose=4 ipa/Payload/*.app 2>&1 | grep -E "^(Identifier|Authority|Signature|TeamIdentifier)="
```

`codesign` 會輸出到標準錯誤，所以要加 `2>&1`。根據 [Apple 的技術說明 TN3161](https://developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates)，每一行 `Authority` 都是信任鏈中的一環。第一行必須以 `Apple Distribution:` 或 `iPhone Distribution:` 開頭，後面接你的團隊名稱。後者是舊的 iOS Distribution 類型的名稱：從程式碼來看，EAS CLI 24.10.0 仍然會建立這種類型的憑證。如果你看到 `Apple Development:`，那就是開發用 build。如果你看到 `Signature=adhoc`，而且完全沒有 `Authority` 行，代表這個二進位檔沒有用任何憑證簽署。

**2. app 在簽署後有被修改過嗎？**

```bash
codesign --verify --deep --strict -vv ipa/Payload/*.app
```

你希望看到 `valid on disk`，接著是 `satisfies its Designated Requirement`。TN3161 說明了這個檢查保證什麼：所有預期的檔案都在，沒有新增檔案，也沒有檔案被修改。我拿一個簽署後又改過的測試 bundle 來試，指令回應 `a sealed resource is missing or invalid`，接著是 `file modified:` 加上被改動的檔案。這裡的 `--deep` 選項只用來驗證，絕對不要拿來簽署：在 Apple 論壇上，一位支援團隊的工程師就不建議用它來簽署。

**3. 內嵌的是哪個描述檔？**

```bash
security cms -D -i ipa/Payload/*.app/embedded.mobileprovision -o profile.plist
plutil -extract ProvisionedDevices xml1 -o - profile.plist
plutil -extract ExpirationDate raw profile.plist
```

這些是[關於描述檔的技術說明 TN3125](https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles)裡的指令。App Store 描述檔不包含任何裝置清單：第二行應該回應 `Could not extract value`。如果它顯示了裝置識別碼，那就是 ad hoc 描述檔，也就是內部 build 用的那種。第三行會顯示描述檔的到期日。

**4. 擴充功能和 framework 的簽署是否一致？**

```bash
find ipa/Payload/*.app \( -name "*.appex" -o -name "*.framework" \) \
  -exec sh -c 'echo "$1"; codesign -dvv "$1" 2>&1 | grep -m1 "^Authority="' _ {} \;
```

每個元件顯示的 `Authority` 行都應該和 app 相同。如果某個元件不一樣，錯誤訊息指的就是它。

如果你想在上傳前先檢查，TN3161 建議使用 `altool`，它和 Xcode 的 Validate App 按鈕做的是同樣的檢查。它需要一把 App Store Connect API 金鑰，金鑰檔 `AuthKey_<KEY_ID>.p8` 要放在 `~/.appstoreconnect/private_keys`：

```bash
xcrun altool --validate-app -f MyApp.ipa -t ios --api-key <KEY_ID> --api-issuer <ISSUER_ID>
```

## 用 EAS 修正，依原因逐一處理

### 把內部或開發用 build 送給 Apple

根據 [Expo 關於 eas.json 的文件](https://docs.expo.dev/build/eas-json/)，`"distribution": "internal"` 的 build 不是為商店簽署的：它們用的是 ad hoc 描述檔。只有 distribution 為 `store`（預設值）的設定檔，才會產生可以上傳的 build。**最保險的做法是直接上傳你剛 build 好的版本，不要手動挑選**：

```bash
eas build --platform ios --profile production --auto-submit
```

如果你用 `eas submit --path`，要確認檔案真的是你最新的 store build。在 Apple 論壇上，有個團隊發現他們的上傳工具每次送出的都是一個舊的 IPA，而那個 IPA 被版本控制在 git 裡。

### 漏掉的擴充功能

每個擴充功能都是獨立的 bundle，有自己的識別碼和自己的描述檔。在使用原生程式碼產生（prebuild）的 Expo 專案中，[Expo 關於 iOS 擴充功能的頁面](https://docs.expo.dev/build-reference/app-extensions/)要求你在 `extra.eas.build.experimental.ios.appExtensions` 裡宣告它們。這樣 EAS CLI 在 build 之前就知道它們的存在，並會建立或驗證它們的憑證。大多數會加入擴充功能的函式庫，都會透過自己的 plugin 幫你寫好這段宣告。

Solys 是我做的小遊戲鬧鐘，內含四個擴充功能：一個 widget 和三個 Screen Time 擴充功能。這四個都宣告在它的設定裡，EAS 也為每一個準備了描述檔。**在 Xcode 裡手動加入、卻沒有這段宣告的擴充功能，最有可能就是**錯誤訊息裡那個 `.appex` 路徑的元凶。

### 憑證已撤銷或過期

[Apple 關於憑證的頁面](https://developer.apple.com/support/certificates/)講得很明白：用已過期或已撤銷的憑證簽署的 build，你就不能再上傳了。一個已經上傳、但還沒送審的 build，如果它的憑證被撤銷，甚至可能變成 Invalid Binary。

EAS CLI 24.10.0 的程式碼顯示了這種情況什麼時候會被忽略：

- **互動式 build，已登入 Apple**：EAS 會把它的憑證和 Apple 那邊仍有效的憑證比對。如果找不到，會顯示「Current distribution certificate is no longer valid in Apple Dev Portal」，並讓你選擇或建立一個新的。
- **互動式 build，未登入**：EAS 只檢查日期，並提醒你它跳過了 Apple 端的驗證。
- **非互動式 build，在持續整合（CI）中**：EAS 顯示「Distribution Certificate is not validated for non-interactive builds」，然後照樣簽署。

**在持續整合中，EAS 不會重新檢查憑證本身：撤銷的問題可能要到上傳時才會發現。** 修正方式：登入你的 Apple 帳號，執行一次互動式 build，或者使用 `eas credentials --platform ios`，進入 Build Credentials 選單，再選「Distribution Certificate: Add a new one to your account」。包含舊憑證的描述檔會失效：EAS 會在下一次 build 時檢查並重新產生它們。Apple 對憑證數量的限制，詳見[iOS 開發者憑證指南](https://devoria.fr/zh-hant/blog/ios-developer-certificate-provisioning-profile-expo)。

### 簽署後被修改的二進位檔

簽署會用雜湊值把程式碼、資源和中繼資料封存起來，[Apple 的技術說明 TN3126](https://developer.apple.com/documentation/technotes/tn3126-inside-code-signing-hashes) 有詳細解釋。把 IPA 解壓縮、改一個檔案、再重新壓縮，就會破壞這個封存。**請在你的設定裡修改，然後重新 build。** 絕對不要修改 EAS 產生的 IPA。

程式碼放錯位置也是同樣的道理，例如放在 `.zip` 壓縮檔裡：App Store 無法重新簽署它。Apple 在[bundle 內容](https://developer.apple.com/documentation/bundleresources/placing-content-in-a-bundle)的頁面中說明了允許的位置。

### 本機憑證

如果你的 EAS 設定檔使用 `"credentialsSource": "local"`，你的 `credentials.json` 會指向一個 `.p12` 憑證和一個 `.mobileprovision` 描述檔。用步驟 3 的指令檢查這個描述檔：它必須是 App Store 類型，並且包含你目前的發佈憑證。另外，這些檔案要放在儲存庫之外，就像[Expo app 的 API 金鑰](https://devoria.fr/zh-hant/blog/expo-api-key-security-supabase)一樣。

### 全部都有效的時候

還有一種讓人很挫折的情況。在 Apple 論壇上，有開發者把同一個 build 重新上傳，什麼都沒改，錯誤就消失了。2026 年 8 月和 9 月，有兩篇討論串描述了相反的情況：全新的憑證和描述檔、簽署也驗證過，卻還是一直失敗。其中一篇裡，一位 Apple 工程師建議提交錯誤回報，附上 IPA、簽署分析和 Transporter 的日誌，然後聯絡 App Store Connect。

所以，先用新的 build 號碼重新上傳一次。如果你的四個指令結果都沒問題，錯誤卻又出現，就帶著這些資料回報給 Apple。**不要反射性地撤銷你的憑證**：這不會多解決什麼，反而會讓你的描述檔失效。

## 上傳 build，不再有意外

上傳前花兩分鐘就能檢查簽署。其他自動檢查也需要同樣的嚴謹，例如 Xcode 版本相關的 [ITMS-90725](https://devoria.fr/zh-hant/blog/itms-90725-sdk-version-issue-expo)，或權限說明文字相關的 [ITMS-90683](https://devoria.fr/zh-hant/blog/itms-90683-missing-purpose-string-expo)。從 build 到上傳、不用 Mac 的完整流程，請看[沒有 Mac 也能發佈 iOS app](https://devoria.fr/zh-hant/blog/publish-ios-app-without-mac-expo-eas)。

審查人員的拒絕就需要多一點思考：處理步驟在[app 被 Apple 拒絕](https://devoria.fr/zh-hant/expertise/app-rejected-by-apple)這一頁，最常見的拒絕原因則在[Apple 為什麼拒絕你的 app](https://devoria.fr/zh-hant/blog/apple-app-rejection-reasons-real-cases)。

如果你想在上傳前檢查你的資料，[Review Kit](https://devoria.fr/zh-hant/kits/app-review) 收錄了我的檢查清單，以及會幫你審閱專案的 Claude Code skills。如果你的上傳卡住了，想找真人幫忙看看，[跟我預約一小時](https://devoria.fr/zh-hant/coaching)：我們透過視訊，在你的螢幕上一起檢查你的專案。如果你正在準備第一次上架，[做一下免費診斷](https://devoria.fr/zh-hant/diagnostic)：它會幫你把步驟排好順序，並寄給你我的防 Apple 拒絕檢查清單。

## 常見問題

### ITMS-90034 是 App Review 的拒絕嗎？

不是。這是上傳 build 時的自動驗證，發生在 TestFlight 和任何審查之前。沒有人打開過你的 app：Apple 只是發現它的簽署不是來自有效的發佈憑證。

### 要修正 ITMS-90034，需要撤銷我的發佈憑證嗎？

只有在憑證外洩或本來就已失效時才需要。撤銷一個正常運作的憑證，會讓你的描述檔失效，卻沒有解決根本原因。先用 `codesign` 檢查 IPA 的簽署，再依照決策表指出的問題修正。

### 可以用遠端更新修正 ITMS-90034 嗎？

不行。簽署是二進位檔的一部分，被拒絕的 build 永遠無法使用。你必須產生一個正確簽署的新二進位檔，然後重新上傳。

### 為什麼錯誤訊息提到的是我的 widget，而不是我的 app？

因為 widget 是獨立的 bundle，用它自己的描述檔簽署。如果它沒有向 EAS 宣告，或是用別的方式簽署，就會讓整個上傳失敗。在你的設定中宣告這個擴充功能，然後重新 build。

### 如果 codesign 說一切都有效，該怎麼辦？

也要檢查內嵌的描述檔和每個擴充功能。如果全部都沒問題，就用新的 build 號碼重新上傳一次。如果錯誤還是存在，就向 Apple 提交回報，附上 IPA、`codesign` 的輸出和上傳日誌。


## 你的專案

[Review Kit](https://devoria.fr/zh-hant/kits/app-review)：我的 App Store 審查檢查清單、我被 Apple 退件後的修正、Google Play 檢查清單，以及三個 Claude Code skill。$1,749。

[iOS & Android Kit](https://devoria.fr/zh-hant/kits/ios)：用 Claude Code 打造你的 iPhone 和 Android App：我自己 App 的起始程式碼、上架商店的完整流程，以及所有套件。$3,599。

[診斷：你離自己的 iPhone App 還差什麼](https://devoria.fr/zh-hant/diagnostic)：7 個問題，60 秒：找出真正卡住你發布 iPhone App 的原因，拿到你的 4 步驟路線，以及最適合你的套件。
