PC パソコン

Xcode「Entitlements file was modified during the build」の解決方法

XcodeでiOS・macOS AppをBuildやArchiveした際に、次のようなErrorが表示されることがあります。

Entitlements file "MyApp.entitlements" was modified during the build, which is not supported.

さらに:

You can disable this error by setting 'CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION' to 'YES', however this may cause the built product's code signature or provisioning profile to contain incorrect entitlements.

このErrorは、Code Signingに利用する.entitlements Fileが、XcodeがBuildを開始してからSigning処理までの間に変更されたことを意味します。

代表的な原因は、Run Script Phase、CI Script、Fastlane、PlistBuddy、sedなどがBuild途中でEntitlements Fileを書き換えているケースです。

一時的にErrorだけを消すのではなく、EntitlementsをBuild中に直接書き換えず、Debug・Release・StagingなどConfigurationごとに固定したEntitlements Fileを用意して切り替えるのが安全な解決方法です。

  1. Entitlements Fileとは
  2. 「modified during the build」とは
  3. 代表的な発生状況
  4. まず確認すること
    1. 1. CODE_SIGN_ENTITLEMENTSを確認する
    2. 2. Build PhasesのRun Scriptを確認する
    3. 3. Project全体からentitlementsへの書き込み処理を検索する
  5. 主な原因
    1. 1. Run ScriptでEntitlementsを直接編集している
    2. 2. Debug・Releaseで同じFileを書き換えている
    3. 3. CIでBuild番号やEnvironment名と一緒にEntitlementsを書き換えている
    4. 4. Fastlane ActionやCustom ScriptがFileを書き換えている
    5. 5. 複数Targetが同じEntitlements Fileを共有している
    6. 6. Build中に生成FileをSource FileへCopyしている
    7. 7. Build SystemのCacheが古い
  6. 解決方法1:Clean Build Folderを実行する
  7. 解決方法2:DerivedDataを削除する
  8. 解決方法3:Build中のEntitlements書き換えをやめる
  9. 解決方法4:ConfigurationごとにEntitlements Fileを分ける
  10. 解決方法5:.xcconfigでEntitlements Fileを切り替える
  11. 解決方法6:XcodeのSigning & Capabilitiesから管理する
  12. 解決方法7:Build前に生成し、Build開始後は変更しない
  13. 解決方法8:生成先をSource Entitlementsとは別Fileにする
  14. 解決方法9:Build Phaseの順序を確認する
  15. 解決方法10:Entitlements Fileの変更をGitで確認する
  16. 解決方法11:FileのTimestampを確認する
  17. 解決方法12:CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATIONを使用する場合
  18. 解決方法13:Temporary WorkaroundとしてDebugだけ許可する
  19. 解決方法14:Provisioning Profileとの一致を確認する
  20. 解決方法15:実際に署名されたEntitlementsを確認する
  21. 解決方法16:Provisioning Profile側のEntitlementsを確認する
  22. 解決方法17:App Groupsの動的書き換えをやめる
  23. 解決方法18:Associated DomainsもConfigurationごとに分離する
  24. 解決方法19:複数TargetでEntitlementsを共有しすぎない
  25. 解決方法20:CIでSource Treeを書き換えない
  26. Clean Build Folderで直った場合
  27. DerivedData削除でも再発する場合
  28. Archive時だけ発生する場合
  29. やってはいけない対処
  30. 最短で確認するチェックリスト
  31. まとめ

Entitlements Fileとは

Entitlementsは、Appが利用する特別なCapabilityや権限をCode Signatureへ含めるための設定です。

例えば:

  • Push Notifications
  • App Groups
  • Keychain Sharing
  • iCloud
  • Associated Domains
  • Sign in with Apple
  • App Sandbox

などで利用されます。

Entitlements Fileは一般的に:

MyApp.entitlements

のようなProperty List Fileです。

例:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.associated-domains</key> <array> <string>applinks:example.com</string> </array> </dict> </plist>

「modified during the build」とは

XcodeはBuild開始時にEntitlements FileをSigning Inputとして読み込みます。

ところがBuild途中でそのFileが書き換えられると、最初に読み込んだ内容とSigning時の内容が一致しなくなります。

