Solving Swift Modular Header Issues in React Native for Good

Oskar Kwaśniewski
No items found.

In short

The article addresses a common Swift modular header error in React Native library installations. It explains the issue's cause and offers solutions, including enabling static frameworks or using a custom CocoaPods plugin.

Introduction

When installing a new React Native library you might have run into this issue when installing pod:

issue with Swift pod install

After seeing this error you might say: “Ah this library just doesn’t work…”, and move on to a similar one.

In this article, I want to discuss why this happens and suggest potential solutions that might save you hours of trying different workarounds.

Why does this error happen?

Let’s start by analyzing the error message. The first sentence tells us that a Pod (library in CocoaPods nomenclature) depends on something else that doesn’t define modules.

What are modules?

Modules are a modern way to package and distribute code in Apple’s ecosystem. When you import Objective-C dependency into a Swift codebase that dependency needs to expose a module interface.

The error then suggests using use_modular_headers! which tells CocoaPods to generate module maps for all of our dependencies. A module map file (.modulemap) tells the compiler how to import the framework’s contents.

However, you might run into compilation errors when you opt-in to use modular headers for all your dependencies. Let’s go over other solutions that you may want to consider.

Solution #1 - Enable static frameworks

One of the most frequent solutions to this issue is to enforce library users to enable static frameworks during build time. This solution fixes the issue because enabling frameworks automatically includes module support.

But in some cases you might want to stick to using static libraries (the default). For that case I’ve created a new CocoaPods plugin that automagically fixes the issue for you.

Let’s see how it works.

Solution #2 - Use CocoaPods Plugin

Here is a quick video demo of how this plugin works:

using CocoaPods demo

Let’s see what goes on under the hood.

When using CocoaPods in a regular native project (without React Native), you would typically resolve this issue by adding :modular_headers => true next to your dependency definition.

In native projects Podfile is the source of truth for your App’s dependencies. So if we have the following Podfile which now has only one dependency (SomeLibrary):

We can fix the modular headers error by specifying modular_headers like so:

This is great for native iOS development, In React Native, however, the source of our dependencies is package.json.

When you look at your Podfile, you will see something more similar to the following:

As you can see, pods are automatically added to your project thanks to React Native's Auto Linking mechanism based on the native code from your node_modules.

Fortunately, we can use CocoaPods utility function set_use_modular_headers_for_pod to achieve the same outcome in cases where we don't have access to pod declaration.

However, there’s an important caveat to keep in mind. Iterating over every library and calling set_use_modular_headers_for_pod is essentially the same as use_modular_headers! (as it will be enabled globally). This can come with its own set of challenges, as discussed earlier in the article.

To address this, the plugin hooks into the pre_install phase of pods installation. It then traverses the dependency tree, identifying Swift libraries and applying modular headers only where necessary.

This approach ensures that modular headers are applied selectively, enabling the pod installation phase to succeed.

Using the plugin

The first step to use the plugin is to add it to your Gemfile (if you are not using bundler, you can install it globally, although I highly recommend you to do so - it’s the default).

gem 'cocoapods-swift-modular-headers'

After that, run bundle install and you can reference the plugin in your Podfile:

If you already have some pre-install hooks, you can add the plugin to the existing hooks:

Here is the plugin repository if you want to learn more.

Summary

With Swift growing in popularity mixing Objective-C and Swift will become more and more popular, so at one point you will most likely run into this error. I hope that now you understand why it happens and how you can fix it once and for all.

Latest update:
January 16, 2025

FAQ

No items found.
React Galaxy City
Get our newsletter

By subscribing to the newsletter, you give us consent to use your email address to deliver curated content. We will process your email address until you unsubscribe or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

Callstack astronaut
Download our ebook

I agree to receive electronic communications By checking any of the boxes, you give us consent to use your email address for our direct marketing purposes, including the latest tech & biz updates. We will process your email address and names (if you have entered them into the above form) until you withdraw your consent to the processing of your names, or unsubscribe, or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

By pressing the “Download” button, you give us consent to use your email address to send you a copy of the Ultimate Guide to React Native Optimization.