DEV Community

Aymeric M
Aymeric M

Posted on

1

The Mystery of Fonts on iOS: Why Was My App Not Displaying Custom Fonts?

A Frustrating Bug on iOS

Recently, while working on a mobile application with React Native and Expo, I encountered an unexpected issue: my custom fonts were not displaying on iOS. Yet, everything worked perfectly on Android.

After hours of debugging and investigation, I discovered that iOS does not recognize fonts by their file name but rather by their "Full Name", a subtlety that does not exist on Android.

In this article, I'll explain the cause of this issue, how to identify it, and most importantly, how to fix it.


Understanding Font Behavior on iOS

On Android, using a custom font is relatively straightforward. You define the font in expo-font using the file path, and it can be referenced directly by its filename:

import { useFonts } from 'expo-font';
import { Text } from 'react-native';

const [fontsLoaded] = useFonts({
  'BasierCircle-Regular': require('./assets/fonts/BasierCircle-Regular.ttf'),
});

if (!fontsLoaded) {
  return null;
}

<Text style={{ fontFamily: 'BasierCircle-Regular' }}>Hello, world!</Text>
Enter fullscreen mode Exit fullscreen mode

Problem: This code does not always work on iOS. The reason is that iOS does not identify fonts by their file name (BasierCircle-Regular.ttf), but rather by their internal font name.


Identifying the Issue

To check which fonts were actually loaded by iOS, I added a simple console.log() in my code:

useEffect(() => {
  console.log('Fonts loaded on iOS:', ExpoFont.getLoadedFonts());
}, []);
Enter fullscreen mode Exit fullscreen mode

The result was surprising:

Fonts loaded on iOS: [
  "BasierCircle-Regular",
  "font000000002d6f7cbc",
  "BasierCircle-SemiBold",
  "SwearDisplay-Bold"
]
Enter fullscreen mode Exit fullscreen mode

Some font names appeared as hexadecimal identifiers (font000000002d6f7cbc) instead of the expected names!

What was happening was that iOS was not using the correct font name but instead generating an identifier.


The Solution: Editing the "Full Name" of the Font

To fix this, I used FontForge, an open-source software that allows you to edit font metadata.

Steps to follow:

  1. Open FontForge and load the font (.ttf or .otf).
  2. Go to Element → Font Info.
  3. Modify the "Full Name" field to match the exact desired name (e.g., BasierCircle-Regular).
  4. Save the font and re-import it into the application.

Proper Integration in Expo

Once the name was corrected, I declared my fonts in app.config.ts (instead of using require() in my code):

export default ({ config }) => ({
  ...config,
  plugins: [
    [
      'expo-font',
      {
        fonts: [
          './assets/fonts/BasierCircle-Regular.ttf',
          './assets/fonts/BasierCircle-Medium.ttf',
          './assets/fonts/BasierCircle-SemiBold.ttf',
          './assets/fonts/BasierCircle-Bold.ttf',
        ],
      },
    ],
  ],
});
Enter fullscreen mode Exit fullscreen mode

This avoids issues related to manually loading fonts and ensures cleaner management via expo-font.


Conclusion

This bug highlights a crucial difference between iOS and Android in handling custom fonts. To avoid this type of issue, here are some best practices to keep in mind:

✅ Always check a font's "Full Name" on iOS using FontForge.

✅ Declare fonts in app.config.ts rather than loading them with require().

✅ Use ExpoFont.getLoadedFonts() to quickly debug font loading.

🚀 With these adjustments, my app now displays fonts correctly on all platforms!


Useful Resources

If you've encountered a similar issue, share your experience in the comments!

Billboard image

Deploy and scale your apps on AWS and GCP with a world class developer experience

Coherence makes it easy to set up and maintain cloud infrastructure. Harness the extensibility, compliance and cost efficiency of the cloud.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more