2
votes

UPDATE: From @Manoj's code below and some other sources, I am now able to load the youtube player into a webview based on the Youtube iframe api. But the question still is: how can I have my app recognize when the video itself starts playing? (after the video loads, and after any ad plays).

The key code is "trapped" in the webview.

There is a nativescript-webview interface plugin that is meant to allow you to get information from the webview. If that is what is required here, what would be the correct code with that plugin to register when the video itself starts playing?

The examples on that plugin's repo seem pretty specific and different than what I have in mind here.


Original Question:

I have a Nativescript app using iOS and Angular. I would like to have youtube videos play in the app, and I want to be able to control the playback. So I want to do things like autoplay it programmatically and register when the video is actually playing.

How can I do this?

More Detail:

There is a nativescript-youtubeplayer plugin but i am not able to use that here, bc it requires an api key and some other reasons.

I am able to embed a basic iframe into a WebView, with code like this:

<WebView (loaded)="onWebViewLoaded($event)" requiresUserActionForMediaPlayback="false" [src]="urlSource"></WebView>

and in ts:

 public urlSource= '<iframe src="https://www.youtube.com/embed/ZwO3PG-c5Cs?playsinline=1&autoplay=1&fs=0&controls=1&enablejsapi=1"></iframe>'

This loads the video. But it does not have the normal youtube controls (like no big pause button on the video)--maybe bc its overridden by the webview. More importantly, it does NOT autoplay, and it does not give me a way to programmatically access the iframe info--so, for example, I am not able to tell when the video is actually playing vs when it is paused.

The Youtube Iframe Player API is made for this purpose, but how do I use it with Nativescript? It seems to require dom manipulation in a way that I have not seen Nativescript do before.

For example, the basic code for that is:

var player;
function onYouTubeIframeAPIReady() {
  player = new YT.Player('player', {
    height: '390',
    width: '640',
    videoId: 'M7lc1UVf-VE',
    events: {
      'onReady': onPlayerReady,
      'onStateChange': onPlayerStateChange
    }
  });
}

But, unsurprisingly, this brings up errors, like 'can't find name YT'.

So, how can I embed a youtube video in Nativescript with iframe and control it like I could if I had a web application?

2
did you figure this out ? - Ricky Levi
See my answer posted below. I was able to get it mostly working with the code there. I say "mostly" because it was awhile ago and I moved on to other projects before putting it into production (as I recall, it was basically functional). There also may be better ways of interacting with the webview than the code I provide--but that should be sufficient to get people started. - 9gt53wS
before I'll make changes according to your code - do you recall if autoplay worked there ? because that's my main issue ... - Ricky Levi
I cannot say for sure as it was awhile ago, but I do recall that autoplay worked by setting the autoplay parameter to true. - 9gt53wS

2 Answers

0
votes

You may use YouTubeIframeAPI within WebView, create a separate local html file that can hold the scripts.

<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
        // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          width: '100%',
          videoId: 'M7lc1UVf-VE',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        if (event.data == YT.PlayerState.PLAYING && !done) {
          setTimeout(stopVideo, 6000);
          done = true;
        }
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
</body>

</html>

Playground Sample

Note: You may even pass the videoId or any other parameter in query string, then parse and use the same within the html file.

0
votes

I haven't looked at this for awhile, but thought it would be helpful to follow up to show what got this mostly working in my case. Hopefully there is some code in here that can help others.

For me, the key insight was putting the basic youtube code (which they give you here) into a variable in the TS component:

So, to start, my TS component put in the Youtube code like this:

exportClass YoutubeComponent implements OnInit {
        public youtubeVideoId = [ID OF VIDEO I WANT TO PLAY]
        public youtubeCode = 
          `
           <!DOCTYPE html>
          <html>
          <body>
             <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
               <iframe id="player"
                width="90%" height="375"
                src="https://www.youtube.com/embed/` + this.youtubeVideoId + `?enablejsapi=1&playsinline=1&autoplay=1&fs=0&controls=1" 
            frameborder="0"
                 ></iframe>
           <script>
           /**
           * WebViewInterface class to handle communication between webView and Android/iOS.
          */
         var NSWebViewinterface = (function () {
               function NSWebViewinterface() {
         
          [PUT IN THE REST OF THE WHOLE YOUTUBE CODE IN THIS VARIABLE]
             ...   
        `

And then in html:

<WebView row="0" src="{{youtubeCode}}" #webView></WebView> 

And then to interact with the webview, in the same TS component as above:

 @ViewChild('webView') webView: ElementRef;

  onWebViewLoaded(args) {
     let webView: WebView = this.webView.nativeElement;
     this.oWebViewInterface = new WebViewInterface(webView); 
     this.nextFunction()
   }

  nextFunction {
     this.oWebViewInterface.on('onPlayerStateChange, (data) =>{
       if (data.state === 5){ //video cued
         console.log('video is cued up')
       }
    })
  }