Skip to content

Commit 2ecd9e7

Browse files
mfazekasclaude
andcommitted
feat: add fromFileURL API for cross-platform file:// URL support
Adds `fromFileURL()` method to RiveFileFactory for loading .riv files from local file:// URLs on both iOS and Android. **Changes:** - Add `fromFileURL` to RiveFile.nitro.ts spec - Implement `fromFileURL` in iOS (HybridRiveFileFactory.swift) - Validates file:// URL scheme - Loads data from local file path - Runs on background thread (userInitiated QoS) - Implement `fromFileURL` in Android (HybridRiveFileFactory.kt) - Validates file:// URL scheme (matches iOS behavior) - Converts URI to file path using java.net.URI - Loads file on Dispatchers.IO background thread - Update `fromSource()` to use `fromFileURL()` for file:// URLs - Previously tried to parse resource name from path (fragile) - Now directly loads from file URL (more robust) - Regenerate Nitrogen boilerplate **Fixes:** Resolves production mode issue where iOS bundled assets resolve to file:// URLs instead of resource names, which was causing "Could not find Rive file" errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 4c610e8 commit 2ecd9e7

12 files changed

Lines changed: 136 additions & 5 deletions

File tree

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)