How to play vimeo videos in React Native?

Viewed 18944

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}
/>
5 Answers

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'}
      />

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;

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,
  },
});

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

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 }} /> : <></>;
}
Related