Flutter iOS cannot build due to modular header settings in podfile

4,342

Solution 1

After a very long search, the answer is easy.

1- navigate to ios directory inside your app

2- edit podfile in text editor

3- search for target 'Runner' do

4- add use_frameworks! in the next line

5- save and run your app

for example, my full podfile looks like this before solving the issue

# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
  end
end

After solving the issue by adding the extra line it looks like

# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
  use_frameworks!
  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
  end
end

Solution 2

I'been struggling all day with the same issue using a very similar plugin list.

Using this answer: Using static libraries with CocoaPods 1.5 no such module at import

I was able to modify the flutter pod as follows and build the project:

# Uncomment this line to define a global platform for your project
platform :ios, '8.0'

inhibit_all_warnings! # ------------------> NEW

use_frameworks! # ------------------> NEW
dynamic_frameworks = ['BoringSSL-GRPC'] # ------------------> NEW

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}


def parse_KV_file(file, separator='=')
  file_abs_path = File.expand_path(file)
  if !File.exists? file_abs_path
    return [];
  end
  generated_key_values = {}
  skip_line_start_symbols = ["#", "/"]
  File.foreach(file_abs_path) do |line|
    next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
    plugin = line.split(pattern=separator)
    if plugin.length == 2
      podname = plugin[0].strip()
      path = plugin[1].strip()
      podpath = File.expand_path("#{path}", file_abs_path)
      generated_key_values[podname] = podpath
     else
      puts "Invalid plugin specification: #{line}"
     end
  end
  generated_key_values
end

target 'Runner' do
  # Flutter Pod

  copied_flutter_dir = File.join(__dir__, 'Flutter')
  copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
  copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
  unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
    # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
    # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
    # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.

    generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
    unless File.exist?(generated_xcode_build_settings_path)
      raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
    end
    generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
    cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];

    unless File.exist?(copied_framework_path)
      FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
    end
    unless File.exist?(copied_podspec_path)
      FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
    end
  end

  # Keep pod path relative so it can be checked into Podfile.lock.
  pod 'Flutter', :path => 'Flutter'
  # Plugin Pods

  # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
  # referring to absolute paths on developers' machines.
  system('rm -rf .symlinks')
  system('mkdir -p .symlinks/plugins')
  plugin_pods = parse_KV_file('../.flutter-plugins')
  plugin_pods.each do |name, path|
    symlink = File.join('.symlinks', 'plugins', name)
    File.symlink(path, symlink)  
    pod name, :path => File.join(symlink, 'ios')
  end
end


pre_install do |installer|  # ------------------> NEW BLOCK
    installer.pod_targets.each do |pod|
puts "Evaluating static framework for pod #{pod.name}"
        if dynamic_frameworks.include?(pod.name)
            puts "Overriding the static_framework method for #{pod.name}"
            pod pod.name, :modular_headers => false        
end
    end
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
      target.build_configurations.each do |config|
      config.build_settings['ENABLE_BITCODE'] = 'NO'
      end
  end
end

Its my first time building the app in IOS and the total build time is around 35m (!), I don t known if it is related to this fix, or it's something else.

Also tried doing the inverse, all dynamic and the DKPhotoGalley static, but that makes the build fail with errors on the DKPhotoGallery code.

if someone can chime in with a better approach or understanding of the underlying issue would be great.

Share:
4,342
Kyle B.
Author by

Kyle B.

Updated on December 21, 2022

Comments

  • Kyle B.
    Kyle B. over 1 year

    I have a flutter app that was working fine. I'm going through updating my flutter version and the versions of some of my plugins (on the newest XCode version 11). I can no longer build my app because either one of two things occurs:

    1) If I don't have "use_modular_headers!" in my podfile, I get this error when trying to run pod install:

    The Swift pod `DKPhotoGallery` depends upon `SDWebImage`, which does not define modules. To opt into those targets generating module maps (which is necessary to import them from Swift when building as static libraries), you may set `use_modular_headers!` globally in your Podfile, or specify `:modular_headers => true` for particular dependencies.
    

    2) If I add "use_modular_headers!" to the podfile, then I can successfully install the podfiles, but it fail when building with this error:

    fatal error: module map file '/Users/mbpro/Documents/Perkl/ios/Pods/Headers/Private/openssl_grpc/BoringSSL-GRPC.modulemap' not found
    

    The second error I've come to find out is because GRPC doesn't support modular headings. This is where I'm stuck, because due to flutter's way of dynamically generating podfile from the pubspec, it seems modular headers are either globally on or off, and I can't specifically turn on modular headers for specific pods.

    Here is a list of my pubspec dependencies:

      cloud_firestore: 0.13.6
      firebase_auth: 0.16.1
      firebase_core:
      firebase_database:
      firebase_storage:
      firebase_messaging:
      google_sign_in:
      image_picker:
      image_cropper:
      intl:
      flutter_sound:
      flutter_launcher_icons:
      flushbar:
      file_picker:
      path_provider:
      #audioplayers:
      provider:
      sliding_up_panel:
      font_awesome_flutter:
      marquee:
    

    Any help on this is going to greatly appreciated!! It's completely shut down my development since I can't build to test anything after upgrading.

    Edit: Flutter Doctor -v output (everything looks fine)

    [✓] Flutter (Channel stable, v1.17.3, on Mac OS X 10.15.5 19F101, locale en-US)
        • Flutter version 1.17.3 at /Users/mbpro/Downloads/flutter
        • Framework revision b041144f83 (8 days ago), 2020-06-04 09:26:11 -0700
        • Engine revision ee76268252
        • Dart version 2.8.4
    
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
        • Android SDK at /Users/mbpro/Library/Android/sdk
        • Platform android-29, build-tools 29.0.2
        • Java binary at: /Applications/Android
          Studio.app/Contents/jre/jdk/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build
          1.8.0_202-release-1483-b49-5587405)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 11.5)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 11.5, Build version 11E608c
        • CocoaPods version 1.9.3
    
    [✓] Android Studio (version 3.5)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin version 44.0.1
        • Dart plugin version 191.8593
        • Java version OpenJDK Runtime Environment (build
          1.8.0_202-release-1483-b49-5587405)
    
    [✓] Connected device (1 available)
        • iPhone SE (2nd generation) • 9FC22937-91AB-4F22-BB1E-20FFB1CAF4C8 • ios •
          com.apple.CoreSimulator.SimRuntime.iOS-13-5 (simulator)
    
    • No issues found!