Skip to content

Commit 503a981

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/rive-ios-experimental
2 parents 7f5904d + 9831e19 commit 503a981

File tree

49 files changed

+2319
-336
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2319
-336
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.2.6"
2+
".": "0.2.7"
33
}

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [0.2.7](https://github.com/rive-app/rive-nitro-react-native/compare/v0.2.6...v0.2.7) (2026-03-06)
4+
5+
6+
### Features
7+
8+
* setting fallback fonts ([#152](https://github.com/rive-app/rive-nitro-react-native/issues/152)) ([e2c64ea](https://github.com/rive-app/rive-nitro-react-native/commit/e2c64eaf513085e52e543908a05c6598b2316d81))
9+
310
## [0.2.6](https://github.com/rive-app/rive-nitro-react-native/compare/v0.2.5...v0.2.6) (2026-03-05)
411

512

android/src/main/java/com/margelo/nitro/rive/Rive.kt renamed to android/src/main/java/com/margelo/nitro/rive/HybridDefaultFallbackFont.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,4 @@ import com.facebook.proguard.annotations.DoNotStrip
55

66
@Keep
77
@DoNotStrip
8-
class Rive : HybridRiveSpec() {
9-
override fun multiply(a: Double, b: Double): Double {
10-
return a * b
11-
}
12-
}
8+
class HybridDefaultFallbackFont : HybridFallbackFontSpec()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.margelo.nitro.rive
2+
3+
import androidx.annotation.Keep
4+
import com.facebook.proguard.annotations.DoNotStrip
5+
6+
@Keep
7+
@DoNotStrip
8+
class HybridFallbackFont(
9+
val fontBytes: ByteArray
10+
) : HybridFallbackFontSpec()
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.margelo.nitro.rive
2+
3+
import android.util.Log
4+
import androidx.annotation.Keep
5+
import app.rive.runtime.kotlin.fonts.FontFallbackStrategy
6+
import app.rive.runtime.kotlin.fonts.FontHelper
7+
import app.rive.runtime.kotlin.fonts.Fonts
8+
import com.facebook.proguard.annotations.DoNotStrip
9+
import com.margelo.nitro.NitroModules
10+
import com.margelo.nitro.core.ArrayBuffer
11+
import com.margelo.nitro.core.Promise
12+
import java.net.URL
13+
import kotlinx.coroutines.Dispatchers
14+
import kotlinx.coroutines.withContext
15+
16+
@Keep
17+
@DoNotStrip
18+
class HybridRiveFontConfig : HybridRiveFontConfigSpec() {
19+
companion object {
20+
private const val TAG = "RiveFonts"
21+
private const val DEFAULT_WEIGHT = 0
22+
private val fontsByWeight: MutableMap<Int, List<HybridFallbackFontSpec>> =
23+
java.util.Collections.synchronizedMap(mutableMapOf())
24+
25+
private fun resetFontCache() {
26+
try {
27+
FontFallbackStrategy.cppResetFontCache()
28+
} catch (e: Exception) {
29+
Log.e(TAG, "Failed to reset font cache: ${e.message}")
30+
}
31+
}
32+
}
33+
34+
override fun loadFontFromURL(url: String): Promise<HybridFallbackFontSpec> {
35+
return Promise.async {
36+
val fontBytes = withContext(Dispatchers.IO) {
37+
URL(url).readBytes()
38+
}
39+
HybridFallbackFont(fontBytes)
40+
}
41+
}
42+
43+
override fun loadFontFromResource(resource: String): HybridFallbackFontSpec {
44+
val context = NitroModules.applicationContext
45+
?: throw Error("Application context not available")
46+
47+
val resName = resource.substringBeforeLast(".")
48+
49+
val rawId = context.resources.getIdentifier(resName, "raw", context.packageName)
50+
if (rawId != 0) {
51+
val fontBytes = context.resources.openRawResource(rawId).use { it.readBytes() }
52+
return HybridFallbackFont(fontBytes)
53+
}
54+
55+
val fontId = context.resources.getIdentifier(resName, "font", context.packageName)
56+
if (fontId != 0) {
57+
val fontBytes = context.resources.openRawResource(fontId).use { it.readBytes() }
58+
return HybridFallbackFont(fontBytes)
59+
}
60+
61+
val assetPaths = listOf("fonts/$resource", resource)
62+
for (assetPath in assetPaths) {
63+
try {
64+
val fontBytes = context.assets.open(assetPath).use { it.readBytes() }
65+
return HybridFallbackFont(fontBytes)
66+
} catch (_: Exception) {
67+
}
68+
}
69+
70+
throw Error("Font resource not found: $resource (checked res/raw, res/font, assets/fonts)")
71+
}
72+
73+
override fun loadFontFromBytes(bytes: ArrayBuffer): HybridFallbackFontSpec {
74+
val buffer = bytes.getBuffer(false)
75+
val byteArray = ByteArray(buffer.remaining())
76+
buffer.get(byteArray)
77+
return HybridFallbackFont(byteArray)
78+
}
79+
80+
override fun loadFontByName(name: String): HybridFallbackFontSpec {
81+
val fonts = FontHelper.getFallbackFonts(Fonts.FontOpts(familyName = name))
82+
if (fonts.isEmpty()) {
83+
throw Error("System font not found: $name")
84+
}
85+
val fontBytes = FontHelper.getFontBytes(fonts.first())
86+
?: throw Error("Could not read font bytes for: $name")
87+
return HybridFallbackFont(fontBytes)
88+
}
89+
90+
override fun getSystemDefaultFont(): HybridFallbackFontSpec {
91+
return HybridDefaultFallbackFont()
92+
}
93+
94+
override fun setFontsForWeight(weight: Double, fonts: Array<HybridFallbackFontSpec>) {
95+
val key = weight.toInt()
96+
synchronized(fontsByWeight) {
97+
fontsByWeight[key] = fonts.toList()
98+
}
99+
}
100+
101+
override fun applyFallbackFonts(): Promise<Unit> {
102+
return Promise.async {
103+
FontFallbackStrategy.stylePicker = object : FontFallbackStrategy {
104+
override fun getFont(weight: Fonts.Weight): List<ByteArray> {
105+
val requestedWeight = weight.weight
106+
val specs = synchronized(fontsByWeight) {
107+
fontsByWeight[requestedWeight] ?: fontsByWeight[DEFAULT_WEIGHT] ?: emptyList()
108+
}
109+
return specs.mapNotNull { spec ->
110+
when (spec) {
111+
is HybridDefaultFallbackFont ->
112+
FontHelper.getFallbackFontBytes(Fonts.FontOpts(weight = weight))
113+
is HybridFallbackFont ->
114+
spec.fontBytes
115+
else -> {
116+
Log.e(TAG, "Unknown fallback font spec type: ${spec::class.simpleName}")
117+
null
118+
}
119+
}
120+
}
121+
}
122+
}
123+
resetFontCache()
124+
}
125+
}
126+
127+
override fun clearFallbackFonts(): Promise<Unit> {
128+
return Promise.async {
129+
synchronized(fontsByWeight) {
130+
fontsByWeight.clear()
131+
}
132+
FontFallbackStrategy.stylePicker = null
133+
resetFontCache()
134+
}
135+
}
136+
}
169 KB
Binary file not shown.
25.4 KB
Binary file not shown.
8.14 KB
Binary file not shown.

example/ios/RiveExample.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
1414
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
1515
F8EBA76E2DD7CE540010BBD0 /* rewards.riv in Resources */ = {isa = PBXBuildFile; fileRef = F8EBA76D2DD7CE540010BBD0 /* rewards.riv */; };
16+
F8EBA7712DD7CF000010BBD0 /* kanit_regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F8EBA7702DD7CF000010BBD0 /* kanit_regular.ttf */; };
1617
/* End PBXBuildFile section */
1718

1819
/* Begin PBXFileReference section */
@@ -27,6 +28,7 @@
2728
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>"; };
2829
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
2930
F8EBA76D2DD7CE540010BBD0 /* rewards.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = rewards.riv; sourceTree = "<group>"; };
31+
F8EBA7702DD7CF000010BBD0 /* kanit_regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = kanit_regular.ttf; sourceTree = "<group>"; };
3032
/* End PBXFileReference section */
3133

3234
/* Begin PBXFileSystemSynchronizedRootGroup section */
@@ -60,6 +62,7 @@
6062
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
6163
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,
6264
F8EBA76D2DD7CE540010BBD0 /* rewards.riv */,
65+
F8EBA7702DD7CF000010BBD0 /* kanit_regular.ttf */,
6366
);
6467
name = RiveExample;
6568
sourceTree = "<group>";
@@ -175,6 +178,7 @@
175178
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
176179
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
177180
F8EBA76E2DD7CE540010BBD0 /* rewards.riv in Resources */,
181+
F8EBA7712DD7CF000010BBD0 /* kanit_regular.ttf in Resources */,
178182
35B325D75078933C519F2ACC /* PrivacyInfo.xcprivacy in Resources */,
179183
);
180184
runOnlyForDeploymentPostprocessing = 0;

example/ios/kanit_regular.ttf

169 KB
Binary file not shown.

0 commit comments

Comments
 (0)