I am using Xamarin to develop a cross-platform mobile app for both Android and iPhone. In my app I have to programmatically play a YouTube video. For the Android part I used a bind version of the official YouTube library and I have finished it without problem.
For the iPhone part I am unable to find a working library that could let me programmatically play the YouTube video.
I have tried the YouTube iframe API sample code from the following link: https://developers.google.com/youtube/iframe_api_reference#Getting_Started
The code I used is like this:
<!DOCTYPE html>
<html>
<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', {
height: '390',
width: '640',
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>
In the browser from my desktop, it auto-start the video after it is loaded using the startVideo() method. It works perfectly fine on desktop browser until I bring it to the iOS web view. It can load the video but it does not auto-start, which is one of our customer's requirement.
I understand that there are iOS library which could do the auto-play feature, but as I lack the knowledge on iOS native development, I am unable to do the iOS binding process.
I have tried other solutions like the followings:
https://github.com/afalz/YTHelper
https://github.com/nodoid/YoutubeBindings/tree/master/GoogleYoutube
But none of the above could work.
Any suggestion on how to do the auto-play feature in Xamarin?
Related
I have a basic webpage that I am attempting to load into a WebView on a XAML page. The relevant code is such:
<WebView x:Name="WebViewQuestionText" Source="editor.html" HeightRequest="500" WidthRequest="500" />
As per the official Microsoft .NET MAUI documentation, I have editor.html located in /Resources/Raw/editor.html and set to a Build Action of MauiAsset.
During runtime I don't generate any errors but the WebView is blank. An inspection of the WebView reveals a webpage that is barebones with nothing in it, I assume is the default for a WebView control. If I throw an actual URL in, the page loads up and works as expected, displaying the contents of the given website.
I believe it's simply not finding my page to display it. I'm building for Windows currently but this application will be eventually deployed to both Windows and Mac. How can I ensure it finds it correctly?
As pointed out below - I have also tried it this way, with the same result - when I click the link, I get a blank page.
<WebView x:Name="WebViewQuestionText" HeightRequest="500" WidthRequest="500">
<WebView.Source>
<HtmlWebViewSource>
<HtmlWebViewSource.Html>
<![CDATA[
<html>
<head>
</head>
<body>
<h1>.NET MAUI</h1>
<p>The CSS and image are loaded from local files!</p>
<p>next page</p>
</body>
</html>
]]>
</HtmlWebViewSource.Html>
</HtmlWebViewSource>
</WebView.Source>
</WebView>
My editor.html page is as follows:
<!DOCTYPE html>
<HTML>
<BODY>
<H1>This is a test</H1>
<P>This is only a test</P>
</BODY>
</HTML>
I've fixed this with this PR into .Net Maui. Will be in the SR2 release due in the next few weeks.
The docs suggested it worked consistently on all platforms, but it simply had never been implemented on Windows... slightly concerning.
The workaround I've posted on the PR (mentioned also by Reinaldo below) will get around this for the mean time, however you should probably remove it once SR2 is released and you update to it.
This ends up being a currently open bug against .NET MAUI on the Windows platform.
https://github.com/dotnet/maui/issues/5523
There appears to be a workaround here but it is not ideal. The issue appears to be one of resolving the correct path on Windows for the local file, so the workaround solution is to load the file directly via StreamReader
As mentioned before it is an open bug at the moment. However there is a workaround besides using a StreamReader.
#if WINDOWS
private static readonly System.Lazy<bool> _isPackagedAppLazy = new System.Lazy<bool>(() =>
{
try
{
if (Windows.ApplicationModel.Package.Current != null)
return true;
}
catch
{
// no-op
}
return false;
});
private static bool IsPackagedApp => _isPackagedAppLazy.Value;
// Allow for packaged/unpackaged app support
string ApplicationPath => IsPackagedApp
? Windows.ApplicationModel.Package.Current.InstalledLocation.Path
: System.AppContext.BaseDirectory;
#endif
private async void WebView_HandlerChanged(object sender, EventArgs e)
{
#if WINDOWS
await ((sender as WebView).Handler.PlatformView as Microsoft.Maui.Platform.MauiWebView).EnsureCoreWebView2Async();
((sender as WebView).Handler.PlatformView as Microsoft.Maui.Platform.MauiWebView).CoreWebView2.SetVirtualHostNameToFolderMapping(
"localhost",
ApplicationPath,
Microsoft.Web.WebView2.Core.CoreWebView2HostResourceAccessKind.Allow);
var wv = (sender as WebView).Handler.PlatformView as Microsoft.Maui.Platform.MauiWebView;
wv.LoadUrl($"https://localhost/{wv.Source.AbsolutePath}");
#endif
}
The WebView would look something like this:
<WebView x:Name="dashBoardWebView" BackgroundColor="Transparent"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
IsVisible="True"
HandlerChanged="WebView_HandlerChanged"
Source="test.html"></WebView>
Hope it helps.
Note: Taken from https://github.com/dotnet/maui/pull/7672
I have an Adobe AIR application that plays YouTube videos using the YouTube iframe API, implemented using StageWebView. It has worked well for a few years now, and today I found it does not play YouTube videos.
If I create StageWebView() with no parameters (which I have always done and has worked without issues until today), AIR uses WebKit. The YouTube iframe API loads, but the video does not play. If I right-click the window and click on "Stats for nerds", then highlight the text and press Control+A to select it all, I get the below after copying and pasting it into a text editor:
"Your browser does not currently recognize any of the video formats
available."
When I saw it wasn't working, I used StageWebView(true) instead, which uses the machine's system default web engine. This doesn't successfully load the YouTube iframe API, so no video window appears at all.
Here is the code used in Adobe AIR (Animate CC 2017 / AIR v.26) for basic verification:
var webView:StageWebView = new StageWebView();
webView.stage = this.stage;
webView.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
webView.loadURL("http://batsonengineering.com/testyt.html");
The code inside “testyt.html” is the example on the YouTube iframe API web page (https://developers.google.com/youtube/iframe_api_reference), except I added some alert statements to see what is happening. If you run this, you will see the alert("4") never appears if I use the WebKit, and alert("3") never appears if I use the default web engine. Below is the code in testyt.html:
<!DOCTYPE html>
<html>
<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.
alert("1");
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
alert("2");
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
alert("3");
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
alert("4");
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) {
alert("5");
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
</body>
</html>
If I change the line:
webView.loadURL("http://batsonengineering.com/testyt.html");
to:
webView.loadURL("https://youtu.be/M7lc1UVf-VE");
which takes me to the YouTube page this video plays on, the YouTube page will load, but the video will not play if I use the system web engine. If I use WebKit, the video will play. However, I need to be able to use the iframe API commands to the control the video, and don't want the entire YouTube page showing to my users. I need it to be embedded.
After I this I decided to see if I could get YouTube playing videos in the C# WebBrowser component. This also would not work. However, if I run http://batsonengineering.com/testyt.html directly in a browser, the video plays. So, it appears that YouTube has changed something on their side to prevent videos from playing when embedded inside a container like StageWebView or WebBrowser.
So my questions are:
1) What has made the WebKit suddenly unable to play YouTube videos in StageWebView?
2) What has made my system's web engine suddenly unable to load the YouTube API when in StageWebView?
3) Is there anything I can do to fix this?
Consider :
Try loading when HTML file is on an https server?
It's possible Youtube only accepts outside requests from secure (https) domains.
You cannot mix http content with https based content.
That means if your domain is http://batsonengineering.com (using HTTP) it cannot have html code like tag.src = "https://www.youtube.com/iframe_api"; (using HTTPS).
Try using tag.src = "http://www.youtube.co... etc
I have different YouTube video id's to play in iframe, at present only one video playing at a time, for handling next video i tried onPlayerStateChange() event, but event not fires when video is ended, is there any way to fire an event when video is ended or play multiple video one after another. any one please help me.
i have tried this below code.
html code:
<script type="text/javascript">
function ifplayer_onPlayerStateChange() {
alert("statechanged");
}
</script>
<iframe id="ifplayer" runat="server"/>
cs code:
ifplayer.Attributes.Add("src", "//www.youtube.com/embed/videoid");
ifplayer.Attributes.Add("onload", "ifplayer_onPlayerStateChange();");
I tired this below code to play another video after first video ended, it's working for me.
<iframe class="ytplayer" src="https://www.youtube.com/watch?v=pwfnT4CKoJo?enablejsapi=1" id="player" height="500" width="600" runat="server"></iframe>
<script>
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player( 'player', {
events: { 'onStateChange': onPlayerStateChange },
});
}
function onPlayerStateChange(event) {
switch(event.data) {
case 0:
document.getElementById('player').src = "https://www.youtube.com/watch?v=bhGQSsuTjmw?enablejsapi=1";
onYouTubeIframeAPIReady();
break;
case 1:
alert('video playing from ' + player.getCurrentTime());
break;
case 2:
alert('video paused at ' + player.getCurrentTime
break;
}
}
</script>
I would recommend taking a look at the YouTube API First and see if that can take away some of the work you need to do as google might have already created a solution to that.
You can find it here: https://developers.google.com/youtube/code_samples
I'm using the plug in called GalleryView (http://spaceforaname.com/galleryview/) and I want to find a way to make a function to pause the gallery when I want.
I use some Ajax requests to call images from a calendar in determinates days, if a play the gallery in the day 1 and click in the day 2, the gallery don't stop.
In the js file of the plug have the code bellow that I think stops the gallery, but I don't know how do access it from my content page:
stopSlideshow: function(changeIcon) {
var self = this,
dom = this.dom;
if(changeIcon) {
dom.gv_navPlay.removeClass('gv_navPause').addClass('gv_navPlay');
}
this.playing = false;
dom.gv_galleryWrap.stopTime('slideshow_'+this.id);
},
Thanks.
I'm creating an application which plays youtube videos in C# (winform). Now i'd like to fire an event, or something like that, when the video has ended.
I'm using the webbrowser control and call a youtube video like this:
wbYoutube.Navigate("http://www.youtube.com/v/" + playString[1] + "?version=3&enablejsapi=1&autoplay=1");
playString[1] is the youtube video id (like rGJN5K2cV_8).
I've been trying to get this working a few days now, has anyone got an idea on how to achieve this? If it's even possible...
If you need more info, let me know.
Thanks
I think this is possible but you have to write the html code into the browser element by yourself
wbYoutube.DocumentText = "";
Here is the html (You have to escape it)
<html><head></head><body>
<script type='text/javascript' src='http://www.youtube.com/player_api'></script>
<iframe id="player" width="100%" height="100%" src="http://www.youtube.com/embed/VIDEO_ID?autoplay=1&controls=0&enablejsapi=1" frameborder="0" allowfullscreen></iframe>
<script type="text/javascript">
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
videoId: 'VIDEO_ID',
events: {
'onStateChange': function(evt){
if(evt.data == 0){
window.external.Test('Video finished!!');
}
}
}
});
}
</script>
</body></html>
And have a look at Implement Two-Way Communication Between DHTML Code and Client Application Code
There you find the rest of the code.