hermes.frameworkのbitcodeエラーによるInvalid Executable
問題文
Xcode 16でアプリをアーカイブ後にTestFlightへアップロードすると、次のエラーが発生します:
Asset validation failed
NSLocalizedRecoverySuggestion=Invalid Executable.
The executable 'TrueCaller.app/Frameworks/hermes.framework/hermes' contains bitcode.
この問題の特徴:
✅ ローカルビルドやアーカイブは正常に成功する
🚫 TestFlightアップロード時にだけ発生
⚠️ macOS 15/Xcode 16環境で頻発
🔍 Hermesフレームワークがbitcodeを含むことが原因
エラーの原因
bitcodeはAppleが採用している中間コードフォーマットです。最新のXcode 16では、特定の外部フレームワーク(特にHermes)がbitcodeを含んでいると、TestFlightのアセットバリデーションでエラーが発生します。React NativeプロジェクトでHermesエンジンを使用している場合、そのFramework内にbitcodeが含まれることで問題が起こります。
解決方法
以下のいずれかの方法でbitcodeを除去します。React Nativeバージョンによらず適用可能です。
方法1: CocoaPodsのpost_installスクリプトで自動除去(推奨)
Podfileにスクリプトを追加して、インストール時に自動的にbitcodeを除去します。
post_install do |installer|
# bitcode_stripツールのパス取得
bitcode_strip_path = `xcrun --find bitcode_strip`.chop!
# フレームワークからbitcodeを除去する関数
def strip_bitcode(bitcode_strip_path, framework_path)
full_path = File.join(Dir.pwd, framework_path)
if File.exist?(full_path)
command = "#{bitcode_strip_path} #{full_path} -r -o #{full_path}"
system(command)
end
end
# Hermes関連パス(プロジェクトに応じて調整)
framework_paths = [
"Pods/hermes-engine/destroot/Library/Frameworks/macosx/hermes.framework/hermes",
"Pods/hermes-engine/destroot/Library/Frameworks/macosx/hermes.framework/Versions/Current/hermes",
"Pods/hermes-engine/destroot/Library/Frameworks/universal/hermes.xcframework/ios-arm64/hermes.framework/hermes",
"Pods/hermes-engine/destroot/Library/Frameworks/universal/hermes.xcframework/ios-arm64_x86_64-maccatalyst/hermes.framework/hermes"
]
# 各フレームワークを処理
framework_paths.each do |path|
strip_bitcode(bitcode_strip_path, path)
end
end
実施手順:
Podfile
を開き上記スクリプトを追加- ターミナルでプロジェクトの
ios
フォルダに移動 - コマンド実行:
pod install
- 改めてアーカイブ → TestFlightアップロード
方法2: スクリプトを使った全フレームワークのbitcode自動検出・除去
全てのフレームワークをスキャンし、bitcodeを含むものだけ自動処理します。
post_install do |installer|
def strip_bitcode_from_frameworks
frameworks = Dir.glob("Pods/**/*.framework")
frameworks.each do |framework|
binary = File.join(framework, File.basename(framework, ".framework"))
if File.exist?(binary)
# bitcodeの有無をチェック
if `otool -l "#{binary}" | grep __LLVM` != ""
stripped_file = "#{binary}_stripped"
# bitcode除去実行
system("xcrun bitcode_strip \"#{binary}\" -r -o \"#{stripped_file}\"")
# オリジナルファイルを置換
FileUtils.mv(stripped_file, binary, force: true)
end
end
end
end
strip_bitcode_from_frameworks()
end
注意
この方法は全てのフレームワークをスキャンするため時間がかかりますが、手動でパスを指定する必要がありません。
(オプション)BoringSSL-GRPCエラーが同時発生する場合
以下のエラーが併発する時は追加対応が必要です:
error: buildSettings:GCC_WARN_INHIBIT_ALL_WARNINGS
Podfileのpost_install
内に以下を追記:
installer.pods_project.targets.each do |target|
if target.name == 'BoringSSL-GRPC'
target.source_build_phase.files.each do |file|
if file.settings && file.settings['COMPILER_FLAGS']
flags = file.settings['COMPILER_FLAGS'].split
flags.reject! { |flag| flag == '-GCC_WARN_INHIBIT_ALL_WARNINGS' }
file.settings['COMPILER_FLAGS'] = flags.join(' ')
end
end
end
end
根本的な原因と解決原理
Hermesエンジンはデフォルトでbitcodeを含んでビルドされますが、Appleの最新審査システムではこれが不正と判定されます。bitcode_strip
ツールを使い実行ファイルからbitcodeセクションを物理的に除去することで回避可能です。
変更後に必ず行うこと
pod install
の実行- XcodeのDerivedData削除(
~/Library/Developer/Xcode/DerivedData
) - Product > Clean Build Folder
補足情報
- React Native < 0.72 の場合は
hermes_enabled
フラグを確認 - 複数人開発時は全メンバーが同じスクリプト適用済みPodfileを使用すること
- Hermesのバージョンアップで根本解決される可能性あり(要追記)
これらの対応により、bitcode関連のTestFlightアップロードエラーは解決します。方法1を標準的な解決策として推奨しますが、プロジェクト構造に応じて適切なアプローチを選択してください。