そのためXcodeは:

Entitlements file was modified during the build

としてBuildを停止します。

重要:EntitlementsはCode Signingへ直接影響するため、普通のResource Fileとは違い、Build途中で内容を変更する設計は避ける必要があります。

代表的な発生状況

  • Run Script Phaseで.entitlementsを変更している
  • PlistBuddyでApp Groupsを書き換えている
  • sedでEnvironmentごとの値を置換している
  • DebugとReleaseで同じEntitlements Fileを動的に書き換えている
  • Fastlane Scriptが.entitlementsを変更している
  • CI ScriptがBuild直前または途中でFileを書き換えている
  • 複数Targetが同じEntitlements Fileを同時に変更している
  • Code Generation Toolが.entitlementsを生成している
  • Git CheckoutやScriptでBuild中にFile内容が戻されている
  • DerivedDataに古いSigning情報が残っている

まず確認すること

1. CODE_SIGN_ENTITLEMENTSを確認する

Xcodeで:

Target → Build Settings → Code Signing Entitlements

を確認します。

Build Setting名は:

CODE_SIGN_ENTITLEMENTS

です。

例えば:

MyApp/MyApp.entitlements

となっているなら、そのFileがBuild中に変更されていないか調べます。

2. Build PhasesのRun Scriptを確認する

次を開きます。

Target → Build Phases

Run Script Phaseに:

PlistBuddy sed cp mv echo cat

など、Entitlements Fileを変更する処理がないか確認します。

3. Project全体からentitlementsへの書き込み処理を検索する

Terminalなら:

grep -R "\.entitlements" .

PlistBuddyを探すなら:

grep -R "PlistBuddy" .

sedを探すなら:

grep -R "sed .*entitlements" .

主な原因

1. Run ScriptでEntitlementsを直接編集している

例えば:

/usr/libexec/PlistBuddy \ -c "Set :com.apple.developer.associated-domains:0 applinks:staging.example.com" \ MyApp.entitlements

のようなScriptです。

Build途中でSigning Inputそのものを変更するため、Errorの原因になります。

2. Debug・Releaseで同じFileを書き換えている

例えば:

Debug: group.com.example.debug

Release:
group.com.example

のような差分を1つのFileへ動的に書き込んでいる場合です。

3. CIでBuild番号やEnvironment名と一緒にEntitlementsを書き換えている

CI ScriptがSource Tree内のEntitlements Fileを変更してからXcode Buildを走らせる構成では、Timingによって変更検出が発生することがあります。

4. Fastlane ActionやCustom ScriptがFileを書き換えている

Signing自動化の一部でEntitlementsを直接編集している場合があります。

5. 複数Targetが同じEntitlements Fileを共有している

Main App、Widget、Notification Service Extensionなどで同じFileを共有し、どれかが変更すると他Targetへ影響します。

6. Build中に生成FileをSource FileへCopyしている

例えば:

cp generated.entitlements MyApp.entitlements

のようなScriptです。

7. Build SystemのCacheが古い

Fileを正しく修正した後でも、古いDerivedDataやBuild Artifactによって変更検出が残る場合があります。

解決方法1:Clean Build Folderを実行する

まず:

Product → Clean Build Folder

を実行します。

一時的なBuild Cacheが原因なら、これだけで解決する場合があります。

注意:毎回Cleanしないと再発する場合は、根本原因が別にあります。Run ScriptなどがEntitlements Fileを書き換えていないか確認してください。

解決方法2:DerivedDataを削除する

Clean Build Folderで直らない場合:

