Paras Watts
Paras Watts

Reputation: 2665

How to play vimeo videos in React Native?

I have a requirement to play Vimeo videos in my react native app. I am using webview to play videos, Videos play but I can not see anything on screen, audio is coming but the screen is blank. Below is my code. Is there something I am doing wrong or any other way to play Vimeo ? Any help would be appreciated.

<AutoHeightWebView
    startInLoadingState
    style={{ width: "100%", height: '100%', borderColor: 'white', borderWidth: 2 }}
    source={{
        uri: 'https://player.vimeo.com/video/299264098?autoplay=1' //'this.state.videoUrl'
    }}
    onError={() => console.log('on error')}
    onLoad={() => console.log('on load')}
    onLoadStart={() => console.log('on load start')}
    onLoadEnd={() => console.log('on load end')}

    bounces={false}
/>

Upvotes: 6

Views: 27078

Answers (7)

Mudit Gulgulia
Mudit Gulgulia

Reputation: 1266

Bit late to answer but anyone seeking the solution yet, can either use React Native Video or Can use Iframe from package react-native-vimeo-iframe

Will share the code to use with react-native-vimeo-iframe

  1. Import the necessary components and hooks:
import React, { useState } from 'react';
import { View, StyleSheet, Text } from 'react-native';
import { Vimeo } from 'react-native-vimeo-iframe';
  1. Create a functional component called VideoPlayer that takes a videoId prop as input:
const VideoPlayer = ({ videoId }) => {
  // ...
}
  1. Define a state variable and a corresponding setter for each event that you want to handle using the useState hook:
const [isPlaying, setIsPlaying] = useState(false);
const [currentTime, setCurrentTime] = useState(0);
const [played, setPlayed] = useState(0);
const [loaded, setLoaded] = useState(0);
const [volume, setVolume] = useState(1);
const [error, setError] = useState(null);
  1. Define event handler functions for each event that you want to handle:
const handleReady = () => {
  console.log('Player is ready');
};

const handlePlay = () => {
  console.log('Video started playing');
  setIsPlaying(true);
};

const handlePause = () => {
  console.log('Video paused');
  setIsPlaying(false);
};

const handleEnded = () => {
  console.log('Video ended');
  setIsPlaying(false);
};

const handleTimeUpdate = ({ currentTime, duration }) => {
  console.log('Current time:', currentTime);
  setCurrentTime(currentTime);
};

const handleProgress = ({ played, loaded }) => {
  console.log('Played:', played, 'Loaded:', loaded);
  setPlayed(played);
  setLoaded(loaded);
};

const handleSeeked = () => {
  console.log('Seeked to new position');
};

const handleVolumeChange = (newVolume) => {
  console.log('Volume changed to:', newVolume);
  setVolume(newVolume);
};

const handleError = (error) => {
  console.log('Error:', error);
  setError(error);
};
  1. Return Vimeo player component with all the required props and event handlers.
return (
  <View style={styles.container}>
    <Vimeo
      videoId={videoId}
      autoplay={false}
      loop={false}
      controls={true}
      onReady={handleReady}
      onPlay={handlePlay}
      onPause={handlePause}
      onEnded={handleEnded}
      onTimeUpdate={handleTimeUpdate}
      onProgress={handleProgress}
      onSeeked={handleSeeked}
      onVolumeChange={handleVolumeChange}
      onError={handleError}
    />
    <Text style={styles.text}>
      {isPlaying ? 'Playing' : 'Paused'} at {currentTime} seconds
    </Text>
    <Text style={styles.text}>
      Played: {played.toFixed(2)}, Loaded: {loaded.toFixed(2)}
    </Text>
    <Text style={styles.text}>Volume: {volume.toFixed(2)}</Text>
    {error && <Text style={styles.text}>Error: {error.message}</Text>}
  </View>
);
  1. Define StyleSheet
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#000',
  },
  text: {
    color: '#fff',
    textAlign: 'center',
    marginVertical: 10,
  },
});

export default VideoPlayer;

Upvotes: 2

Gh05d
Gh05d

Reputation: 8982

You can use the oEmbed api that Vimeo provides. It will generate an embeddable <iframe> element for the video in question. You can use a function in a hook like this:

React.useEffect(() => {
setLoading(true);

(async function init() {
  try {
    const urlParts = url.split("/");
    const channelID = urlParts[urlParts.length - 2];
    const videoID = urlParts[urlParts.length - 1];
    const videoURL = `https://vimeo.com/${channelID}/${videoID}`;

    const requestURL = `https://vimeo.com/api/oembed.json?url=${videoURL}&height=${400}`;

    const { data } = await axios(requestURL);
    setHtml(data.html);
  } catch (err) {
    console.error(err);
  } finally {
    setLoading(false);
  }
})();
}, [url]);

