-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Out of band assets #285
base: main
Are you sure you want to change the base?
Out of band assets #285
Conversation
|
||
val source = assetData?.getMap("source") ?: return false // Do not handle the asset. | ||
|
||
CoroutineScope(Dispatchers.IO).launch { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ErikUggeldahl, your input here would be great on the best way to implement coroutine scope management (canceling it if the view is destroyed).
|
||
// Handle release mode (URL instead of asset id) | ||
// Resource needs to be loaded in release mode | ||
// https://github.com/facebook/react-native/issues/24963#issuecomment-532168307 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lancesnider would be great if we can give extra testing on this. It's handled differently between a dev and release build.
@@ -104,6 +108,10 @@ type Props = { | |||
testID?: string; | |||
alignment?: Alignment; | |||
artboardName?: string; | |||
/** | |||
* @experimental This is an experimental feature and may change without a major version update (breaking change). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opinions on marking this as experimental?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's probably a good idea, especially since we're likely to have a major overhaul of the runtime relatively soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great!
I really like the assetsHandled
object. I think it'll be easier for users to grasp than assetLoader
which requires some extra steps. If I'm understanding correctly the downside is that you can only define a referenced asset at load time, but not at runtime. I'm assuming that has to do with the limitation you mentioned in the video where we can't have a callback?
I love that you don't need to add assets to Bundled Assets
in iOS, but I'm not sure I understand why.
// path: 'fonts', // only needed for Android assets | ||
// }, | ||
}, | ||
'referenced-image-2929282': { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though I'd prefer not to need the ID, I think using it by default is probably necessary, given the fact that it's possible to have multiple assets with the same name. I could see users being very confused when both fonts named Tomorrow
display the same even though one of them is actually supposed to be a different weight.
I really like the idea of being able to override the default behavior with includeId
. Do you have thoughts on that being a global attribute, rather than on a per-asset basis?
// | ||
// The key of the map is the unique asset identifier (as exported in the Editor), | ||
// which is a combination of the asset name and its unique identifier. | ||
assetsHandled={{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's your thinking on the name assetsHandled
? My first thought would be to call this referencedAssets
to align it with the naming in the editor, but maybe that's too restricting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've also been toying with thinking of a different name for this.
@@ -104,6 +108,10 @@ type Props = { | |||
testID?: string; | |||
alignment?: Alignment; | |||
artboardName?: string; | |||
/** | |||
* @experimental This is an experimental feature and may change without a major version update (breaking change). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's probably a good idea, especially since we're likely to have a major overhaul of the runtime relatively soon.
sourceAsset?: string; | ||
sourceAssetId?: string; | ||
path?: string; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth being explicit that exactly one of sourceUrl
, sourceAsset
and path
is required?
type FileAssetSource =
| {
sourceUrl: string
sourceAsset?: never
path?: never
sourceAssetId: string
}
| {
sourceAsset: string
sourceUrl?: never
path?: never
sourceAssetId: string
}
| {
path: string
sourceUrl?: never
sourceAsset?: never
sourceAssetId: string
}
```
// path: 'images', // only needed for Android assets | ||
// }, | ||
}, | ||
'referenced_audio-2929340': { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no scenario where the asset IDs might change, is there? For example, if the Rive file gets copied or if you reimport a PSD? That could be painful if you have a giant object with ID's included.
Adds clarity and formatting.
Couple more quick formatting changes.
Great work and thank you so much for doing this ❤️ I'm not sure what is the "ID" tbh, how would we obtain it so we know what to set the key to, but if it it depends on the Thank you |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There may be some more RN-specific comments left, but generally from the Swift side of things, things look great! I left some comments about things we previously discussed during a live walkthrough.
@@ -64,6 +64,10 @@ func createMalformedFileError() -> NSError { | |||
return NSError(domain: RiveErrorDomain, code: RiveErrorCode.malformedFile.rawValue, userInfo: [NSLocalizedDescriptionKey: "Malformed Rive File", "name": "Malformed"]) | |||
} | |||
|
|||
func createAssetFileError(_ assetName: String) -> NSError { | |||
return NSError(domain: RiveErrorDomain, code: RiveErrorCode.malformedFile.rawValue, userInfo: [NSLocalizedDescriptionKey: "Could not load Rive asset: \(assetName)", "name": "Malformed"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicky, but I would maybe use .fileNotFound
rather than malformed as the error code.
// | ||
// The key of the map is the unique asset identifier (as exported in the Editor), | ||
// which is a combination of the asset name and its unique identifier. | ||
assetsHandled={{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've also been toying with thinking of a different name for this.
} | ||
} | ||
|
||
private func processAssetBytes(_ data: Data, asset: RiveFileAsset, factory: RiveFactory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth having another check here to validate that data.isEmpty == false
.
} | ||
|
||
private func splitFileNameAndExtension(fileName: String) -> (name: String?, ext: String?)? { | ||
let components = fileName.split(separator: ".") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any documentation surrounding naming? This might not work as intended, for example, if a user has an asset name with a .
in it.
return (name: String(components[0]), ext: String(components[1])) | ||
} | ||
|
||
private func loadResourceAsset(sourceAsset: String, path: String?, listener: @escaping (Data) -> Void) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed live, but path is currently ignored. This is understandable as a first-pass, with the expectation being that the file is already in the bundle's Resources
directory. There may be a time where we wish to expand this API to support further paths.
Love the ability to load assets different ways. As mentioned by others, we still really need the ability to replace an asset at run time. For our use case, we have an image that represents a topic. The user can shuffle this topic, so the current image gets replaced with another image. These images are dynamic (UGC). So we only know them at run time. In our case we'd want have two referenced images that we toggle between, allowing a the theoretically infinite number or images to be displayed as there is no hard limit to the number of shuffles. If that was too long to follow: we have a need for the API to also allow us to replace an image after the animation loads any number of times, like the JS web rumtime supports (though I do think this API is simpler/cleaner so if there's a way to combine the ideas that would be awesome). |
This PR adds out of band asset support to Rive React Native.
rev file used in the video:
out_of_band.rev.zip
Video:
https://drive.google.com/file/d/1jDZY2MRLhLfV8EOpRz3rVcCRbTdkv6sI/view?usp=sharing
Edit: