Set listener on WebView | nativescript + vue - android

I am trying to play a video from YouTube and get the current-time by YT.API.
The video plays successfully and functions on HTML content works too,
But I can't figure it out how can I get data from this webView Element.
I want to be informed about events from webView,
this is my code:
<template>
<Page #loaded=pageLoaded>
<GridLayout>
<web-view id="webView"></web-view>
</GridLayout>
</Page>
</template>
let webViewInterfaceModule = require('nativescript-webview-interface');
#Component
export default class someComponent extends Vue {
oWebViewInterface;
pageLoaded(args){
let page = args.object;
this.setupWebViewInterface(page);
}
setupWebViewInterface(page){
let webView = page.getViewById('webView');
this.oWebViewInterface = new webViewInterfaceModule.WebViewInterface(webView, this.html);
this.oWebViewInterface.on( '*', function(eventData){
console.log("some change!!"); // but never fires!
});
}
}
and i define this.html as:
html = `
<!DOCTYPE html>
<html>
<body>
<div id="player"></div>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '280',
width: '100%',
videoId: 'k3On6DLPGLA',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
event.target.playVideo();
}
var done = false;
function onPlayerStateChange(event) {
console.log("state changed!"); // it fires!
}
function stopVideo() {
player.stopVideo();
}
<\/script>
<\/body>
<\/html>
`;
but i just get such these results:
chromium: [ERROR:web_contents_delegate.cc(224)] WebContentsDelegate::CheckMediaAccessPermission: Not supported.
chromium: [INFO:CONSOLE(35)] "state changed!", source: ..../ (35)

Ok I got the answer:
there is some issues here:
#1. implanting nativescript-webview-interface.js:
I need to copy this file:
cp node_modules/nativescript-webview-interface/www/nativescript-webview-interface.js app/assets/www/lib/
#2. permissions!
but #1 causes another problem: net::ERR_ACCESS_DENIED
for solving this one I add this:
setupWebViewInterface(page){
let webView = page.getViewById('webView');
webView.android.getSettings().setAllowFileAccess(true);
}
and now I have access to the folder so I moved this.html variable content to a new file : /assets/www/index.html
#3. setting src
since just now we have access to the folder, we need to (re)set the src of web-view so I add this one to the setupWebViewInterface Function:
this.oWebViewInterface = new webViewInterfaceModule.WebViewInterface( webView, '~/assets/www/index.html' );
note: I removed src from <webView /> since it causes problem! (if old and new src would be the same it will not reload!)
#4.defining Variables:
in html file I need to add this line:
var oWebViewInterface = window.nsWebViewInterface;
#5. defining listener:
I add this one: oWebViewInterface.emit('anyEvent', event);
inside this function:
function onPlayerStateChange(event) {
console.log("state changed!");
oWebViewInterface.emit('anyEvent', event);
}
Now it works :)

Related

issue with webview and Ti.App.addEventListener causing crash

