Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/calm-shrinkers-pass.md
Original file line number Diff line number Diff line change
@@ -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`.
1 change: 1 addition & 0 deletions packages/repack/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions packages/repack/android/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -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.**
25 changes: 24 additions & 1 deletion website/src/latest/api/loaders/assets-loader.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,29 @@
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`, `gif`, `webp`) | `drawable-*` (e.g. `drawable-mdpi`, `drawable-hdpi`) per scale |
| Font binaries (`ttf`, `otf`, `ttc`) | `font` **and** `raw` |
| XML font families (`<font-family>`) | `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.

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
Expand All @@ -12,6 +34,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)

:::

Expand Down
1 change: 1 addition & 0 deletions website/src/latest/docs/guides/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"inline-assets",
"remote-assets",
"svg",
"fonts",
"deploy"
]
81 changes: 81 additions & 0 deletions website/src/latest/docs/guides/fonts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# 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 `<Text>` 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 `<Text>` 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
<Text style={{ fontFamily: 'Inter' }}>Hello</Text>
```

### Register fonts emitted by Re.Pack (Android release builds)

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 <Text>
require('./assets/fonts/Inter.ttf');
```

```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.

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`)

`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:
Comment thread
CristiCeban marked this conversation as resolved.

```js title="rspack.config.cjs"
const Repack = require('@callstack/repack');

module.exports = {
module: {
rules: [
...Repack.getAssetTransformRules(),
{
test: /\.ttc$/,
use: '@callstack/repack/assets-loader',
},
],
},
};
```

This is enough for libraries that load fonts from JavaScript, such as React Native Skia. Native `<Text>` 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).