How to display a video from an S3 bucket in React Native? - react-native

I am trying to download a video from an S3 bucket and pass it to Expo's Video component. I am using s3.getObject() and the callback function to get the object as an ArrayBuffer. But I don't know how to use this data from this point. I tried concatenating "data:video/mp4;base64," + videoData.body and passing that as an object. I also tried converting it to Base64String, which also didn't work.
let videoData = {}
const downloadIntro = async () => {
s3.getObject(bucketParams, function (err, data) {
if (err) {
console.log("Error:" + err)
} else {
console.log(data.ContentLength) // 1210362
console.log(data.ContentType) // video/mp4
console.log(data.Metadata) // Object {}
console.log(data.Body.buffer) // ArrayBuffer []
videoData.body = data.Body.buffer
}
})
}
export default function App() {
let [vidData, setVidData] = useState(null)
const playVideo = () => {
console.log("Trying to play")
setVidData({video: "data:video/mp4;base64," + videoData.body})
}
return (
<SafeAreaView style={styles.container}>
<Button title={"Load Video"} onPress={downloadIntro}/>
<Button title={"Start"} onPress={playVideo}/>
<Video
source={vidData}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode={"contain"}
shouldPlay={paused}
isLooping={false}
style={{
width: 300,
height: 300
}}
/>
</SafeAreaView>
);
}

It looks like you are trying to put the raw video data in the source. Try just setting the attribute to the url of the video :
<video controls width="250">
<source src="/media/cc0-videos/flower.mp4"
type="video/mp4">
</video>

Related

How to only load/render custom rendered image when it comes into view (react-native-render-html)

I am using react-native-render-html to render content that has images in it via a custom renderer. The issue I'm running into is some pages have dozens of images, and I would like to only download/render the ones I need that are in or near the viewport. The way the custom renderer is set up currently (via the documentation) it downloads all of them at once (How would I go about Implementing the logic into a more flatlist-like render system?
Here's the image renderer (if it helps):
const ImgRenderer = useCallback((props: any) => {
console.log('imgRendererProps: ', props)
const { Renderer, rendererProps } = useInternalRenderer('img', props);
const uri = rendererProps.source.uri;
const imgSource = {
...rendererProps.source,
// You could change the uri here, for example to provide a thumbnail.
uri: `https://home.website.com${uri?.split('about://')[1]}`
};
return (
<TouchableWithoutFeedback onPress={() => setModalImage(uri?.split('about://')[1] ?? null)}>
<Renderer {...rendererProps} source={imgSource} style={{resizeMode: 'contain'}} />
</TouchableWithoutFeedback>
);
}, [props.tnode?.init.nodeIndex])

Change videosource in React Native

Im using react-native-video in my react-native application. I want to be able to dynamically change videosource but found out it wasnt that easy. My approach is simply by changing the clip name with a hook, changing video1 to video2. But I was not able to update the videoinstance:
I did try something like this:
const [clipSelected, setClipSelected] = useState('video1');
const onButton = (name) => {
console.log("videoname", name)
setClipSelected(name);
}
return (
<Fragment>
<View style={styles.container}>
<Video
source={require('./' + clipSelected + '.mp4')}
ref={(ref) => {
bgVideo = ref
}}
onBuffer={this.onBuffer}
onError={this.videoError}
rate={1}
repeat={true}
/>
<Button onPress={(e) => onButton('video2')}></Button>
</View>
</Fragment >
);
Are there any other library, approach or method anyone are aware of where I can solve this? Basically a way to update the source instance of the video. Im going to run this on an Android TV ...
Use the status values to make changes.
const [clipSelected, setClipSelected] = useState(false);
const onButton = () => {
setClipSelected(true);
}
...
<Video
source={clipSelected === false ? require('./video1.mp4') : require('./video2.mp4')}
...
<Button onPress={(e) => onButton()}></Button>

How can I send a message from the WebView to React Native?