Please excuse the ugly code this is here just as the simplest possible version of my actual code that I can use to reproduce my error. I am basically using a WebView in titanium to open a locally held .htm file so that I can leverage HTML5 graphics capabillities. What I am doing works fine. The problem is that I need to pass some data to the htm file which I am doing exactly as the docs recommend - using Ti.App.fireEvent - and this works ... once. But if I navigate away from the window and then navigate back again it fails and gives me a NS_ERROR_NOT_AVAILABLE. I have tried this code in firefox as a web preview and on Android device and emulator with the same issue in each. Clearly there is some issue with it not loading the same way if the view is called back, I am guessing it is pulled back off the stack which is messing with the 'load' event listener or something, but I have no idea how to fix it. Here is a simplified version of my code, just to demonstrate the issue:
app.js
Titanium.UI.setBackgroundColor('#000');
var win = Ti.UI.createWindow({
layout: 'vertical',
});
var wv = Ti.UI.createWebView({
url: 'test.htm',
height: '50%'
});
var but = Ti.UI.createButton({
width: 100,
height: 50,
title: 'Press',
});
var wvopen = false;
but.addEventListener('click', function() {
if (wvopen === false) {
win.add(wv);
wvopen = true;
} else {
win.remove(wv);
wvopen = false;
}
});
wv.addEventListener('load', function() {
Ti.App.fireEvent('go');
});
win.add(but);
win.open();
And the .htm file:
test.htm
<!doctype html>
<html>
<head>
<title>Test</title>
</head>
<body>
<p>A Little Test</p>
<script>
var Ti = window.parent.Ti;
Ti.App.addEventListener('go', function(){
alert(1);
});
</script>
</body>
</html>
Try this,
but.addEventListener('click', function() {
if (wvopen === false) {
win.add(wv);
wvopen = true;
} else {
win.remove(wv);
wv.release();
wvopen = false;
}
});
I found the answer myself eventually. It is in the docs but realising what the problem actually is and why it is happening is not always simple so I feel it is worth me answering here myself for others use.
The key point is this:
"Keep in mind that app-level events are global, which means they remain in context the entire time your app is running (unless you remove them). This also means that any objects they reference will also remain in scope while your app runs. This could prevent those objects from being garbage collected. See the Managing Memory and Finding Leaks chapter for more information."
~ Titanium docs.
link: https://wiki.appcelerator.org/display/guides2/Event+Handling#EventHandling-Application-LevelEvents
So basically the event listener will exist even if it is not loaded and you try to delete the context in which it exists. So you must delete both the event listener and nullify the view that holds it.
In practice the implementation may vary a little depending on your specifics, but this is what I came up with.
NB ... there may be more efficient methods to do this in which case please let me know.
app.js
/*
* Build window and buttons
*/
var win = Ti.UI.createWindow({
layout: 'vertical',
backgroundColor:'black'
});
var but = Ti.UI.createButton({
top: 20,
width: 200,
height: 50,
title: 'Toggle WV',
});
var but2 = Ti.UI.createButton({
top: 20,
width: 200,
height: 50,
title: 'Fire Event'
});
var wv;
function newWv(){
wv = Ti.UI.createWebView({
top:20,
right: 20,
left: 20,
height: '50%',
url: 'test.htm',
});
}
win.add(but);
win.add(but2);
/*
* Main functionality goes here of tests goes here.
*/
var isVisible = false;
but.addEventListener('click', function() {
if (isVisible) {
win.remove(wv);
Ti.App.fireEvent('close');
wv = null;
isVisible = false;
} else {
newWv();
win.add(wv);
isVisible = true;
}
});
but2.addEventListener('click', function() {
try{
Ti.App.fireEvent('go');
} catch(e) {
alert(e);
}
});
win.open({modal:true});
And then a few changes in the htm file:
test.htm
<!doctype html>
<html>
<head>
<title>Test</title>
</head>
<body>
<p>A Little Test</p>
<script>
var Ti = window.parent.Ti;
var go = function() {
alert('called by Titanium app');
};
var close = function() {
Ti.App.removeEventListener('go',go);
Ti.App.removeEventListener('close',close);
};
window.addEventListener('load', function() {
Ti.App.addEventListener('go', go);
Ti.App.addEventListener('close', close);
});
</script>
</body>
</html>

Cordova/Phonegap YouTube iframe_api error: XMLHttpRequest cannot load chrome-extension Cross origin requests are only supported for HTTP

I am trying to use the a YouTube iframe API with my cordova-android project. When I run the code in a browser on my computer it runs perfectly, but when i build my app and run it on my phone the page containing the iframe will not load, and i get the following error in my console:
XMLHttpRequest cannot load chrome-extension://boadgeojelhgndaghljhdicfkmllpafd/cast_sender.js. Cross origin requests are only supported for HTTP
Here is my code:
<div class='ui-body ui-body-a'>
<!-- 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) {
console.log('Loaded Video)
}
// 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>
</div>
Thanks in advance!
I got it to work by using glitchbone's cordova plugin YoutubeVideoPlayer.

Playing Youtube html5 videos on Android Phones using iframe API

I am using the following code to play HTML5 videos
<!DOCTYPE html>
<html>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script type="text/javascript" id="youtubeplayer">
</script>
<script>
document.getElementById('youtubeplayer').style.width=window.innerWidth;
document.getElementById('youtubeplayer').style.height=window.innerHeight;
// 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', {
//videoId: localStorage.getItem('videoid'),
videoId : "8UVNT4wvIGY",
width : Math.abs(window.innerWidth*0.99),
height : Math.abs(window.innerHeight*0.99),
allowFullScreen : true,
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>
Basically I am embedding it in a HTML5 page.
It works very well on Desktop, but on a Android device (Google Nexus 10), it just shows the title of the video and the video doesn't load.
Fitvids plugin worked super well for me and played nicely within the bootstrap framework I was using.
From their github page:
<script src="path/to/jquery.min.js"></script>
<script src="path/to/jquery.fitvids.js"></script>
<script>
$(document).ready(function(){
// Target your .container, .wrapper, .post, etc.
$("#thing-with-videos").fitVids();
});
</script>
Boom done!

Streaming of ShoutCast .MP3 File in jPlayer on Android/iPhone

I have a very specific problem with jPlayer. I need to run it in Android/iPhone, which is no problem thanks to "jPlayer Android Fix" on the documentation. However, I also need it to stream a ShoutCast .MP3 file, not a ShoutCast stream. All the documentation I read points to a generic URL/IP/Port, but not a file.
I have got it all working with a static MP3 using the following code:
<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
var id = "#jquery_jplayer_1";
var bubble = {
mp3:"http://www.jplayer.org/audio/mp3/Miaow-07-Bubble.mp3"
};
var options = {
swfPath: "/jplayer2-4-0",
supplied: "mp3",
wmode: "window",
smoothPlayBar: true,
keyEnabled: true
};
var myAndroidFix = new jPlayerAndroidFix(id, bubble, options);
$('#setMedia-Bubble').click(function() {
myAndroidFix.setMedia(bubble);
$('.jp-title ul li').text('Bubble');
});
$('#setMedia-Bubble-play').click(function() {
myAndroidFix.setMedia(bubble).play();
$('.jp-title ul li').text('Bubble');
});
$("#jplayer_inspector").jPlayerInspector({jPlayer:$("#jquery_jplayer_1")});
});
//]]>
</script>
... but the moment I change
mp3:"http://www.jplayer.org/audio/mp3/Miaow-07-Bubble.mp3"
to
mp3:"http://live.station.ca:8000/stream.mp3"
... I get nothing. I've even tried
mp3:"http://live.station.ca:8000/stream.mp3;stream/1"
Can anybody help? Thanks in advance!

