From e1557afcc59c228ce99563f263759925926d1dfb Mon Sep 17 00:00:00 2001 From: Cristian Ceban <58264709+CristiCeban@users.noreply.github.com> Date: Thu, 8 Oct 2026 08:43:00 +0300 Subject: [PATCH 1/2] feat(docs): update docs about fonts + proguard rules --- .changeset/calm-shrinkers-pass.md | 5 ++ packages/repack/android/build.gradle | 1 + packages/repack/android/consumer-rules.pro | 5 ++ .../src/latest/api/loaders/assets-loader.md | 23 +++++- website/src/latest/docs/guides/_meta.json | 1 + website/src/latest/docs/guides/fonts.md | 72 +++++++++++++++++++ 6 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 .changeset/calm-shrinkers-pass.md create mode 100644 packages/repack/android/consumer-rules.pro create mode 100644 website/src/latest/docs/guides/fonts.md diff --git a/.changeset/calm-shrinkers-pass.md b/.changeset/calm-shrinkers-pass.md new file mode 100644 index 000000000..2aafab0b5 --- /dev/null +++ b/.changeset/calm-shrinkers-pass.md @@ -0,0 +1,5 @@ +--- +"@callstack/repack": patch +--- + +Ship consumer ProGuard rules for the Android library so release builds with R8 (`minifyEnabled true`) no longer fail with missing `com.google.errorprone.annotations` classes referenced by `nimbus-jose-jwt`. diff --git a/packages/repack/android/build.gradle b/packages/repack/android/build.gradle index 50bfc847f..824efd7fc 100644 --- a/packages/repack/android/build.gradle +++ b/packages/repack/android/build.gradle @@ -108,6 +108,7 @@ android { targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') versionCode 1 versionName "1.0" + consumerProguardFiles "consumer-rules.pro" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", IS_NEW_ARCHITECTURE_ENABLED.toString() externalNativeBuild { cmake { diff --git a/packages/repack/android/consumer-rules.pro b/packages/repack/android/consumer-rules.pro new file mode 100644 index 000000000..736ab74bb --- /dev/null +++ b/packages/repack/android/consumer-rules.pro @@ -0,0 +1,5 @@ +# Applied to apps that depend on Re.Pack when R8/ProGuard is enabled (minifyEnabled true). + +# nimbus-jose-jwt (used by code signing) bundles a shaded Gson that references +# Error Prone annotations. They are compile-time only and not on the runtime classpath. +-dontwarn com.google.errorprone.annotations.** diff --git a/website/src/latest/api/loaders/assets-loader.md b/website/src/latest/api/loaders/assets-loader.md index 85a64e7a0..10dda7dd6 100644 --- a/website/src/latest/api/loaders/assets-loader.md +++ b/website/src/latest/api/loaders/assets-loader.md @@ -3,7 +3,27 @@ The `AssetsLoader` processes image and other static assets (video, audio, etc.) in your React Native application. It handles asset extraction, copying files to the appropriate platform-specific output directories, and supports additional features like base64 inlining and conversion into remote assets. :::info Platform-Specific Output -By default, extracted asset files are copied to `assets/` directory for iOS and `drawable-*` directories (e.g. `drawable-mdpi`, `drawable-hdpi`, etc.) for Android which matches Metro's asset handling behavior. +By default, extracted asset files are copied to `assets/` directory for iOS and to Android resource directories for Android, which matches Metro's asset handling behavior. +::: + +### Android resource directories + +When bundling for Android without the development server, extracted assets are placed in the following resource directories: + +| Asset | Output directory | +| -------------------------------------------- | ---------------------------------------------------------------- | +| Images (`png`, `jpg`, `webp`, etc.) | `drawable-*` (e.g. `drawable-mdpi`, `drawable-hdpi`) per scale | +| Font binaries (`ttf`, `otf`, `ttc`) | `font` **and** `raw` | +| XML font families (``) | `font` | +| Other XML files | `drawable-*` | +| Everything else (video, audio, other files) | `raw` | + +Font binaries are emitted twice: the `font` copy keeps native references such as `@font/...` and `R.font` working, while the `raw` copy lets libraries that load fonts by name at runtime (e.g. [React Native Skia](https://shopify.github.io/react-native-skia/)) find them the same way they do with Metro. + +Re.Pack also generates `raw/keep.xml` listing all bundled Android resources. Assets loaded by name from JavaScript are invisible to the resource shrinker, so this file keeps them in the APK when `shrinkResources` is enabled. + +:::note +Development server builds and [remote assets](/docs/guides/remote-assets) are not copied into Android resource directories, so the layout above and `keep.xml` don't apply to them. ::: :::tip Guides related to AssetsLoader @@ -12,6 +32,7 @@ Looking to do more with your assets? Check out the guides on: - [Inlining assets as base64 strings](/docs/guides/inline-assets) - [Converting to remote assets](/docs/guides/remote-assets) - [Adding SVG support](/docs/guides/svg) +- [Using custom fonts](/docs/guides/fonts) ::: diff --git a/website/src/latest/docs/guides/_meta.json b/website/src/latest/docs/guides/_meta.json index aedf86538..65fc150aa 100644 --- a/website/src/latest/docs/guides/_meta.json +++ b/website/src/latest/docs/guides/_meta.json @@ -6,5 +6,6 @@ "inline-assets", "remote-assets", "svg", + "fonts", "deploy" ] diff --git a/website/src/latest/docs/guides/fonts.md b/website/src/latest/docs/guides/fonts.md new file mode 100644 index 000000000..c511cca22 --- /dev/null +++ b/website/src/latest/docs/guides/fonts.md @@ -0,0 +1,72 @@ +# Using custom fonts + +Font files (`ttf` and `otf`) are processed by the [Assets loader](/api/loaders/assets-loader) like any other asset, so you can `require` or `import` them from JavaScript. How you load the font afterwards depends on whether it is used by a JavaScript library or by native `` components. + +## Loading fonts from JavaScript + +Libraries that load fonts at runtime from an asset reference, such as [React Native Skia](https://shopify.github.io/react-native-skia/), work without any additional configuration: + +```jsx +import { useFont } from '@shopify/react-native-skia'; + +const font = useFont(require('./assets/fonts/Inter.ttf'), 24); +``` + +In development, the font is served by the development server. In release builds on Android, Re.Pack emits the font to both the `font` and `raw` resource directories and generates a `raw/keep.xml` file, so the font can be found by name and is kept when resource shrinking (`shrinkResources`) is enabled. See [Android resource directories](/api/loaders/assets-loader#android-resource-directories) for details. + +## Using fonts in native `` components + +Requiring a font file doesn't register it with the platform, so it can't be used with the `fontFamily` style yet. This is the same as with Metro. Use one of the following approaches. + +### Link fonts natively (recommended) + +Add the font files to the native projects so they are available in both debug and release builds: + +- **Android**: place the files in `android/app/src/main/assets/fonts/`. The file name (without extension) becomes the `fontFamily` value. +- **iOS**: add the files to your app target in Xcode and list them under `UIAppFonts` in `Info.plist`. The font's family name becomes the `fontFamily` value. + +```jsx +Hello +``` + +### Register fonts emitted by Re.Pack (Android release builds) + +In Android release builds, fonts bundled by Re.Pack are available as `font` resources, named after their path in the project (e.g. `assets/fonts/Inter.ttf` becomes `assets_fonts_inter`). You can register them in `MainApplication` with `ReactFontManager`: + +```kotlin title="MainApplication.kt" +import com.facebook.react.common.assets.ReactFontManager + +override fun onCreate() { + super.onCreate() + loadReactNative(this) + + val fontId = resources.getIdentifier("assets_fonts_inter", "font", packageName) + if (fontId != 0) { + ReactFontManager.getInstance().addCustomFont(this, "Inter", fontId) + } +} +``` + +:::warning Release builds only +When using the development server, fonts are served over HTTP and are not part of the Android resources, so the resource lookup above returns `0` and the font falls back to the system font. Link the font natively if you need it in debug builds as well. +::: + +## Font collections (`.ttc`) + +`ttc` files are not included in the default [asset extensions](/api/utils/constants#asset_extensions). To use them, add a rule that processes them with the Assets loader: + +```js title="rspack.config.cjs" +const Repack = require('@callstack/repack'); + +module.exports = { + module: { + rules: [ + ...Repack.getAssetTransformRules(), + { + test: /\.ttc$/, + use: '@callstack/repack/assets-loader', + }, + ], + }, +}; +``` From 65ed63782779f1012253b7af5d3ffc2f3c10a871 Mon Sep 17 00:00:00 2001 From: Cristian Ceban <58264709+CristiCeban@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:41:49 +0300 Subject: [PATCH 2/2] feat(docs): cr follow up --- website/src/latest/api/loaders/assets-loader.md | 16 +++++++++------- website/src/latest/docs/guides/fonts.md | 11 ++++++++++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/website/src/latest/api/loaders/assets-loader.md b/website/src/latest/api/loaders/assets-loader.md index 10dda7dd6..9d841ffd4 100644 --- a/website/src/latest/api/loaders/assets-loader.md +++ b/website/src/latest/api/loaders/assets-loader.md @@ -10,13 +10,15 @@ By default, extracted asset files are copied to `assets/` directory for iOS and When bundling for Android without the development server, extracted assets are placed in the following resource directories: -| Asset | Output directory | -| -------------------------------------------- | ---------------------------------------------------------------- | -| Images (`png`, `jpg`, `webp`, etc.) | `drawable-*` (e.g. `drawable-mdpi`, `drawable-hdpi`) per scale | -| Font binaries (`ttf`, `otf`, `ttc`) | `font` **and** `raw` | -| XML font families (``) | `font` | -| Other XML files | `drawable-*` | -| Everything else (video, audio, other files) | `raw` | +| Asset | Output directory | +| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------- | +| Images (`png`, `jpg`, `gif`, `webp`) | `drawable-*` (e.g. `drawable-mdpi`, `drawable-hdpi`) per scale | +| Font binaries (`ttf`, `otf`, `ttc`) | `font` **and** `raw` | +| XML font families (``) | `font` | +| Other XML files | `drawable-*` | +| Everything else (other image formats such as `jpeg` or `svg`, video, audio, other files) | `raw` | + +`xml` and `ttc` are not included in the default [asset extensions](/api/utils/constants#asset_extensions), so `getAssetTransformRules()` doesn't process them. To bundle them, add a rule that uses the Assets loader for these extensions. Font binaries are emitted twice: the `font` copy keeps native references such as `@font/...` and `R.font` working, while the `raw` copy lets libraries that load fonts by name at runtime (e.g. [React Native Skia](https://shopify.github.io/react-native-skia/)) find them the same way they do with Metro. diff --git a/website/src/latest/docs/guides/fonts.md b/website/src/latest/docs/guides/fonts.md index c511cca22..7b513c93d 100644 --- a/website/src/latest/docs/guides/fonts.md +++ b/website/src/latest/docs/guides/fonts.md @@ -31,7 +31,12 @@ Add the font files to the native projects so they are available in both debug an ### Register fonts emitted by Re.Pack (Android release builds) -In Android release builds, fonts bundled by Re.Pack are available as `font` resources, named after their path in the project (e.g. `assets/fonts/Inter.ttf` becomes `assets_fonts_inter`). You can register them in `MainApplication` with `ReactFontManager`: +In Android release builds, fonts bundled by Re.Pack are available as `font` resources. A font is only bundled if it is `require`d or `import`ed somewhere in your JavaScript code. The resource name comes from the font's path relative to the project root, not to the file that requires it (e.g. `assets/fonts/Inter.ttf` becomes `assets_fonts_inter`). You can register these fonts in `MainApplication` with `ReactFontManager`: + +```js title="index.js" +// makes Re.Pack bundle the font, even if it's only used by native +require('./assets/fonts/Inter.ttf'); +``` ```kotlin title="MainApplication.kt" import com.facebook.react.common.assets.ReactFontManager @@ -49,6 +54,8 @@ override fun onCreate() { :::warning Release builds only When using the development server, fonts are served over HTTP and are not part of the Android resources, so the resource lookup above returns `0` and the font falls back to the system font. Link the font natively if you need it in debug builds as well. + +The lookup also returns `0` in release builds if the font isn't required from JavaScript. Because of the `fontId != 0` check, this fails silently and the text uses the system font. ::: ## Font collections (`.ttc`) @@ -70,3 +77,5 @@ module.exports = { }, }; ``` + +This is enough for libraries that load fonts from JavaScript, such as React Native Skia. Native `` on Android only looks up `.ttf` and `.otf` files in `assets/fonts/`, so a `.ttc` file can't be linked natively there. In Android release builds, you can still register the `font` resource emitted by Re.Pack with [`addCustomFont`](#register-fonts-emitted-by-repack-android-release-builds).