The videoURL parameter will depend on the kind of channel the video was posted on.

Upvotes: 0

Marius Brataas
Marius Brataas

Reputation: 642

Short answer: Use the progressive files, not hls. These seem to contain links to mp4-files, which expo-av supports on both Android and iOS, no matter if your project is a bare React Native project, or managed by Expo.

Similar to the solution posted by Zuhair Naqi, but use the url from an object in res.request.files.progressive, rather than res.request.files.hls.cdns[res.request.files.hls.default_cdn].url

The function in the below example will return a list of objects containing links to that video at different resolutions.

function getVimeoLinks(url: string) {
  return fetch(`https://vimeo.com/api/oembed.json?url=${url}`, {
    headers: {
      'content-type': 'application/json',
      accept: 'application/json'
    }
  })
    .then(r => r.json())
    .then(({ video_id }) =>
      fetch(`https://player.vimeo.com/video/${video_id}/config`)
    )
    .then(r => r.json())
    .then(
      r =>
        r.request.files.progressive as {
          profile: number;
          width: number;
          mime: string;
          fps: number;
          url: string;
          cdn: string;
          quality: string;
          id: number;
          origin: string;
          height: number;
        }[]
    );
}

then, for your component, do something like this:

import { Video } from 'expo-av';

// Hook for getting some Vimeo video url (mp4)
function useVimeoUrl(url: string) {
  const [state, setState] = useState<undefined | string>();
  useEffect(() => {
    getVimeoConfig(url).then(r => setState(r[0].url));
  }, [url]);
  return state;
}

// Render video
function MyComponent({ url }: { url: string }) {
  // State containing video url
  const vimeoUrl = useVimeoUrl(url);

  // Render
  return vimeoUrl ? <Video source={{ uri: vimeoUrl }} /> : <></>;
}

Upvotes: 3

Lucas Gabriel
Lucas Gabriel

Reputation: 61

I was facing the same problem trying to display an embed Vimeo video in my app. The solution, using html content, as shown from Juliano worked very well for me

Upvotes: 1

Juliano Reis
Juliano Reis

Reputation: 221

I found a solution with embed iframe on webview.

import React from 'react';
import { string, func } from 'prop-types';
import WebView from 'react-native-autoheight-webview';

const VimeoPlayer = ({ videoId, onError }) => {
  return (
    <WebView
      style={style}
      onError={onError}
      allowsFullscreenVideo
      scrollEnabled={false}
      automaticallyAdjustContentInsets
      source={{
        html: `
          <html>
            <body>
              <iframe src="https://player.vimeo.com/video/${videoId}" width="100%" height="200px" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
              <script src="https://player.vimeo.com/api/player.js"></script>
            </body>
          </html>
        `,
      }}
    />
  );
};

const style = {
  height: 200,
  maxWidth: '100%',
};

VimeoPlayer.propTypes = {
  videoId: string,
  onError: func,
};

export default VimeoPlayer;

Upvotes: 6

Zuhair Naqi
Zuhair Naqi

Reputation: 1270

I found a way to run a vimeo video in react native. simply you've to request on URL to get it's detail config through vimeo id. Inside config you'll find videoUrl, that can be easily run on react-native-video-controls.

Here is example

const VIMEO_ID = '179859217';
fetch(`https://player.vimeo.com/video/${VIMEO_ID}/config`)
      .then(res => res.json())
      .then(res => this.setState({
        thumbnailUrl: res.video.thumbs['640'],
        videoUrl: res.request.files.hls.cdns[res.request.files.hls.default_cdn].url,
        video: res.video,
      }));

In Render

<VideoPlayer
        ref={ref => {
          this.player = ref;
        }}
        source={{uri: this.state.videoUrl}}
        navigator={this.props.navigator}
        fullscreen={true}
        resizeMode={'cover'}
      />

Upvotes: 18

Sateesh Yemireddi
Sateesh Yemireddi

Reputation: 4409

Try react-native-video package to play Vimeo videos in React Native project.

To install with npm

npm install --save react-native-video

or using yarn:

yarn add react-native-video

It is worth noting the issues that may occur in the links below.

https://stackoverflow.com/a/52976151/5519329

https://stackoverflow.com/a/39982973/5519329

Code:

import Video from 'react-native-video';

<Video source={{uri: "your url"}}   // Can be a URL or a local file.
       ref={(ref) => {
         this.player = ref
       }}                                      // Store reference
       onBuffer={this.onBuffer}                // Callback when remote video is buffering
       onEnd={this.onEnd}                      // Callback when playback finishes
       onError={this.videoError}               // Callback when video cannot be loaded
       style={styles.backgroundVideo} />

// Later on in your styles..
var styles = StyleSheet.create({
  backgroundVideo: {
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },
});

Upvotes: 2

Related Questions