rm -rf ~/Library/Developer/Xcode/DerivedData/*

を実行してBuild Cacheを削除できます。

その後Xcodeを再起動し、Buildし直します。

解決方法3:Build中のEntitlements書き換えをやめる

問題のある例:

/usr/libexec/PlistBuddy \ -c "Set :com.apple.security.application-groups:0 group.com.example.staging" \ MyApp.entitlements

このようにSource Entitlements Fileを直接書き換える処理は削除します。

解決方法4:ConfigurationごとにEntitlements Fileを分ける

例えば:

MyApp-Debug.entitlements MyApp-Staging.entitlements MyApp-Release.entitlements

を用意します。

Debug:

CODE_SIGN_ENTITLEMENTS = MyApp/MyApp-Debug.entitlements

Release:

CODE_SIGN_ENTITLEMENTS = MyApp/MyApp-Release.entitlements

のようにBuild Settingsで切り替えます。

解決方法5:.xcconfigでEntitlements Fileを切り替える

Debug.xcconfig:

CODE_SIGN_ENTITLEMENTS = MyApp/MyApp-Debug.entitlements

Release.xcconfig:

CODE_SIGN_ENTITLEMENTS = MyApp/MyApp-Release.entitlements

とすれば、File自体をBuild途中で変更する必要がなくなります。

解決方法6:XcodeのSigning & Capabilitiesから管理する

標準Capabilityなら:

Target → Signing & Capabilities

から設定します。

例えば:

  • Push Notifications
  • App Groups
  • Associated Domains
  • Keychain Sharing

などです。

Xcodeに管理させることで、手動ScriptによるEntitlements変更を減らせます。

解決方法7:Build前に生成し、Build開始後は変更しない

どうしてもEntitlementsを自動生成する必要がある場合は、Xcode Buildの前に生成してください。

例えばCIで:

./Scripts/generate-entitlements.sh

xcodebuild
-project MyApp.xcodeproj
-scheme MyApp
-configuration Release
archive

という順番にします。

重要なのは、xcodebuild開始後にFileを書き換えないことです。

解決方法8:生成先をSource Entitlementsとは別Fileにする

例えば:

Generated/MyApp-Release.entitlements

をBuild前に生成し、CODE_SIGN_ENTITLEMENTSでそのFileを指定します。

Source Control上のEntitlementsを直接変更しない構成にします。

解決方法9:Build Phaseの順序を確認する

Run ScriptがSigning処理に関係する場合:

Target → Build Phases

でScriptの実行Timingを確認します。

ただし、順序変更だけでSource EntitlementsをBuild途中に変更する設計を維持するより、Fileを固定化する方が安全です。

解決方法10:Entitlements Fileの変更をGitで確認する

Build前:

git status

Build後:

git status

を比較します。

差分を見るなら:

git diff -- MyApp/MyApp.entitlements

Build後に差分が出るなら、何らかの処理がFileを書き換えています。

解決方法11:FileのTimestampを確認する

Build前後で:

stat MyApp/MyApp.entitlements

を実行します。

内容が同じでもTimestampが変わっている場合、ScriptがFileを再生成・再Copyしている可能性があります。

解決方法12:CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATIONを使用する場合

XcodeのError Messageでは:

CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES

を設定すると検査を無効化できると案内されます。

User-defined Build Settingとして設定することはできます。

ただしXcode自身が:

this may cause the built product's code signature or provisioning profile to contain incorrect entitlements

と警告しています。

重要:CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION=YESは基本的に最後の手段です。Signing InputをBuild途中で変更する根本原因を修正する方を優先してください。

解決方法13:Temporary WorkaroundとしてDebugだけ許可する

どうしてもDevelopment中だけ必要なら:

Debug: CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES

Release:
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = NO

のようにReleaseでは無効にする方法があります。

ただし、これも根本解決ではありません。

解決方法14:Provisioning Profileとの一致を確認する

Entitlements Fileを固定しても、Provisioning Profileが対応Capabilityを含んでいなければCode Signing Errorになります。

例えばApp Groupsを使うなら、Developer Portal側でも対応App GroupとCapability設定が必要です。

解決方法15:実際に署名されたEntitlementsを確認する

Build後のAppから確認できます。

codesign -d \ --entitlements :- \ /path/to/MyApp.app

これにより、最終的なCode Signatureへ入っているEntitlementsを確認できます。

解決方法16:Provisioning Profile側のEntitlementsを確認する

Embedded Profileがある場合:

security cms -D \ -i /path/to/MyApp.app/embedded.mobileprovision \ > /tmp/profile.plist

確認:

/usr/libexec/PlistBuddy \ -c "Print :Entitlements" \ /tmp/profile.plist

AppのEntitlementsとProfile側を比較できます。

解決方法17:App Groupsの動的書き換えをやめる

例えばEnvironmentごとに:

group.com.example.debug group.com.example.staging group.com.example

を切り替えるなら、それぞれ固定Entitlements Fileを用意する方が安全です。

解決方法18:Associated DomainsもConfigurationごとに分離する

例えば:

Debug: applinks:staging.example.com

Release:
applinks:example.com

をBuild中に書き換えず、別Entitlements Fileとして管理します。

解決方法19:複数TargetでEntitlementsを共有しすぎない

Main AppとExtensionは必要なCapabilityが違うことがあります。

例えば:

MyApp.entitlements MyWidget.entitlements NotificationService.entitlements

のように分離します。

解決方法20:CIでSource Treeを書き換えない

CIでは:

sed -i ... PlistBuddy ... cp ... MyApp.entitlements

のような処理をxcodebuildと並行またはBuild途中で実行しないようにします。

必要な生成処理はBuild開始前に完了させます。

Clean Build Folderで直った場合

一度だけ発生し、Clean Build Folder後に再発しないならCacheの不整合だった可能性があります。

しかし毎回:

Product → Clean Build Folder

を実行しないとBuildできない場合、Build ScriptなどがEntitlementsを変更している可能性が高いため、Root Causeを調査してください。

DerivedData削除でも再発する場合

DerivedDataを削除しても再発するなら、CacheではなくSource TreeやBuild Scriptの問題と考えます。

次を優先して確認してください。

  1. Run Script Phase
  2. Fastlane
  3. CI Script
  4. PlistBuddy
  5. sed
  6. cpやFile Generation
  7. 複数Targetからの共有File書き込み

Archive時だけ発生する場合

Debug Buildでは正常でArchiveだけErrorになる場合:

  • Release用Run Script
  • Release.xcconfig
  • Archive用Environment Variable
  • Distribution Signing設定
  • Release用Entitlements File

を確認します。

やってはいけない対処

原因を調べずにCODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION=YESだけ設定するのは避けてください。

Errorは消えても:

  • Code Signature
  • Provisioning Profile
  • App Groups
  • Push Notifications
  • Associated Domains

などのEntitlementsが意図と違う状態になる可能性があります。

特にApp Store配布用Release Buildでは、Signing Inputを固定する構成へ直す方が安全です。

最短で確認するチェックリスト

  1. CODE_SIGN_ENTITLEMENTSのPathを確認する
  2. Product → Clean Build Folderを実行する
  3. DerivedDataを削除する
  4. Build PhasesのRun Scriptを確認する
  5. PlistBuddyでEntitlementsを書き換えていないか確認する
  6. sedで置換していないか確認する
  7. Build前後のgit diffを確認する
  8. Build前後のFile Timestampを確認する
  9. Debug・Releaseで別Entitlements Fileを使用する
  10. .xcconfigでCODE_SIGN_ENTITLEMENTSを切り替える
  11. Signing & Capabilitiesから標準Capabilityを管理する
  12. CIではBuild前に生成処理を完了する
  13. 複数Targetで同じFileを変更していないか確認する
  14. Provisioning ProfileとEntitlementsを一致させる
  15. CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATIONは最後の手段にする

まとめ

Xcodeの「Entitlements file was modified during the build」は、Code Signingに利用するEntitlements FileがBuild途中で変更された場合に発生します。

最も多い原因はRun Script、PlistBuddy、sed、CI、Fastlaneなどによる.entitlements Fileの直接書き換えです。

まずClean Build FolderやDerivedData削除を試し、再発する場合はBuild Scriptを確認してください。

EnvironmentごとにEntitlementsが異なる場合は、1つのFileを動的に変更するのではなく、Debug・Staging・Releaseごとに固定したEntitlements Fileを用意し、CODE_SIGN_ENTITLEMENTSで切り替える方法が安全です。

CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION=YESでError検査を回避することはできますが、Xcode自身もCode SignatureやProvisioning Profileへ不正なEntitlementsが入る可能性を警告しています。

そのため、恒久対策としてはBuild中のEntitlements変更をなくし、Signingに使うFileをBuild開始前から終了まで固定することが最も重要です。