Playing Videos from Chrome Filesystem Not Working on Android

I am trying to create an offline video player that would download video content from my site for later viewing offline via an HTML5 video element. The code below works fine in Chrome for the desktop, but not on mobile (Nexus S smartphone, Nexus 7 tablet, 4.1 since only that runs chrome, which is required for the filesystem api). I am using the filesystem API that is supported by chrome on both the desktop and mobile.
I have confirmed it is correctly storing the file on the mobile device and I can retrieve the file correctly, but for some reason after retrieving the video from the localsystem chrome does not want to play the video. This is true whether I am using the html5 video element or whether I am navigating directly to the filesystem URL. When I use the html5 video element it returns the error media_err_not_supported. I have confirmed that the device can play the video if I navigate directly to it on my server (without first storing it using the filesystem api), so the issue is not a codec or video format problem. I am also using the video/mp4 mime type in both cases.
Again, this works on desktop, but not mobile. Any ideas?
Here is the code we are using:
<!DOCTYPE html >
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"> </script>
<script type="text/javascript">
var _fs;
var filename = "test3.mp4";
var diskSpaceRequired = 10 * 1024 * 1024;
$(document).ready(function () {
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
function onInitFs(fs) {
_fs = fs;
getVideo(fs);
}
if (!!window.requestFileSystem) {
window.webkitStorageInfo.requestQuota(
window.webkitStorageInfo.PERSISTENT,
diskSpaceRequired, // amount of bytes you need
function () { },
function () {}
);
window.requestFileSystem(window.PERSISTENT, diskSpaceRequired, onInitFs, function () { alert('error'); });
} else {
alert('not supported');
}
$("#play").on('click', playVideo);
$("#ourVideo").on('error', function(e) { console.log('ERROR!!!', e, arguments);
console.log($("#ourVideo")[0].error);
});
});
function playVideo() {
_fs.root.getFile(filename, {}, function (fileEntry) {
$("#ourVideo").attr('src', fileEntry.toURL());
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function (e) {
$("#ourVideo").get(0).play();
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
function getVideo(fs) {
fs.root.getFile(filename, { create: true }, function (fileEntry) {
fileEntry.createWriter(function (fileWriter) {
fetchResource(fileWriter);
}, errorHandler);
}, errorHandler);
}
function errorHandler(e) {
console.log('error', e);
}
function fetchResource(fileWriter) {
console.log('fetchresource');
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("GET", "http://mydomain.com/trailer.mp4", true);
xhr.onload = function(e) {
if (this.status == 200) {
var bb = new WebKitBlobBuilder();
bb.append(this.response);
var blob = bb.getBlob("video\/mp4");
fileWriter.write(blob);
} else {
console.log(this.status);
}
};
xhr.send();
}
</script>
<title>foo</title>
</head>
<body>
<input type="button" value="Play Video" id="play"/>
<video id="ourVideo" controls="">
<source id="vidSource" type="video/mp4"/>
</video>
</body>
</html>
The problem looks like your android chrome coudn't access the android file system correctly, For that you can use nanoHttpd server for access android local files in device or sdcard.
for NanoHttpd server use this one class in your application and pass the media file location as http://localhost:8081/sdcard/(your_media_location).mp4
or get nanoHttpd from https://gist.github.com/1893396
I think this is more accurate to access sdcard files than directly calling for them
try change html part to
</head>
<body>
<input type="button" value="Play Video" id="play"/>
<video id="ourVideo" controls="">
<source src="video1.mp4" type= "video/mp4">
<source src="video1.ogv" type= "video/ogg">
</video>
</body>
you can convert your mp4 to ogv using
http://video.online-convert.com/convert-to-ogg
and put ogv file in the same location in mp4
**for more information check out these
http://www.broken-links.com/2010/07/08/making-html5-video-work-on-android-phones/
HTML5 <video> element on Android does not play

Categories

Resources