Question

I can't get Flowplayer to automatically play video in a WebView on Android. The video plays fine if the in-HTML play button is pressed, but it won't start by itself. This seems to be Chrome-related since autoplay doesn't work in the Android Chrome browser either. It does work in the stock Android browser and in Chrome for the (Linux) desktop.

I've seen this page that suggests adding a WEBM file to get MP4 content to work, but it didn't help. I've also seen this page that mentions using the new setting setMediaPlaybackRequiresUserGesture(), but that didn't help either.

Has anyone gotten autoplay to work in an Android WebView?

Here is my test code that distills the app down to its essentials.

package com.example.testautovideo;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends Activity {

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        WebView webview = new WebView(this);
        setContentView(webview);

        webview.setWebChromeClient(new WebChromeClient());
        webview.getSettings().setJavaScriptEnabled(true);

        webview.getSettings().setLoadsImagesAutomatically(true);
        // webview.getSettings().setMediaPlaybackRequiresUserGesture(false);  // didn't help
        webview.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                return false;
            }
        });

        webview.loadUrl(THE_URL);
    }
}

Here is the source of my web page. The Flowplayer and jQuery calls are to standard installs. The Flowplayer library is the latest free version; the jQuery library is the latest production version.

<!DOCTYPE HTML>
<html>
<head>
<meta name='viewport' content='width=device-width,initial-scale=1,maximum-scale=1,target-densitydpi=device-dpi'>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta property="ws:skip" value="false" />
<title>Autoplay Test</title>
<link rel="stylesheet" type="text/css" href="src/js/flowplayer/skin/minimalist.css">
<script type="text/javascript" src="src/js/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="src/js/flowplayer/flowplayer.min.js"></script>

<script>
$(document).ready(function(){
    function playVideo(){
        var player = flowplayer($('#theVideo'));
        player.play();
    }
    setTimeout(playVideo,10);
});
</script>

<style>
body {
    margin:0;
    padding:0;
    background:#000;
}

#wrapper .flowplayer {
    width:640px;
    height:360px;
}

#wrapper {
    width:640px;
    height:360px;
    background:#000;
    margin:30px auto;
}
</style>
</head>

<body>
<div id="wrapper">
    <div class="flowplayer" id="theVideo">
        <video preload="none" autoplay>
            <source type="video/webm" src="video_1.webm">
            <source type="video/mp4" src="video_1.mp4">
        </video>
    </div>
</div>
</body>
</html>

I know links can go stale, but here's a copy of that web page with working Flowplayer and jQuery installs.

Was it helpful?

Solution

The following is an approach that works on all versions of Android down to Honeycomb (API 11), and perhaps earlier. The important part is to dynamically run load() and play() on the video via JavaScript. Even then, it doesn't always work on older versions of Android (with the setMediaPlaybackRequiresUserGesture() call, which was added in API 17, removed.

The WebView refuses to let the load/play start automatically, but it will let the Android app initiate it. It's desirable for the page itself to be able to determine when the video is started, rather than the app.

Here's what was done to get it all to work. First, a guard condition was put around around the setMediaPlaybackRequiresUserGesture() call to keep it from being run on pre-Jellybean MR1 devices. Then a small, single-method JavascriptInterface class was added and enabled. That method calls an on-page JavaScript method that loads and plays the page's video. Finally, the web pages were altered to call the exposed method when the video should be started. In the code below, the method is called when page has finished loading and the video is set to loop continuously.

Yes, there's a known security concern with enabling a JavascriptInterface class, but our's only has a single method and that method doesn't do anything other than call back into the calling JavaScipt.

The relevant parts of the app:

{    
    ...

    webView = (WebView) findViewById(id.web);
    webView.setWebChromeClient(new WebChromeClient());
    webView.getSettings().setJavaScriptEnabled(true);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
        webView.getSettings().setMediaPlaybackRequiresUserGesture(false);

    webView.addJavascriptInterface(new JsInterface(), "AndroidApp");
}

class JsInterface {
    @JavascriptInterface
    public void startVideo() {
        Log.v(TAG, "in JsInterface.startVideo()");
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.v(TAG, "in JsInterface.startVideo.run");
                webView.loadUrl("javascript:playVideo()");
            }
        });
    }
}

The web page:

<!DOCTYPE HTML>
<html>
<head>
<meta name='viewport' content='width=device-width,initial-scale=1,maximum-scale=1,target-densitydpi=device-dpi'>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Autoplay Test</title>
<link rel="stylesheet" type="text/css" href="src/js/flowplayer/skin/minimalist.css">
<script type="text/javascript" src="src/js/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="src/js/flowplayer/flowplayer.min.js"></script>    
<script type="text/javascript">

function playVideo(){
    var player = flowplayer($('#theVideo'));
    player.load('video_1.mp4');
    player.bind("finish", function() {
        player.play();
    });
}

$(document).ready(function(){    
    AndroidApp.startVideo()    
});
</script>

<style>
body {
    margin:0;
    padding:0;
    background:#000;
}

#wrapper .flowplayer {
    width:640px;
    height:360px;
}

#wrapper {
    width:640px;
    height:360px;
    background:#000;
    margin:30px auto;
}
</style>
</head>

<body>
    <div id="wrapper">
        <div class="flowplayer is-splash" id="theVideo">
            <video preload="none">
                <source type="video/mp4" src="">
            </video>
        </div>
    </div>
</body>
</html>

OTHER TIPS

You will definitely need to call setMediaPlaybackRequiresUserGesture(false) to get this to work. I can't see a problem with your HTML right away, does it work if you use javascript to call play() on the video element from an onload handler, say?

It's intended behavior that Chrome for Android does not support autoplay. But it should work in WebView when setMediaPlaybackRequiresUserGesture is false.

I wasn't able to get it working even with setMediaPlaybackRequiresUserGesture.

So what I did was a simple javascript call to the webpage.

public void triggerPlayVideo()
{

activity.runOnUiThread(new Runnable() {

          @Override
          public void run()
          {
              webView.loadUrl("javascript:playVideo()");
          }

      }

  );  }

This method is triggered once i receive an event from webview that the page got loaded/Video got loaded.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top