I have found a bug using the external controls for the html5 widget on iOS, i have tested with iphone and ipad. The controls inside the widget work ok. However on my clients site http://www.bushytunes.net and the widget api playground http://w.soundcloud.com/player/api_playground.html the external controls run an error.
Here is what the console from the widget playground prints:
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PAUSE {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.PLAY {"loadedProgress":null,"currentPosition":0,"relativePosition":0}
SC.Widget.Events.READY {}
Loading...
Thanks, James
TL;DR: iOS 6 should work with a limitation of a call to play to be init by user action, iOS5 and below probably won't get a fix.
We'll try to resolve this with some kind of a hack, but most probably this won't get a proper solution any time soon.
SoundCloud Widget is using HTML5 Audio to play sounds on iOS. There are two limitations on starting playback in iOS:
Playback must be started by user action (so within event handler)
The call to audio.play method has to be within synchronous call stack of that event handler.
This means, that this works:
document.querySelector('.play-button').addEventListener('click', function () {
audioController.play();
}, false);
But this doesn't:
document.querySelector('.play-button').addEventListener('click', function () {
setTimeout(function () {
audioController.play();
}, 500);
}, false);
Cross-domain communication between iframes is only possible in asynchronous manner. Our implementation is using postMessage DOM API, but even older techniques such as Fragment Identifier Messaging (FIM) that is using location.hash are asynchronous. This means we don't currently see a way of enabling playback through API for iOS5 and below (as there is also no Flash fallback).
However, there are also good news: iOS6 has dropped the limitation No2. This means that as long as the API call to play is called by user action, you'll be able to play sounds. Even though the communication between your parent window and widgets' iframe is still async. Unfortunately iOS hasn't dropped this limitation.
I hope this helps and I'll update this answer in case we find a proper workaround.
My suggestion would be to build your own custom player with a library like Audio5JS or SoundManager2 in case controlling playback on iOS is crucial for your app.
You can see vague description of what I am talking about on developer.apple.com resource.
I can't completely tell if #gryzzly is trying to say this, but the Widget API's external controls are completely broken on mobile. The answer does explain why -- you can't synchronously tell the iFrame to play the sound, but it is my understanding that proper iframe.contentWindow calls would be synchronous? I may be wrong.
Try directing your mobile phone to the widget API playground: https://w.soundcloud.com/player/api_playground.html
Even there it doesn't actually play unless you press the orange button.
Pretty irritating since there's no application to get around the streaming API limit either. There seems to be literally no way to get a site that may experience more than 15,000 requests/plays per day to work with SoundCloud on mobile. I just want continuous music playback.
Related
I'm writing a web app for Tizen Smart TV. One of the required features is implementing the Smarthub Public Preview deeplinking.
I have setup the app to open at a specific content when the Public preview tile is clicked. However, I cannot prevent the app to reload. The documentation mentions adding the appcontrol event to the window event listeners, but I don't think this event is being recognized by the app, since the code is not executed.
It only works if I directly add my deeplink() method to the onload property.
According to documentation, this piece of code should prevent the app to reload, but it is not working:
<tizen:app-control>
<tizen:src name='index.html' reload='disable'></tizen:src>
<tizen:operation name='http://samsung.com/appcontrol/operation/eden_resume'></tizen:operation>
</tizen:app-control>
window eventListener is not working wither:
onload="window.addEventListener('appcontrol', deepLink)"
Any help on how to implement this correctly?
Thank you in advance
You are probably modyfing window.location in the app (ie in router).
reload='disable' prevents reloading index.html. When application receives app control request and page is different, application will be reloaded.
You can find more about appcontrol in Tizen documentation (note that Tizen for TV may differ from other devices):
https://docs.tizen.org/application/web/guides/app-management/app-controls/
I've got some information regarding your question.
To do application resume without Page reload,
Set extra data in app-control like below
key: SkipReload
value: Yes
We use the YouTube embedded player on a hybrid app based on Cordova. The app has a lot of traffic worldwide.
The player displays the message "Please click here to watch this video on YouTube" to some users when they try to play any video under unclearly circumstances.
We do not see a clear pattern, it doesn't seem to depend on the user's country nor the restrictions of the video.
We have seen in the player code (https://www.youtube.com/yts/jsbin/player_ias-vflrnurMS/en_US/base.js) that the message is assigned to a constant called "TOO_MANY_REQUESTS_WITH_LINK" but there is no high volume of requests per user and the quota cannot be configured as in other Google APIs.
We follow the iFrame API reference:
https://developers.google.com/youtube/iframe_api_reference?hl=en
<iframe id="player" src="https://www.youtube.com/embed/M7lc1UVf-VE?autoplay=1&cc_load_policy=0&controls=0&disablekb=1&enablejsapi=1&fs=0&iv_load_policy=3&loop=0&modestbranding=1&playsinline=1&rel=0&showinfo=0&wmode=transparent&origin=XXX" frameborder="0"></iframe>
<script type="text/javascript">
var player,
scriptTag = document.createElement('script'),
firstScriptTag = document.getElementsByTagName('script')[0];
scriptTag.src = "https://www.youtube.com/iframe_api";
firstScriptTag.parentNode.insertBefore(scriptTag, firstScriptTag);
function onYouTubeIframeAPIReady() {
var options = JSON.parse('{"autoplay":1,"cc_load_policy":0,"controls":0,"disablekb":1,"enablejsapi":1,"fs":0,"iv_load_policy":3,"loop":0,"modestbranding":1,"playsinline":1,"rel":0,"showinfo":0,"wmode":"transparent","origin":"XXX"}');
if (!options.origin) {
options.origin = location.origin ||
location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
}
player = new YTRemoteVPlayer('player', '<%-videoId%>', options);
}
</script>
Does anyone know what may be happening and how to fix it?
Me and my teammates managed to reproduce that behaviour locally.
To reproduce that behaviour, all you need to do is, under the same IP Address, to load the youtube JS multiple times and for different videos. Although I cannot clarify the exact amount of times it must be done (we left some devices aside doing it), the behavior certainly happened.
As an attempt of a workaround for that problem, we accessed the https://web.archive.org/web website and fetched an old YouTube JS script (https://www.youtube.com/iframe_api). We tried to use that old script, but with no success. The message continued to appear =/.
I really do not know if there is much we, developers, can do about it, but wait for an YouTube statement and/or revision of recent changes on their end.
Update
There is an issue opened on Google's issue tracker website:
https://issuetracker.google.com/issues/143091693
Update
It looks like that YouTube have resolved that problem on their end. We'll keep monitoring :)
Update (November 5th 2019)
The problem is happening again.
Update (November 7th 2019)
I have opened a new issue on issuetracker:
- https://issuetracker.google.com/issues/144057800
I don't have a fix for it, but I can add more information about the problem, this way maybe someone can help us with this issue.
I am getting the same error with some users, and like you said there is no a clear pattern. My devices are working properly, but I did some tests with the help of a user of my app that is getting this error. Following the results:
Demo used in my tests: https://developers.google.com/youtube/youtube_player_demo
Test 1 - Open the iframe player api demo on device's browser - WORKED
Test 2 - Open the iframe player api demo into a webview on my app - FAIL
Test 3 - Open the iframe player api demo into a webview on my app using a VPN connection - WORKED
So, it appears to be a combination of APP + IP is blocked. I don't know the reason, and it will be very helpful if someone repeat these tests. I am trying to confirm it with another user, but it's a little hard to find someone willing to help.
UPDATE: a second user tried to use a VPN and it worked to him too.
UPDATE 2: a user with this problem told me that the videos are working properly again now. It appears to be a temporary block by Youtube on server side.
We are using Google Analytics to track events, but events don't appear to track 100% of the time. Sometimes they track, and sometimes they don't. We're not exceeding quota limits per session (at most we have 20 events per session). That shouldn't be the issue.
The tracking fails to work consistently on our normal website as well as our HTML5 mobile app version, though it's far less reliable with the HTML5 mobile app version.
Code:
var share_url = 'http://twitter.com/intent/tweet?text=';
// Log in GA
_gaq.push( ['_trackEvent', 'Share Twitter', ''] );
// Open URL in browser
open_external( share_url + encodeURIComponent( msg ) );
function open_external( url ) {
window.open( url + '#phonegap=external' );
}
_gaq.push( ['_trackEvent', 'Share Twitter', ''] );
This won't do anything.
For _trackEvent, the third argument (where you pass an empty string) is required. It's the 'Action' parameter. But an empty string is falsey, so it just fails silently.
Pass any value there, and it'll work.
Is this a reduced case? You shouldn't be seeing any events with that code.
Are you positive that you waited long enough for the data to be processed by Google? Especially since some tracking seems to be working.
I had the same behaviour (in a mobile app btw) but after waiting for more than a day it still came through. This still occurs on a daily basis... Hope this is the case for you too.
I'm not exactly sure what your problem can be, so I will throw some idea.
Most of them are obvious but it might help.
On your website:
Are you sure your embed the Google Analytics code snippet on every page who required tracking?
Load Google analytics from the asynchronous way.
On Google analytics check on Real time > Overview. As full report are delayed from few hours.
If you url is something like httq://localhost/ then your need to add the javascript code _gaq.push(['_setDomainName', 'none']); please read this post
It can't work with file:// url
(Probably not) Check if you can download the JavaScript from Google Analytics. Maybe your proxy block Google analytics tracking ?
In your application:
You are using embedded HTML 5 page within your app. So the way your open a page is using file://PATH_TO_MY_DIR/index.html as it's on your hard drive you can't send data to Google analytics.
As you are probably using PhoneGap, you need to "jump out" of your HTML page into native Objective-c code and send the event from your Objective-C code. Read Google Analytics and PhoneGap and this google group thread
Hope it help.
The problem is third parameter in:
_gaq.push( ['_trackEvent', 'Share Twitter', ''] );
The 2nd element of the array should be the category and the 3rd should be the action. For example:
_gaq.push( ['_trackEvent', 'Share', 'Twitter'] );
You can verify this yourself by pasting each of the above into your developer console (F12 in Chrome, Ctrl-Shift-K in Firefox) and watching the network traffic.
Reference:
https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiEventTracking
I'm just doing some initial research into creating iAds with iAd Producer, but we'd like to link the ad to an external website, rather than an iTunes listing.
Is this possible, if so, how would you go about it? Ideally clicking on the ad would open the link in Safari, but if there is a UIWebView equivalent that would be fine too (The WebGL view control confusingly seems to be for displaying 3d objects).
Many thanks in advance.
Ted
I'm not familiar with iAds, what does it look like when specified in HTML?
According to this http://developer.apple.com/library/ios/#featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html
it looks like it won't be recognized.
(This is s useful reference in this area: http://wiki.akosma.com/IPhone_URL_Schemes)
But if you load the page in a UIWebView you can intercept the iAds link within shouldStartLoadWithRequest: and launch Safari yourself from there.
Ah, I've realised now I was overcomplicating things somewhat / missed the easy answer.
The iAds produced by iAd Producer are all HTML, with Javascript added to handle page / control events. This should have given me the clue that they themselves are executing in some sort of UIWebView control.
Hence, when I added the following Javascript, on a button click event, the user is warned they are leaving the app (well they were when leaving the iAd Tester app) and then thrown out into Safari to view the website, as I wanted all along. Simple. I guess it's not really what Apple want people to do with iAds (it's not driving them to the appstore), hence it's not that well documented.
this.onViewTouchUpInside = function (event) {
document.location = "http://www.google.co.uk";
};
Does anyone know if the YouTube scubscribe button (the one that appears in widgets on various websites) has a callback function once the user has clicked subscribe? I have looked into making my own but due to the fact they load in iframes I dont think its possibe.
It currently (2013-01-08) does not: https://developers.google.com/youtube/iframe_api_reference
Yes they recently added a callback function. In their GUI for creating a subscribe button, you can check "My application listens for button events." and it'll include the callback in the widget code: https://developers.google.com/youtube/youtube_subscribe_button