Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
37962ea
feat: unified async RiveFonts.addFallbackFont(source) API
mfazekas Feb 20, 2026
6814e51
fix: add kanit_regular.ttf to Xcode bundle resources
mfazekas Feb 23, 2026
a188657
fix: guard setRiveText call until instance is ready
mfazekas Feb 23, 2026
8540354
Revert "fix: guard setRiveText call until instance is ready"
mfazekas Feb 23, 2026
48c76e5
style: fix prettier formatting in FontFallbackExample
mfazekas Feb 23, 2026
7c3a850
test: track transient errors in harness test for reliable regression …
mfazekas Feb 23, 2026
96f8577
refactor: convert UseRiveStringContext to class
mfazekas Feb 23, 2026
3810783
feat: add system font by name support and array-based addFallbackFont…
mfazekas Feb 24, 2026
07a23e9
docs: add JSDoc to addFallbackFonts
mfazekas Feb 24, 2026
03b5d4b
refactor: batch font cache reset via applyFallbackFonts
mfazekas Feb 24, 2026
d372290
fix: ktlint try-catch-finally-spacing
mfazekas Feb 24, 2026
e1bc43b
refactor: two-phase font loading with weight-based fallback map
mfazekas Feb 27, 2026
8c5a01f
refactor: use 'default' key instead of 0 for fallback font weight map
mfazekas Feb 27, 2026
36aadef
fix: load only first matching system font in fallback strategy
mfazekas Mar 2, 2026
313d01a
refactor: extract DEFAULT_WEIGHT constant for fallback font weight map
mfazekas Mar 2, 2026
f58fd11
refactor: make system font fallback opt-in via 'default' sentinel
mfazekas Mar 4, 2026
ad1e74f
chore: remove uncommitted RiveInternal exports to fix CI
mfazekas Mar 4, 2026
4efeb5b
chore: regenerate nitrogen bindings without RiveInternal
mfazekas Mar 4, 2026
208eb41
chore: update Podfile.lock for RiveRuntime 6.15.2
mfazekas Mar 4, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@ import com.facebook.proguard.annotations.DoNotStrip

@Keep
@DoNotStrip
class Rive : HybridRiveSpec() {
override fun multiply(a: Double, b: Double): Double {
return a * b
}
}
class HybridDefaultFallbackFont : HybridFallbackFontSpec()
10 changes: 10 additions & 0 deletions android/src/main/java/com/margelo/nitro/rive/HybridFallbackFont.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.margelo.nitro.rive

import androidx.annotation.Keep
import com.facebook.proguard.annotations.DoNotStrip

@Keep
@DoNotStrip
class HybridFallbackFont(
val fontBytes: ByteArray
) : HybridFallbackFontSpec()
136 changes: 136 additions & 0 deletions android/src/main/java/com/margelo/nitro/rive/HybridRiveFontConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package com.margelo.nitro.rive

import android.util.Log
import androidx.annotation.Keep
import app.rive.runtime.kotlin.fonts.FontFallbackStrategy
import app.rive.runtime.kotlin.fonts.FontHelper
import app.rive.runtime.kotlin.fonts.Fonts
import com.facebook.proguard.annotations.DoNotStrip
import com.margelo.nitro.NitroModules
import com.margelo.nitro.core.ArrayBuffer
import com.margelo.nitro.core.Promise
import java.net.URL
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

