Reputation: 13329
I understand that html5 video on Android cannot autoplay. As it stands my video works on the device only when the user clicks on the play button.
<video width="640px" height="360px" src="media/video/Moments_of_Everyday_Life.mp4" controls id="video"></video>
<script type="text/javascript">
$(function(){
var video = document.getElementById('video');
video.play();
});
</script>
It works on my desktop though.
Why would this not work? And what is the difference between clicking play and using .play()
?
Upvotes: 12
Views: 32594
Reputation: 69581
I took some of the advice here, most notably from @JenniferG, however I still had to tweak to get a nice experience... Here are the main points
audio
tags as @JenniferG has mentionedrefs
play()
method returns a promise (at least in Chrome); use catch
to handle errors appropriatelyplay()
while the sound is currently playing, it will fail in that caseNote: If you don't have the user click on some button, you will get an error like this
play() failed because the user didn't interact with the document first.
Putting it all together, here is a sample React component which should serve as a decent starting point (it is contrived, but should illustrate the possibilities)
class AudioPlayer extends React.Component
{
constructor(props) {
super(props);
this.audioRef = React.createRef();
this.state = {
interacted: false,
firstSoundPlayed: false,
secondSoundPlayed: false,
};
}
playAudio = () => {
const node = this.audioRef.current;
node.muted = false;
node.volume = 1.0;
node
.play()
.catch((e) => {
console.error('caught audio error: ', e.message);
});
}
handleClick = () => {
this.setState({
interacted: true,
});
setTimeout(() => {
this.playAudio();
this.setState({
firstSoundPlayed: true,
});
setTimeout(() => {
this.playAudio();
this.setState({
secondSoundPlayed: true,
});
}, 6000);
}, 4000);
}
renderStartup = () => (
<p>
Please give me permission to play sounds...
<button onClick={this.handleClick}>Grant permission</button>
</p>
)
renderScreen = () => (
<div>
<p>I will play a sound as many times as I want now!</p>
<p>A sound is about to play...</p>
</div>
)
renderSecondSound = () => (
<div>
<p>Soon it will play again...</p>
</div>
)
renderSummary = () => (
<div>
<p>Hope you found this demo useful...</p>
</div>
)
render = () => {
const {
interacted,
firstSoundPlayed,
secondSoundPlayed,
} = this.state;
return (
<div>
<audio
autoPlay
muted
src="https://freesound.org/data/previews/33/33245_65091-lq.mp3"
ref={this.audioRef}
/>
{interacted === false ? this.renderStartup() : null}
{interacted === true && firstSoundPlayed === false ? this.renderScreen() : null}
{interacted === false || firstSoundPlayed === false || secondSoundPlayed === true ? null : this.renderSecondSound()}
{secondSoundPlayed === false ? null : this.renderSummary()}
</div>);
}
}
ReactDOM.render(
<AudioPlayer />,
document.getElementById('react')
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.0/umd/react-dom.production.min.js"></script>
Upvotes: 0
Reputation: 602
After hours of searching and testing "solutions" this is the one that worked for me! Solved by Angry Fridges (thanks a lot for that).
<video id="video" class="video" autoplay muted >
noticed both autoplay and muted, they are both needed.
This allowed the video to play in both computer and on android phone.
Upvotes: 2
Reputation: 3534
Or you can in initialize your WebView to do it easily, as follows:
webview.setWebViewClient(new WebViewClient() {
// autoplay when finished loading via javascript injection
public void onPageFinished(WebView view, String url) { mMessageContentView.loadUrl("javascript:(function() { document.getElementsByTagName('video')[0].play(); })()"); }
});
The above works fine for me.
Upvotes: 1
Reputation: 23787
I've made the following discoveries about HTML5 video on Android 4.0+.
To perform these tests, I made a sandbox app which consisted of an HTML page saved in /assets.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>HTML5 Video Test</title>
</head>
<body>
<video preload="metadata"><source src="http://www.w3schools.com/html/movie.mp4" type="video/mp4"></video>
<script>
var myvideo = document.getElementsByTagName('video')[0];
myvideo.addEventListener('loadeddata', function() {
console.log("** RECEIVED loadeddata **");
myvideo.play();//this first play is needed for Android 4.1+
}, false);
myvideo.addEventListener('canplaythrough', function() {
console.log("** RECEIVED canplaythrough **");
myvideo.play();//this second play is needed for Android 4.0 only
}, false);
</script>
</body>
</html>
JAVA: ("/assets/html5video.html")
private WebView mWebView;
private ProgressBar mProgressBar;
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.videotest);
// progress bar
mProgressBar = (ProgressBar) findViewById(R.id.videotest_progressbar);
mProgressBar.setProgress(0);
mProgressBar.setVisibility(View.VISIBLE);
// webview
mWebView = (WebView) findViewById(R.id.videotest_webview);
mWebView.getSettings().setJavaScriptEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
{
//NOTE: this is required only for Android 4.2.2+
mWebView.getSettings().setMediaPlaybackRequiresUserGesture(false);
}
mWebView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
Log.i(TAG, "Progress = "+progress);
mProgressBar.setProgress(progress);
}
});
mWebView.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(TestActivity.this, "Problem loading webpage", Toast.LENGTH_LONG).show();
mProgressBar.setVisibility(View.GONE);
}
public void onPageFinished(WebView view, String url) {
mProgressBar.setVisibility(View.GONE);
}
});
}
@Override
protected void onResume() {
super.onResume();
mWebView.loadUrl("file:///android_asset/html5video.html");
}
Android 4.0.3 NOTE
I kept running into the annoying exception java.lang.Throwable: EventHub.removeMessages(int what = 107) is not supported before the WebViewCore is set up.
Thankfully, it did not affect video playback.
Upvotes: 1
Reputation: 653
I found on kitkat that Firefox will allow you to play videos programatically.
Also, Chrome will as well if you go into chrome://flags and enable the "Disable gesture requirement for media playback" option.
Upvotes: 1
Reputation: 13329
I got it to work! Now it can play HTML5 video inline with "autoplay" working! Damn this took time! Ok this is what I did:
<div id=content>
<video width="1280px" height="720px" src="file:///android_asset/videos/Moments_of_Everyday_Life.mp4"></video>
</div>
Note: Some people say they get it to work when adding poster and or preload. I got this working with and with out.
Javascript autoplay the video:
<script type="text/javascript">
$(function(){
function callback () {
document.querySelector('video').src = document.querySelector('video').src
document.querySelector('video').play();
}
window.addEventListener("load", callback, false);
});
</script>
I hope this can help any one, I have struggled with this for a week now!
Just to be clear:
working on:
Android 4.0.4 Samsung 10.1 Tablet Native device Browser
Upvotes: 2
Reputation: 75707
It wouldn't work for the same reason browsers block calls to window.open()
, because allowing it would allow web developers to subvert user preference not to auto play media (or open popup windows).
The difference between clicking play and using this method is exactly what you've said: the click. These sort of calls are allowed in click events, but not generally.
Upvotes: 2