Closed thejustinwalsh closed 5 months ago
This worked for me
getting Error "RiveReactNativeView" was not found in a UI Manager
"RiveReactNativeView" was not found in a UI Manager
same here
Have you found any solution on it ?
I think managed expo doesn't support rive-react-native yet
Seems eject is needed to do pod install
step for ios environment
I thought I didn't do anything special but just checked out my demo project and I am using Expo SDK > 42 and used EAS to build a custom Expo Application for testing the native extensions. EAS did the work of giving me an Expo Go app with the native dependencies.
Just to clarify for everyone, you don't need to "eject". You just need a custom dev client, made with expo prebuild
and expo run:ios
rather than Expo Go. Or, you can build the dev client/final app on EAS. As long as you don't use Expo Go, then you can use any native library with Expo.
For what it's worth, expo prebuild
didn't work for me, since I got a minimum deployment error. I fixed it by adding this plugin to my app.config.ts
:
import { withPodfileProperties } from "@expo/config-plugins"
export default {
plugins: [
withPodfileProperties,
(config) => {
config.modResults = {
...config.modResults,
"ios.deploymentTarget": "14.0",
};
return config;
},
],
}
Then expo run:ios
worked for me.
Looks like @nandorojo solution dosn't work for me. I keep getting:
✖ Config sync failed
TypeError: [ios.podfileProperties]: withIosPodfilePropertiesBaseMod: action is not a function
TypeError: [ios.podfileProperties]: withIosPodfilePropertiesBaseMod: action is not a function
But I did found a way around it which does work.
This is how my app.config.ts
looks like:
const baseConfig = {
name: 'app',
slug: 'app',
version: '1.0.0',
}
export default {
...baseConfig,
mods: {
ios: {
podfileProperties: (config: { modResults: any }) => {
config.modResults = {
...config.modResults,
'ios.deploymentTarget': '14.0'
}
return config
}
}
}
}
Then 'expo prebuild' and then expo run:ios
and everything works for me.
good to know, this may have changed with sdk 47
I was just about to add that my solution is tested on expo version 47.0.8. So yeah, you're probably right. Also, rive-react-native version 3.0.41.
@nandorojo @thehobbit85 you can also set the minimum deployment version using the expo-build-properties
config plugin.
{
"plugins": [
[
"expo-build-properties",
{
"ios": { "deploymentTarget": "14.0" }
}
]
]
}
@nandorojo @thehobbit85 you can also set the minimum deployment version using the
expo-build-properties
config plugin.{ "plugins": [ [ "expo-build-properties", { "ios": { "deploymentTarget": "14.0" } } ] ] }
This is the recommended approach now.
Use Expo Asset to load animations
Using the expo-asset module we can retrieve a full file URI to the animation that is bundled into our app, and load the animations using the
url
prop on theRive
component.App.tsx
import { StatusBar } from 'expo-status-bar'; import { Image, StyleSheet, Text, View } from 'react-native'; import Rive, { Alignment, Fit } from 'rive-react-native'; import { useAssets } from 'expo-asset'; export default function App() { const [assets, error] = useAssets([require('./assets/slime.riv')]); const animationUrl = assets?.[0].localUri; return ( <View style={styles.container}> {animationUrl && <Rive url={animationUrl} fit={Fit.Contain} alignment={Alignment.Center} style={styles.animation} autoplay /> } <StatusBar style="auto" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, animation: { width: 400, height: 400, } });
Unfortunately, this does not work on Android.
Recommend the Rive team prioritizes seamless Expo managed workflow support. If it doesn't then it makes the lib unusable for like 50%+ of React Native projects
I'm able to make it work with expo custom dev client on ios, but don't you guys have this problem where the initial frame before playing the animation is not the actual first frame of the animation ?
I'm able to make it work with expo custom dev client, but don't you guys have this problem where the initial frame before playing the animation is not the actual first frame of the animation ?
Hi there @perroudsky! Can you share the original/sample repo showing how you did this on Android?
Hi @dmahajan980, sorry i was talking about ios. Haven't tried on android yet
If it doesn't then it makes the lib unusable for like 50%+ of React Native projects
Indeed, and maybe even more than 50% on newer projects. Nowadays Expo is the default way of using React native, so not supporting expo will really hamper rive's adoption on new projects.
I came up with another strategy to integrate Rive animations into a React Native/Expo project. At the cost of a little bit of extra storage space and computation time, animations can be embedded into the JS bundle as base-64 encoded data-URI's.
Here's an example config using babel-plugin-inline-import-data-uri
:
// babel.config.js
module.exports = (api) => {
// ...
return {
plugins: [
['inline-import-data-uri', { extensions: ['.riv'] }]
]
}
};
// App.tsx
import { View } from 'react-native';
import Rive from 'rive-react-native';
import MyAnimation from './my-animation.riv';
export default function App() {
return (
<View>
<Rive
autoplay
url={MyAnimation}
style={{ width: 400, height: 400 }}
/>
</View>
);
}
With this method, nothing needs to change in the metro configuration since it explicitly avoids using the RN/metro asset pipeline.
Sadly, just like the expo-asset
method, this method only seems to work on iOS 😭 On Android, a native runtime error is logged:
[1047] NetworkDispatcher.processRequest: Unhandled exception java.lang.RuntimeException: Bad URL data:application/octet-stream;base64,...
The rive-react-native
android implementation and the rive-android
library both only support network protocols and not data:
, because riveUrl
is always processed with Android's Volley HTTP client, which is only meant to deploy network requests.
This might be the same issue that's causing the expo-asset
method to fail on Android too, since it resolves to a file:
protocol URL?
Update: I was able to work around this limitation on Android by patching the rive-react-native
library to manually decode the data-URI:
diff --git a/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt b/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt
index 12a0d808a2abe4a8a1b887b1bc58614f4c73dd05..8d37080b94e2faa44e8613ab791fad4237891510 100644
--- a/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt
+++ b/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt
@@ -19,6 +19,7 @@ import com.facebook.react.bridge.ReadableArray
import com.facebook.react.modules.core.ExceptionsManagerModule
import com.facebook.react.uimanager.ThemedReactContext
import java.io.UnsupportedEncodingException
+import java.util.Base64
import kotlin.IllegalStateException
@@ -299,6 +300,24 @@ class RiveReactNativeView(private val context: ThemedReactContext) : FrameLayout
private fun setUrlRiveResource(url: String, autoplay: Boolean = this.autoplay) {
+ if (url.startsWith("data:")) {
+ val b64data = url.substringAfter(',')
+ val decoder: Base64.Decoder = Base64.getDecoder()
+ val bytes = decoder.decode(b64data)
+
+ riveAnimationView.setRiveBytes(
+ bytes,
+ fit = this.fit,
+ alignment = this.alignment,
+ autoplay = autoplay,
+ stateMachineName = this.stateMachineName,
+ animationName = this.animationName,
+ artboardName = this.artboardName
+ )
+
+ return
+ }
+
val queue = Volley.newRequestQueue(context)
val stringRequest = RNRiveFileRequest(url, { bytes ->
try {
Disclaimer: This patch is kind of quick and dirty - it could probably be cleaner and more error-safe.
@nderscore Has this Android patch been holding up? If so, Would it be worth creating a PR for it?
@tslater I actually haven't been using it. The project I want to use Rive on doesn't have any animations (yet 😅)
I also don't love that my workaround relies on parsing somewhat-large data URL's in JS and passing them across the JS bridge to the native side - it's probably not very performant.
At some point, I would like to try an alternative patch to add local file URL support to the android portion of the library, which I think should unlock a path to using expo-assets
instead. I just haven't prioritized investigating that path yet.
@dmahajan980 Do you know why this doesn't work on android? Is the native code just not set up for local file URLs?
Has this issue been ignored by the Rive team so far? It looks like just because of it our team will stick with Lottie for a while.
It would be awesome to see Rive support for Expo out of the box.
Completing the circular reference:
https://help.rive.app/runtimes/overview/react-native/loading-in-rive-files
I don't recall if resourceName
was exposed or documented at the time of my initial request. Anyone on Android able to confirm that this method works?
expo-filesystem might be a better tool to use to get the paths to local assets here as well. I haven't tried this yet.
Lastly maybe having a ref method or prop that expects base64 encoded data is a solution that works as suggested above. expo-filesystem also exposes methods to return the riv file as a base64 encoded string through readAsStringAsync.
@nderscore Fantastic! ty!
as for me now. it's just make the app crash on ios and android, i already use prebuild
Posting this here for visibility: Docs on how to get Rive working with Expo: https://rive.app/community/doc/adding-rive-to-expo/docFSwIlblYi
The suggestion for a normal react-native app on how to add Rive assets apply to expo as well: https://rive.app/community/doc/loading-in-rive-files/doc8P5oDeLlH
There is also a plugin that automatically brings in files. See this issue for more info: https://github.com/rive-app/rive-react-native/issues/185#issuecomment-1937039990
We can potentially add that to the package. Closing this issue as the above docs exist now, and we can track adding assets in the linked issue.
@HayesGordon I'm not sure that I would consider this complete.
The documented solution requires a full rebuild of your native app (or your dev client) in order to add or update Rive assets. This also applies to the linked plugin.
Without explicit support for expo assets, it's missing two things that I would consider essential, as a developer building an app with Expo:
Without being able to use Expo Assets, this is just a vanilla react native integration. This is a blocker for me being able to adopt Rive in my app.
@HayesGordon I agree with @nderscore. There's a lot of developer pain involved here. Would you be open to a PR?
I finally have a solution that is in line with what I think we all are expecting. For now it requires 2 steps:
1) edit your metro config so that it knows to bundle *.riv
files:
config.resolver["assetExts"] = [
...(config.resolver.assetExts || []),
// for rive animations
"riv",
];
2) Write a wrapper around the default Rive component in order to get the url from the required asset:
import React, { forwardRef } from 'react';
import Rive, { RiveRef } from "rive-react-native";
// @ts-ignore
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
type RiveComponentProps = Omit<React.ComponentProps<typeof Rive>, 'url' | 'resourceName'> & {
source: any
}
export const RiveAnimation = forwardRef<RiveRef, RiveComponentProps>(
(props, ref) => {
const { source, ...riveProps } = props;
const resolved = resolveAssetSource(source);
return (
<Rive
ref={ref}
{...riveProps}
url={resolved.uri}
/>
);
}
);
Then you can call the component:
<RiveAnimation
source={require('assets/animations/your-animation.riv')}
{...otherProps}
/>
This works just like images in expo and react-native. In development, the file is served by metro, so it's super fast and dynamic to change images without builds or prebuilds. In production, the asset is bundled and the appropriate local uri is handled for you. It just works. I just tested in both environments and it works great. SOOOO much better than every other solution I've seen here on github.
Description
Documentation for working with Expo is lacking a workflow for loading animations.
Details
When attempting to load an animation in expo I hit a wall relatively quickly regarding animation loading. Sharing my notes with anyone else who is using Rive in Expo.
Setup Metro Bundler
Add resolution for
.riv
files so that we mayrequire
references to the assets.metro.config.js
Use Expo Asset to load animations
Using the expo-asset module we can retrieve a full file URI to the animation that is bundled into our app, and load the animations using the
url
prop on theRive
component.App.tsx