Learning project: build an Expo config plugin that natively links TTF icon fonts for iOS & Android.
- Links TTF fonts to iOS (Xcode Copy Bundle Resources +
UIAppFonts) & Android (assets/fonts/) - Patches the PostScript name embedded in each TTF to match its filename — so
fontFamilyworks identically on both platforms, even when multiple fonts share the same internal name (common with fontello exports) - Ships a standalone script to patch fonts manually before committing
plugins/
withIconFont.ts # Expo config plugin — links fonts to iOS & Android
scripts/
patchFontName.ts # Patches PostScript names in TTF files in-place
assets/fonts/brix/
filled-icon-font.ttf
line-rounded-icon-font.ttf
line-square-icon-font.ttf
src/components/brix-icons/
BrixFilledIcon.tsx # <BrixFilledIcon name="home" size={24} color="#000" />
BrixLineRoundedIcon.tsx
BrixLineSquareIcon.tsx
IconShowcase.tsx # Grid layout used by each tab
Run this once after downloading new fonts. It modifies each TTF in-place so the PostScript name matches the filename.
npm run patch-fonts -- assets/fonts/brix/*.ttfCommit the patched TTF files.
Add font paths to app.config.ts:
withIconFont(config, {
fonts: [
'./assets/fonts/brix/filled-icon-font.ttf',
'./assets/fonts/brix/line-rounded-icon-font.ttf',
'./assets/fonts/brix/line-square-icon-font.ttf',
],
})npx expo prebuildThe plugin copies each font to the correct native directory and registers it.
import { BrixFilledIcon } from '@/components/brix-icons/BrixFilledIcon';
<BrixFilledIcon name="home" size={24} color="#333" />fontFamily maps to the filename without extension — filled-icon-font, line-rounded-icon-font, line-square-icon-font — on both iOS & Android.
withInfoPlist— adds each filename toUIAppFontsso CoreText registers the fontwithXcodeProject— copies the TTF toios/<AppName>/Fonts/& adds it to Copy Bundle Resources viaIOSConfig.XcodeUtils.addResourceFileToGroup
withDangerousMod — copies the TTF to android/app/src/main/assets/fonts/. React Native resolves fonts by filename on Android, so no additional registration is needed.
iOS identifies fonts by their PostScript name (nameID 6 in the TTF name table), not by filename. Fontello exports all ship with PostScript name fontello — load 3 of them at once and only 1 is accessible. The patcher rebuilds the name table in memory, replacing nameIDs 1, 4 & 6 with the filename, then recomputes the table & head.checkSumAdjustment checksums.
| Command | Description |
|---|---|
npm run patch-fonts -- <file.ttf> |
Patch PostScript name to match filename |
npx expo prebuild |
Generate native projects with fonts linked |
npm run ios |
Build & run on iOS |
npm run android |
Build & run on Android |