@Keep
@DoNotStrip
class HybridRiveFontConfig : HybridRiveFontConfigSpec() {
companion object {
private const val TAG = "RiveFonts"
private const val DEFAULT_WEIGHT = 0
private val fontsByWeight: MutableMap<Int, List<HybridFallbackFontSpec>> =
java.util.Collections.synchronizedMap(mutableMapOf())

private fun resetFontCache() {
try {
FontFallbackStrategy.cppResetFontCache()
} catch (e: Exception) {
Log.e(TAG, "Failed to reset font cache: ${e.message}")
}
}
}

override fun loadFontFromURL(url: String): Promise<HybridFallbackFontSpec> {
return Promise.async {
val fontBytes = withContext(Dispatchers.IO) {
URL(url).readBytes()
}
HybridFallbackFont(fontBytes)
}
}

override fun loadFontFromResource(resource: String): HybridFallbackFontSpec {
val context = NitroModules.applicationContext
?: throw Error("Application context not available")

val resName = resource.substringBeforeLast(".")

val rawId = context.resources.getIdentifier(resName, "raw", context.packageName)
if (rawId != 0) {
val fontBytes = context.resources.openRawResource(rawId).use { it.readBytes() }
return HybridFallbackFont(fontBytes)
}

val fontId = context.resources.getIdentifier(resName, "font", context.packageName)
if (fontId != 0) {
val fontBytes = context.resources.openRawResource(fontId).use { it.readBytes() }
return HybridFallbackFont(fontBytes)
}

val assetPaths = listOf("fonts/$resource", resource)
for (assetPath in assetPaths) {
try {
val fontBytes = context.assets.open(assetPath).use { it.readBytes() }
return HybridFallbackFont(fontBytes)
} catch (_: Exception) {
}
}

throw Error("Font resource not found: $resource (checked res/raw, res/font, assets/fonts)")
}

override fun loadFontFromBytes(bytes: ArrayBuffer): HybridFallbackFontSpec {
val buffer = bytes.getBuffer(false)
val byteArray = ByteArray(buffer.remaining())
buffer.get(byteArray)
return HybridFallbackFont(byteArray)
}

override fun loadFontByName(name: String): HybridFallbackFontSpec {
val fonts = FontHelper.getFallbackFonts(Fonts.FontOpts(familyName = name))
if (fonts.isEmpty()) {
throw Error("System font not found: $name")
}
val fontBytes = FontHelper.getFontBytes(fonts.first())
?: throw Error("Could not read font bytes for: $name")
return HybridFallbackFont(fontBytes)
}

override fun getSystemDefaultFont(): HybridFallbackFontSpec {
return HybridDefaultFallbackFont()
}

override fun setFontsForWeight(weight: Double, fonts: Array<HybridFallbackFontSpec>) {
val key = weight.toInt()
synchronized(fontsByWeight) {
fontsByWeight[key] = fonts.toList()
}
}

override fun applyFallbackFonts(): Promise<Unit> {
return Promise.async {
FontFallbackStrategy.stylePicker = object : FontFallbackStrategy {
override fun getFont(weight: Fonts.Weight): List<ByteArray> {
val requestedWeight = weight.weight
val specs = synchronized(fontsByWeight) {
fontsByWeight[requestedWeight] ?: fontsByWeight[DEFAULT_WEIGHT] ?: emptyList()
}
return specs.mapNotNull { spec ->
when (spec) {
is HybridDefaultFallbackFont ->
FontHelper.getFallbackFontBytes(Fonts.FontOpts(weight = weight))
is HybridFallbackFont ->
spec.fontBytes
else -> {
Log.e(TAG, "Unknown fallback font spec type: ${spec::class.simpleName}")
null
}
}
}
}
}
resetFontCache()
}
}

override fun clearFallbackFonts(): Promise<Unit> {
return Promise.async {
synchronized(fontsByWeight) {
fontsByWeight.clear()
}
FontFallbackStrategy.stylePicker = null
resetFontCache()
}
}
}
Binary file not shown.
Binary file added example/assets/rive/fallback_fonts.riv
Binary file not shown.
Binary file added example/assets/rive/style_fallback_fonts.riv
Binary file not shown.
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1904,7 +1904,7 @@ PODS:
- ReactCommon/turbomodule/core
- RNWorklets
- Yoga
- RNRive (0.2.4):
- RNRive (0.2.5):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -2330,7 +2330,7 @@ SPEC CHECKSUMS:
RNCPicker: 28c076ae12a1056269ec0305fe35fac3086c477d
RNGestureHandler: 6b39f4e43e4b3a0fb86de9531d090ff205a011d5
RNReanimated: 66b68ebe3baf7ec9e716bd059d700726f250d344
RNRive: 5abb7e84bce9e6a0fe3ede1b366c442ac67dda75
RNRive: acc0d2356fbb2f65dce95b25cc154bdd0c8ceecc
RNWorklets: b1faafefb82d9f29c4018404a0fb33974b494a7b
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: 9f110fc4b7aa538663cba3c14cbb1c335f43c13f
Expand Down
4 changes: 4 additions & 0 deletions example/ios/RiveExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
F8EBA76E2DD7CE540010BBD0 /* rewards.riv in Resources */ = {isa = PBXBuildFile; fileRef = F8EBA76D2DD7CE540010BBD0 /* rewards.riv */; };
F8EBA7712DD7CF000010BBD0 /* kanit_regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F8EBA7702DD7CF000010BBD0 /* kanit_regular.ttf */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -27,6 +28,7 @@
E0AD05C932EEB95D292EBDBA /* Pods-RiveExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiveExample.release.xcconfig"; path = "Target Support Files/Pods-RiveExample/Pods-RiveExample.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F8EBA76D2DD7CE540010BBD0 /* rewards.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = rewards.riv; sourceTree = "<group>"; };
F8EBA7702DD7CF000010BBD0 /* kanit_regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = kanit_regular.ttf; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
Expand Down Expand Up @@ -60,6 +62,7 @@
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,
F8EBA76D2DD7CE540010BBD0 /* rewards.riv */,
F8EBA7702DD7CF000010BBD0 /* kanit_regular.ttf */,
);
name = RiveExample;
sourceTree = "<group>";
Expand Down Expand Up @@ -175,6 +178,7 @@
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
F8EBA76E2DD7CE540010BBD0 /* rewards.riv in Resources */,
F8EBA7712DD7CF000010BBD0 /* kanit_regular.ttf in Resources */,
35B325D75078933C519F2ACC /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Binary file added example/ios/kanit_regular.ttf
Binary file not shown.
Loading