Siphon is shutting down on 27th July 2016. To our customers, users and supporters: unfortunately this is the end of the road for Siphon. Our long-term goal was to create the most developer friendly end-to-end publishing platform for mobile apps.

Due to some inherent limitations in the early design decisions that we made (in particular the inability to compile your own native modules with Siphon) we have come to the regrettable conclusion that this vision is not possible at this time. We hoped that these native bridged modules would mature and become less important over time, but this has turned out to not be the case.

All apps created using Siphon are fully compatible with the standard React Native framework and transferring your app should only take a few minutes. Please email us if you need any help migrating your app.

Thanks to everyone who supported us over the past few months.
/docs
Fundamentals Quickstart FAQ Native modules Base versions Running on your device How publishing works Assets Ignoring files Over-the-air updates Convert an existing React Native app Sharing Beta testing Collaborating in a team Tutorials Build a real-time chat app Build a YouTube video browser Using Facebook's SDK with Siphon Turn an existing React Native app into a Siphon app Siphon Sandbox iOS (App Store) Android (Google Play)
Build a YouTube playlist browser with React Native and Siphon

We're going to use Siphon to quickly build a React Native app from scratch. The finished app will display a live YouTube playlist and let you play a video by tapping it.

You will learn all about:

Please follow the quickstart tutorial first if you haven't already set up your machine to use Siphon.

Install the command-line tool

The finished app will look something like this:

Create a new Siphon app

First, navigate to a suitable directory (anywhere is fine) and type the following command to create a new app:

$ siphon create youtube-browser

You can call it anything you like, but for the rest of this tutorial we will refer to the app as youtube-browser.

A new directory containing the basic app template will be created on your local machine and the files will be pushed to our servers.

Open up the Siphon Sandbox app on your iOS device and tap the new app icon to run it. Alternatively, if you have a Mac, you can also run it standalone on your iOS device like this:

$ cd youtube-browser
$ siphon play

Or to run it on an iOS simulator with access to the full React Native debugging environment you can use the develop command:

$ cd youtube-browser
$ siphon develop
Remove the template app content

We want to start with a blank slate, so let's remove all of the views that come with the template app.

Open up the youtube-browser/index.js file in your favourite editor and edit it so that it looks like this:


'use strict';

var React = require('react-native');
var {
  AppRegistry,
  Text
} = React;

var App = React.createClass({
  render: function() {
    return <Text style={{ padding: 100 }}>Blank app.</Text>;
  }
});

AppRegistry.registerComponent('App', () => App);

When you hit save, run siphon push and the app will reload itself. You should see some basic text.

Add a placeholder for the video list screen

Later we're going to need a view to display a list of video thumbnails, so lets add a placeholder for that now. Make a new subdirectory within your app's directory:

$ mkdir components

Then, using your chosen text editor, make a new file in the components subdirectory, call it VideoListView.js, and paste in the following code:


var React = require('react-native');
var {
  ScrollView,
  Image,
  TouchableOpacity
} = React;

var VideoListView = React.createClass({
  getInitialState: function() {
    return {
      videos: []
    }
  },
  render: function() {
    return (
      <ScrollView>
        {
          this.state.videos.map(video => {
            return (
              <TouchableOpacity>
                <Image
                  source={{uri: video.thumbnail}}
                  style={{height: 280}}
                  resizeMode={Image.resizeMode.cover}
                />
              </TouchableOpacity>
            )
          })
        }
      </ScrollView>
    );
  }
});

module.exports = VideoListView;

Notice that it's ready to render an <Image> component for each video in the playlist, but for now it will be empty because we have no data.

Next, edit your index.js file to import and display our new list view:


'use strict';

var React = require('react-native');
var {
  AppRegistry
} = React;

var VideoListView = require('./components/VideoListView');

var App = React.createClass({
  render: function() {
    return <VideoListView playlistID="PLF76F25F55798FDBC" />;
  }
});

AppRegistry.registerComponent('App', () => App);

The purpose of the playlistID property that we passed into <VideoListView> will become clear later. Note that if you push your changes now, the app will render as an empty white screen.

Install an XML parser

In the next section, we're going to parse a YouTube playlist that comes in an XML format.

For that we're going to use the xmldom library. If you don't already have npm installed on your machine, click here to learn how to install it.

To install the library, navigate to your app directory and type in:

$ npm install xmldom

If successful, you should see a newly created node_modules directory.

Your app directory works like a typical Node.js project directory; you can install
suitable third-party modules using npm install and the command-line tool will push the node_modules directory and bundle it with your app.
Fetch, parse and display a YouTube playlist

Our app is going to display a particular YouTube playlist and let you tap a thumbnail to play a video. First we're going to need to fetch the playlist and parse it into a more convenient format.

YouTube kindly provides an API endpoint that requires no authentication and returns a playlist feed as XML:

https://www.youtube.com/feeds/videos.xml?playlist_id=PLAYLIST-ID-HERE

For example, here's a playlist feed containing some funny cat videos. Let's add some code that fetches the feed and outputs the result to the console.

Stream the logs

First, make sure that you're streaming the logs for your app, because we're going to output to the console for now. Open up another terminal window, navigate to the app directory and type in:

$ siphon logs

Be sure to leave this terminal window open for the rest of the tutorial.

Fetch the feed

Let's add some code that uses the built-in React Native fetch() function to retrieve the playlist we want to parse. For now we'll just use the cat video playlist.

Modify your components/VideoListView.js file by adding these three methods to the VideoListView class:


parseVideos: function(s) {
  console.log("Got feed with length: " + responseText.length);
},
fetchVideos: function() {
  console.log('Fetching video feed...');
  var url = "https://www.youtube.com/feeds/videos.xml" +
    "?playlist_id=" + this.props.playlistID;
  fetch(url)
    .then((response) => response.text())
    .then((responseText) => {
      this.parseVideos(responseText);
    })
    .catch((error) => {
      console.log('Error fetching the feed: ', error);
    });
},
componentDidMount: function() {
  this.fetchVideos();
},

When the app loads, it's going to grab the remote feed and then log the length of the returned text to the console. Run siphon push and try it.

Parse the feed

Now we're going to use the xmldom library to parse the result. First put the following line at the top of your components/VideoListView.js file, above the class definition:


var DOMParser = require('xmldom').DOMParser;

Then modify the parseVideos() method in your VideoListView class to extract a thumbnail URL and video ID for each feed item:


parseVideos: function(s) {
  console.log('Parsing the feed...');
  var doc = new DOMParser().parseFromString(s, 'text/xml');
  var objs = [];
  var videos = doc.getElementsByTagName('yt:videoId');
  var thumbs = doc.getElementsByTagName('media:thumbnail');
  for (var i=0; i < videos.length; i++) {
    objs.push({
      id: videos[i].textContent,
      thumbnail: thumbs[i].getAttribute('url')
    })
  }
  this.setState({videos: objs});
},

Now run siphon push and you should see a list of thumbnail images in the app. That's the playlist!

Add a navigator component

We're going to need a <Navigator> component so that our users can switch between the playlist view and the video player that we will add later.

Modify your index.js so that it looks like this:


'use strict';

var React = require('react-native');
var {
  AppRegistry,
  Navigator
} = React;

var VideoListView = require('./components/VideoListView');

var App = React.createClass({
  renderScene: function(route, nav) {
    if (route.name == 'list') {
      return (
        <VideoListView
          navigator={nav}
          playlistID="PLF76F25F55798FDBC"
        />
      );
    } else {
      throw 'Unexpected route.';
    }
  },
  render: function() {
    return (
      <Navigator
        style={{flex: 1, backgroundColor: 'black'}}
        initialRoute={{name: 'list'}}
        renderScene={this.renderScene}
      />
    );
  }
});

AppRegistry.registerComponent('App', () => App);

Right now this doesn't do anything. You will still see the same list of thumbnails, but we expand it later.

Add a video player screen

Now let's add a new component for actually playing the videos and call it PlayerView. It's just going wrap a YouTube component and add a button to close the video screen.

Using your text editor, make a new file called components/PlayerView.js and paste in the following code:


var React = require('react-native');
var {
  StyleSheet,
  View,
  Text,
  TouchableOpacity
} = React;

var YouTube = require('react-native-youtube');

var PlayerView = React.createClass({
  render: function() {
    return (
      <View>
        <YouTube
          videoId={this.props.videoID}
          play={true}
          hidden={false}
          playsInline={true}
          onError={(e) => { alert(e.error) }}
          style={{
            alignSelf: 'stretch',
            height: 300,
            backgroundColor: 'black',
            marginVertical: 10
          }}
        />
        <TouchableOpacity
          onPress={() => this.props.navigator.pop()}>
          <Text style={{ color: '#40b2bf' }}>
            Close this video
          </Text>
        </TouchableOpacity>
      </View>
    );
  }
});

module.exports = PlayerView;

You will notice that it's expecting to be passed a videoID and a navigator prop. The button is hooked up to pop the current navigator screen when it is pressed.

Also notice that we have imported the react-native-youtube library. You don't need to install it because all Siphon apps can access it by default.

Add a navigator route for the video player

Now let's modify our <Navigator> configuration to support the new player screen. Open up index.js and modify it as follows:


'use strict';

var React = require('react-native');
var {
  AppRegistry,
  Navigator
} = React;

var VideoListView = require('./components/VideoListView');
var PlayerView = require('./components/PlayerView');

var App = React.createClass({
  renderScene: function(route, nav) {
    if (route.name == 'list') {
      return (
        <VideoListView
          navigator={nav}
          playlistID="PLF76F25F55798FDBC"
        />
      );
    } else {
      return (
        <PlayerView
          navigator={nav}
          videoID={route.videoID}
        />
      );
    }
  },
  render: function() {
    return (
      <Navigator
        style={{flex: 1, backgroundColor: 'black'}}
        initialRoute={{name: 'list'}}
        renderScene={this.renderScene}
      />
    );
  }
});

AppRegistry.registerComponent('App', () => App);

Now when a view tries to push a new navigator screen containing a videoID in the route definition, our app will load the player view and play the video.

Trigger the video player when tapping a video

Final step. Let's make it so that when you tap a video thumbnail it actually plays a video for us.

Open up your components/VideoListView.js file and add this method to the VideoListView class definition:


onPressVideo: function(videoID) {
  console.log('Pressed video: ', videoID);
  this.props.navigator.push({
    name: 'player',
    videoID: videoID
  });
},

Then modify the existing TouchableOpacity declaration so that it looks exactly like this:


<TouchableOpacity onPress={() => this.onPressVideo(video.id)}>

That's it! Now run siphon push and open up the app. You should be able to tap the videos and watch them.

You can find the full source code for the finished app on GitHub here: siphon-youtube-video-browser

Next up

That's the end of the tutorial, thanks for following along. Check out these other guides and resources to learn more:

Build a chat app FAQs Learn how to publish an app

Watch the video
More docs
Fundamentals Quickstart FAQ Native modules Base versions Running on your device How publishing works Assets Ignoring files Over-the-air updates Convert an existing React Native app Sharing Beta testing Collaborating in a team Tutorials Build a real-time chat app Build a YouTube video browser Using Facebook's SDK with Siphon Turn an existing React Native app into a Siphon app Siphon Sandbox iOS (App Store) Android (Google Play)