I’ve successfully managed to send a message from React Native (RN) to a WebView.
What I’m struggling with, is getting the message back from the WebView to RN. There’s no errors showing - it’s just that the message never gets through.
Here is the code which I’m using:
React Native Code
<WebView
ref={webview => (this.webview = webview)}
source={{ uri: "http://www.my-web-site"}}
onLoadEnd={() => this.onLoadEnd()}
onMessage={this.onMessage}
cacheEnabled={false}
originWhitelist={['*']}
javaScriptEnabled={true}
/>
onLoadEnd() {
this.webview.postMessage("RN message");
}
onMessage(message) {
console.log("I can’t see this message!");
}
WebView Code
document.addEventListener("message", function (event) {
setTimeout(function(){document.postMessage("WebView message")}, 3000);
}, false);
Please make sure that the data for each receiver is in and use the data that You need.
And always check the prescribed documents to see how to use parameters and grammar before using them.
RN
onLoadEnd() {
this.webview.postMessage("sendmessage");
}
onMessage(event) {
alert(event.nativeEvent.data);
}
WebView Code
document.addEventListener("message", function (event) {
window.postMessage(event.data);
});
React-native version 5.0 or later
window.ReactNativeWebView.postMessage(event.data);
Oh, at last, I finally came across the answer. It was a line of code which I had originally been trying to use to send a message from RN to the WebView. Turns out, it was the code required for sending from the WebView to RN:
WebView Code
document.addEventListener("message", function (event) {
window.ReactNativeWebView.postMessage(event.data);
}, false);
RN Code
<WebView onMessage={event => console.log(event.nativeEvent.data)} />
This works.
React Native
<WebView source={{ ... }}
containerStyle={{ ... }}
onMessage={ e => { console.log(e.nativeEvent.data) } }
/>
WebView
if(window.ReactNativeWebView) {
// send data object to React Native (only string)
window.ReactNativeWebView.postMessage(JSON.stringify(dataObject))
}
If you want to send complete object from webview to react-native android app then you need to stringify your object first
// Reactjs webapp
onClickSendObject = (item) => {
if(window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(JSON.stringify(item))
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
In react-native app use onMessage (for functional component)
<WebView
ref={webview => (this.webview = webview)}
source={{ uri: "give source url i.e your webapp link"}}
onMessage={m => onMessage(m.nativeEvent.data)} // functional component and for class component use (this.onMessage)
cacheEnabled={false}
originWhitelist={['*']}
javaScriptEnabled={true}
/>
// onMessage function
const onMessage = (m) => {
const messageData = JSON.parse(m);
console.log(messageData)
}
(window["ReactNativeWebView"] || window).postMessage('hello motiur dear','*');

WebView should use same cookies as fetch

I have done a sign in to my app using the native fetch API. I now need to load an image, so am loading it in a <WebView>, however the webview is not using the cookies from the fetch API outside of the webview. Is it possible to tell webview to use those cookies?
You can post a message containing your cookies content to your Webview using postMessage().
You need to get the ref of the Webview then post the message to your webview.
let webviewRef = null;
const cookiesContent = 'My cookies bla bla bla'
render() {
return (
<WebView
onLoad={() => webviewRef.postMessage(cookiesContent)}
ref={webview => { webviewRef = webview; }}
source={{ uri: 'https://YourUrl' }}
/>
);
}
Then in your Website you can create the cookies and use it
<script>
document.addEventListener("message", function(data) {
document.cookie=`cookiesName=${data.data}`;
});
</script>
If you aren't the owner of the website you can still try to inject the javascript with injectedJavaScript props of Webview Component.
const JsCode = 'document.addEventListener("message", function(data) {
document.cookie=`cookiesName=${data.data}`;
});';
<WebView
injectedJavaScript={JsCode}
onLoad={() => webviewRef.postMessage(cookiesContent)}
ref={webview => { webviewRef = webview; }}
source={{ uri: 'https://YourUrl' }}
/>
You can use https://github.com/react-native-community/cookies to get cookies and set them back

React Native WebView onMessage and postMessage to get all web page

I don't really clear how to implement onMessage and postMessage, can I get whole web page but only from react native side.
I mean, I will inject this code using injectedJavaScript
var markup = document.documentElement.innerHTML
window.postMessage(markup)
and I will receive the result using onMessage. Is it posible cause so far I can't do that
yes you can do this all you to have to do is use window.postMessage("message") from your web-page that is going to load in WebView and you can see that message in onMessage prop.
Example:
class Test extends React.Component{
constructor(props){
super(props);
this.state:{
html:''
}
}
componentWillMount(){
this.setState({
html : `<html>
<head>
<script>
window.postMessage("Messga from webView")
</script>
</head>
<body><h1>Hello from webView</h1></body>
</html>`
})
}
render(){
return (
<View style={{flex: 1}}>
<WebView
ref={(reff) => {
this.webView = reff;
}}
source={{html: this.state.html}}
style={[styles.flex1, styles.padding5]}
onMessage={(event)=>{
let message = event.nativeEvent.data;
/* event.nativeEvent.data must be string, i.e. window.postMessage
should send only string.
* */
}}
onNavigationStateChange={(evt)=>{}}
onError={(e) => {
console.warn('error occured', e)
}}/>
</View>
)
}
}
I just added a sample html and rendered it in WebView, you can do the same in your page that you are going to load in WebView.
Or another solution is:
You can use injectedJavaScript or injectJavaScript props of WebView as described here.
postMessage is deprecated :: and now you have to use window.ReactNativeWebView.postMessage(data)
const injectedJavascript = `(function() {
window.postMessage = function(data) {
window.ReactNativeWebView.postMessage(data);
};
})()`;
for a full imagination of a component will be:
export const WebViewComponent = (props) => {
const webViewScript = `
setTimeout(function() {
window.ReactNativeWebView.postMessage(/*your pushed data back to onMessage 'event.nativeEvent.data'*/);
}, 2500);
true; // note: this is required, or you'll sometimes get silent failures
`;
return (
<WebView
source={{
uri: `https://example.com`,
}}
automaticallyAdjustContentInsets={false}
scrollEnabled={false}
onMessage={(event) => {
// do something with `event.nativeEvent.data`
}}
javaScriptEnabled={true}
injectedJavaScript={webViewScript}
domStorageEnabled={true}
style={{ width: "100%", height: /*webViewHeight*/ }}
/>
);
};
Actually
i was looking at the documentation since i use the injectJavascript function of the react native´s webview. And in here https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage , it says that for extensions we need to use a "*" as a property .
So it wouldn´t be like this "window.postMessage("Messga from webView")"
Instead it will need to be window.postMessage("Messga from webView","*") to work.