Skip to content

Commit 09e0fae

Browse files
mfazekasclaudeHayesGordon
authored
fix: iOS production builds fail to load bundled .riv assets (#12)
* fix: iOS production asset loading Fixes production build issue where iOS bundled assets fail to load. **Problem:** On iOS, `resolveAssetSource()` returns file:// URLs for bundled assets: `file:///path/to/app/assets/rive/rewards_source.riv` The previous implementation tried to extract the filename and load it as a bundle resource, which only worked in debug builds. In production, assets are packaged as actual files in the app bundle, not as named resources accessible via `Bundle.main.path(forResource:)`. **Previous approach (broken in production):** ```typescript // Extract "rewards_source" from file URL const match = assetURI.match(/file:\/\/(.*\/)+(.*)\.riv/); return RiveFileFactory.fromResource(match[2], loadCdn); // ❌ Failed: "Could not find Rive file: rewards_source.riv" ``` **New approach (works in debug and production):** ```typescript // Load directly from file:// URL return RiveFileFactory.fromFileURL(assetURI, loadCdn); // ✅ Reads file directly from disk ``` **Implementation:** - Added `fromFileURL` to `RiveFile.nitro.ts` spec - Implemented `fromFileURL` in iOS (`HybridRiveFileFactory.swift`) - Validates file:// URL scheme - Loads data directly from file path using `Data(contentsOf:)` - Runs on background thread - Implemented `fromFileURL` in Android (`HybridRiveFileFactory.kt`) - Matches iOS validation behavior - Converts URI to path using `java.net.URI` - Loads on `Dispatchers.IO` background thread - Updated `fromSource()` to use `fromFileURL()` for file:// URLs - Regenerated Nitrogen boilerplate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Update src/core/RiveFile.ts Co-authored-by: Gordon <pggordonhayes@gmail.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Gordon <pggordonhayes@gmail.com>
1 parent 70c06a6 commit 09e0fae

File tree

12 files changed

+135
-5
lines changed

12 files changed

+135
-5
lines changed

android/src/main/java/com/margelo/nitro/rive/HybridRiveFileFactory.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import com.margelo.nitro.core.Promise
99
import com.margelo.nitro.NitroModules
1010
import kotlinx.coroutines.Dispatchers
1111
import kotlinx.coroutines.withContext
12+
import java.io.File as JavaFile
13+
import java.net.URI
1214
import java.net.URL
1315

1416
@Keep
@@ -33,6 +35,31 @@ class HybridRiveFileFactory : HybridRiveFileFactorySpec() {
3335
}
3436
}
3537

38+
override fun fromFileURL(fileURL: String, loadCdn: Boolean): Promise<HybridRiveFileSpec> {
39+
if (!fileURL.startsWith("file://")) {
40+
throw Error("fromFileURL: URL must be a file URL: $fileURL")
41+
}
42+
43+
return Promise.async {
44+
try {
45+
val uri = URI(fileURL)
46+
val path = uri.path ?: throw Error("fromFileURL: Invalid URL: $fileURL")
47+
48+
val riveFile = withContext(Dispatchers.IO) {
49+
val file = JavaFile(path)
50+
val riveData = file.readBytes()
51+
File(riveData)
52+
}
53+
54+
val hybridRiveFile = HybridRiveFile()
55+
hybridRiveFile.riveFile = riveFile
56+
hybridRiveFile
57+
} catch (e: Exception) {
58+
throw Error("Failed to load Rive file: ${e.message}")
59+
}
60+
}
61+
}
62+
3663
@SuppressLint("DiscouragedApi")
3764
override fun fromResource(resource: String, loadCdn: Boolean): Promise<HybridRiveFileSpec> {
3865
return Promise.async {

ios/HybridRiveFileFactory.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,45 @@ class HybridRiveFileFactory: HybridRiveFileFactorySpec {
3838
}
3939
}
4040

41+
func fromFileURL(fileURL: String, loadCdn: Bool) throws -> Promise<(any HybridRiveFileSpec)> {
42+
guard let url = URL(string:fileURL) else {
43+
throw RuntimeError.error(withMessage: "fromFileURL: Invalid URL: \(fileURL)")
44+
}
45+
46+
guard url.isFileURL else {
47+
throw RuntimeError.error(withMessage: "fromFileURL: URL must be a file URL: \(fileURL)")
48+
}
49+
50+
return Promise.async {
51+
do {
52+
let riveFile = try await withCheckedThrowingContinuation { continuation in
53+
DispatchQueue.global(qos: .userInitiated).async {
54+
do {
55+
let data = try Data(contentsOf: url)
56+
57+
let riveFile = try RiveFile(data: data, loadCdn: loadCdn)
58+
DispatchQueue.main.async {
59+
continuation.resume(returning: riveFile)
60+
}
61+
} catch {
62+
DispatchQueue.main.async {
63+
continuation.resume(throwing: error)
64+
}
65+
}
66+
}
67+
}
68+
69+
let hybridRiveFile = HybridRiveFile()
70+
hybridRiveFile.riveFile = riveFile
71+
return hybridRiveFile
72+
} catch let error as NSError {
73+
throw RuntimeError.error(withMessage: "Failed to load Rive file: \(error.localizedDescription)")
74+
} catch {
75+
throw RuntimeError.error(withMessage: "Unknown error occurred while loading Rive file")
76+
}
77+
}
78+
}
79+
4180
func fromResource(resource: String, loadCdn: Bool) throws -> Promise<(any HybridRiveFileSpec)> {
4281
guard let _ = Bundle.main.path(forResource: resource, ofType: "riv") else {
4382
throw RuntimeError.error(withMessage: "Could not find Rive file: \(resource).riv")

nitrogen/generated/android/c++/JHybridRiveFileFactorySpec.cpp

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nitrogen/generated/android/c++/JHybridRiveFileFactorySpec.hpp

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridRiveFileFactorySpec.kt

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nitrogen/generated/ios/c++/HybridRiveFileFactorySpecSwift.hpp

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nitrogen/generated/ios/swift/HybridRiveFileFactorySpec.swift

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nitrogen/generated/ios/swift/HybridRiveFileFactorySpec_cxx.swift

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nitrogen/generated/shared/c++/HybridRiveFileFactorySpec.cpp

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nitrogen/generated/shared/c++/HybridRiveFileFactorySpec.hpp

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)