Skip to content

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を除去します。

ruby
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

実施手順:

  1. Podfileを開き上記スクリプトを追加
  2. ターミナルでプロジェクトのiosフォルダに移動
  3. コマンド実行: pod install
  4. 改めてアーカイブ → TestFlightアップロード

方法2: スクリプトを使った全フレームワークのbitcode自動検出・除去

全てのフレームワークをスキャンし、bitcodeを含むものだけ自動処理します。

ruby
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内に以下を追記:

ruby
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を標準的な解決策として推奨しますが、プロジェクト構造に応じて適切なアプローチを選択してください。