expo: Font.loadAsync loads some fonts, does not load others

🐛 Bug Report

Environment

Expo CLI 2.17.1 environment info: System: OS: Windows 10 Binaries: Yarn: 1.9.4 - C:\Users\yossi\AppData\Roaming\npm\yarn.CMD npm: 6.1.0 - C:\Program Files\nodejs\npm.CMD IDEs: Android Studio: Version 3.3.0.0 AI-182.5107.16.33.5314842

Target: Android

Steps to Reproduce

In an expo generated project (project with tabs), I modified the Font.loadAsync call as following:

Font.loadAsync({
  // The following fonts are loaded successfully
        'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
        'pixel-font': require('./assets/fonts/PixelFJVerdana12pt.ttf'),
        'Anton': require('./assets/fonts/Anton.ttf'),
        'OpenSans-Regular': require('./assets/fonts/OpenSans-Regular.ttf'),
        'OpenSans-CondLight': require('./assets/fonts/OpenSans-CondLight.ttf'),
        'Montserrat-Regular.ttf': require('./assets/fonts/Montserrat-Regular.ttf'),

  // The following fonts are not loaded (an error message is displayed. See 'actual behavior' below.
        'Raleway-Regular': require('./assets/fonts/Raleway-Regular.ttf'),
        'Alegreya-Regular': require('./assets/fonts/Alegreya-Regular.ttf'),
        'NotoSans-Regular': require('./assets/fonts/NotoSans-Regular.ttf'),
        'Oswald-Regular': require('./assets/fonts/Oswald-Regular.ttf'),
        'EBGaramond-Regular': require('./assets/fonts/EBGaramond-Regular.ttf'),
        'RobotoRegular': require('./assets/fonts/Roboto-Regular.ttf'),
      }),

Expected Behavior

To have all fonts loaded successfully.

Actual Behavior

In the above fonts list, all the fonts that are listed after The following fonts are not loaded are not loaded. The others are loaded properly. For the fonts that don’t load, I get the following message: Font.loadAsync unexpected exception: Font not found /data/user/0/host.exp.exponent/cache/ExperienceData/<Folder>/ExponentAsset-<number>.ttf

Reproducible Demo

  • Create a new expo project, using expo init (with tabs)
  • Replace Font.loadAsync with the above code
  • Run the app on your android emulator or device

App.json:

{
  "expo": {
    "name": "expo-fonts2",
    "slug": "expo-font2",
    "privacy": "public",
    "sdkVersion": "32.0.0",
    "platforms": [
      "ios",
      "android"
    ],
    "version": "1.0.0",
    "orientation": "portrait",
    "packagerOpts": {
      "assetExts": ["ttf"]
    },
    "icon": "./assets/images/icon.png",
    "splash": {
      "image": "./assets/images/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "updates": {
      "fallbackToCacheTimeout": 0
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "ios": {
      "supportsTablet": true
    }
  }
}

package.json:

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "eject": "expo eject",
    "test": "node ./node_modules/jest/bin/jest.js --watchAll"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/samples": "2.1.1",
    "expo": "^32.0.0",
    "react": "16.5.0",
    "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
    "react-navigation": "^3.0.9"
  },
  "devDependencies": {
    "babel-preset-expo": "^5.0.0",
    "jest-expo": "^32.0.0"
  },
  "private": true
}

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 17
  • Comments: 39 (9 by maintainers)

Most upvoted comments

Having same error but after updating to Expo 34. Before (on 33) there was no issues with same ttf files.

I think I found the cause. So actually, the font is loaded but it takes more than 3000ms on Safari and Firefox.

FontObserver that being used by the expo-font has default timeout 3000ms and there is no way to change that timeout from loadAsync.

So when I tried to set the state without waiting for loadAsync it works fine on the web even though the default font will be used first as the font has not been loaded yet.

This implementation is fixing my problem:

if (IS_WEB) {
  Font.loadAsync({
    'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf'),
  }).catch(() => {});
} else {
  await Font.loadAsync({
    'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf'),
  });
}
setFontsLoaded(true);

@tonnenpinguin have can you try the following:

  • delete your node_nodules and package-lock.json
  • run npm install
  • run expo start -c

If that doesnt work try using yarn or the expo install command

Hi–

We think there are two issues here.

Android Font Loading Issue

One is a possible issue with Android font loading – that some font files work and some font files don’t. If you are having this issue, please create a new issue with a Minimal Reproducible Example including the actual font files you are having trouble loading, and we can investigate that. We didn’t see any of the actual font files here in any of the comments where people had this problem.

Web Font Loading Timeout Issue

The other issue here is that there is no way to configure the timeout for font loading in Expo web currently, even though library under the hood being used does have a configurable timeout (that defaults to 3 seconds / 3000 ms). If you are interested in configuring that option, then please open a new issue asking for that and explaining what is important to you. cc @EvanBacon

Closing this issue for now, but please open a new focused issue if you have one of the above issues or a different issue.

Have been facing the same issue today, what solved my issue:

  • install expo-app-loading instead of expo to use AppLoading;
  • remove node-modules;
  • remove package-lock.json;
  • run in terminal npm cache clean -f;
  • run in terminal npm install;

After that the font loaded.

The reason I use duplicate code is that the FontObserver is using setTimeout. Unfortunately, we can’t catch any thrown error by asynchronous code such as setTimeout using try..catch. That’s why we need .catch for that.

Actually, I could also simplify that code into:

Font
  .loadAsync({
    'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf'),
  })
  .then(() => setFontsLoaded(true))
  .catch(() => setFontsLoaded(true));

FontObserver that being used by the expo-font has default timeout 3000ms and there is no way to change that timeout from loadAsync.

Thanks for finding the root cause, perhaps a PR to expo where they configure FontObserver would do the trick in a futur version.

I do not get your duplicate code, this seems more straightforward and less error prone (you will still wait 3000ms, which is better than calling setFontsLoaded(true) after 0ms like in your code sample):

    try {
      await Font.loadAsync(fonts);
    } catch (e) {
      // Safari FontObserver timeout after 3000ms, this will fail silently
    }

I solved this with sdk35 with undocumented expo command

expo bundle-assets --platform android --dest ./android/app/src/main/assets

expo bundle-assets --help

  Usage: bundle-assets [options] [project-dir]

  Bundles assets for a detached app. This command should be executed from xcode or gradle.

  Options:

    --dest [dest]          Destination directory for assets
    --platform [platform]  detached project platform
    --config [file]        Specify a path to app.json
    -h, --help             output usage information

If you build with Android Studio rather than gradlew command, this is not run; so you have to run it manually before building.

Resolved when deleted node_modules and cleared cache