Android webview视频未达到readyState = 4

时间:2016-10-29 15:27:58

标签: javascript android webview html5-video android-ffmpeg

我在Android Webview中自动播放视频。 这会给慢速互联网连接带来问题。我得到ANR弹出窗口(应用程序没有响应)

我认为这是因为视频在加载数据之前收到了video.play()。 5秒后,ANR弹出窗口出现。

我想要解决的问题是,在调用video.play()之前等待视频完全加载。

问题是Webview中的视频没有收到视频.readystate == 4.它永远不会像准备状态那样进一步扩展2.即使在正常的互联网连接上也是如此。 在我的Chrome浏览器中,它确实收到了状态清单4.那么为什么呢?为什么Webview中的视频没有收到readystate 4?

在我的代码下面:

<!DOCTYPE html>
<html>
    <head>
        <title>Video</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    </head>
    <body>
        <div id="item" class="item">
            <video preload="auto" autobuffer width="1024" height="576" id="video">
                <source id="videomp4" src="http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4" type='video/mp4' />
            </video>
            <script>
                var interval;
                $(document).ready(function () {
                    interval = setInterval('playVideoWhenReady()', 1000);       
                    /*
                    // this doesn't work either
                    video.addEventListener('loadeddata', function() {
                        // Video is loaded and can be played
                        console.log("video play is triggered");
                        video.play();
                    }, false);
                    */
                });

                function playVideoWhenReady() {
                    var video = document.getElementById('video');
                    console.log("!!!!! curstate: " + video.readyState);
                    if ( video.readyState == 4 ) { // this is never true in Android Webview
                        video.play();
                        clearInterval(interval);
                    }
                }
            </script>
        </div>
    </body>
</html>

MainActivity:

package net.eyefinder.www.testvideo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WebView webView = (WebView) findViewById(R.id.activity_main_webview);

        final WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setMediaPlaybackRequiresUserGesture(false);
        settings.setUseWideViewPort(true);

        webView.setWebChromeClient(new WebChromeClient());

        webView.loadUrl("file:///android_asset/video.html");
    }
}

这就是清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.eyefinder.www.testvideo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:hardwareAccelerated="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.INTERNET" />

</manifest>

然后日志输出为:

10-31 10:55:37.369 2181-2195/net.myapp.www.testvideo D/MediaPlayerPrivateAndroid: load url=http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4
10-31 10:55:37.389 2181-2181/net.myapp.www.testvideo D/TilesManager: Starting TG #0, 0x67360d10
10-31 10:55:37.399 2181-2181/net.myapp.www.testvideo D/TilesManager: new EGLContext from framework: 63c6cd40 
10-31 10:55:37.399 2181-2181/net.myapp.www.testvideo D/GLWebViewState: Reinit shader
10-31 10:55:37.429 2181-2181/net.myapp.www.testvideo D/GLWebViewState: Reinit transferQueue
10-31 10:55:37.449 2181-2181/net.myapp.www.testvideo D/VideoLayerManager: Reinit GLResource for VideoLayer
10-31 10:55:38.439 2181-2181/net.myapp.www.testvideo I/Web Console: !!!!! curstate: 2 at ../video.html:23
10-31 10:55:39.379 2181-2181/net.myapp.www.testvideo I/Web Console: !!!!! curstate: 2 at ../video.html:23
10-31 10:55:40.379 2181-2181/net.myapp.www.testvideo I/Web Console: !!!!! curstate: 2 at ../video.html:23

并且它一直悬挂在第二阶段

2 个答案:

答案 0 :(得分:1)

它通过以下配置为我工作:

WebView webView = (WebView) findViewById(R.id.webview);

final WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setMediaPlaybackRequiresUserGesture(false);

webView.setWebChromeClient(new WebChromeClient());

webView.loadUrl("file:///android_asset/video.html");

src/main/assets/video.html

<!DOCTYPE html>
<html>

<head>
    <title>Video</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>

<body>
    <video preload="auto" autoplay="autoplay" autobuffer width="1024" height="576" id="video" />
    <script>
    var video = document.getElementById('video');
    video.src = 'http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4';
    video.load();

    video.addEventListener('loadeddata', function() {
        video.play();
    }, false);
    </script>
</body>

</html>

在清单中获得Internet权限:

<uses-permission android:name="android.permission.INTERNET" />

答案 1 :(得分:0)

经过一些研究后,我得出的结论是,在Android视频完全加载到Android Webview之前,没有正确的方法等待视频。

当然,有一些解决方案,如:

<video preload="auto" autobuffer width="1024" height="576" id="video"></video>
<script>
    var interval;
    $(function () {
        var video = document.getElementById('video');

        var req = new XMLHttpRequest();
        req.open('GET', 'http://your-video-url.mp4', true);
        req.responseType = 'blob';

        req.onload = function() {
            // Onload is triggered even on 404
            // so we need to check the status code
            if (this.status === 200) {
                var videoBlob = req.response;
                var vid = (window.URL || window.webkitURL || window || {}).createObjectURL(videoBlob); // IE10+
                // Video is now downloaded
                // and we can set it as source on the video element
                video.src = vid;
                video.load();
            }
        }
        req.onerror = function() {
            // Error
        }

        req.send();

        video.addEventListener('progress', function() {
            var range = 0;
            var bf = this.buffered;
            var time = this.currentTime;

            while(!(bf.start(range) <= time && time <= bf.end(range))) {
                range += 1;
            }
            var loadStartPercentage = bf.start(range) / this.duration;
            var loadEndPercentage = bf.end(range) / this.duration;
            var loadPercentage = loadEndPercentage - loadStartPercentage;

            console.log("time: " + time);
            console.log("loadStartPercentage: " + loadStartPercentage);
            console.log("loadEndPercentage: " + loadEndPercentage);
            console.log("loadPercentage: " + loadPercentage);

            if ( loadPercentage == 1 ) {
                 video.play();
            }
        });
    });

但此解决方案不适用于Android 4.2(关于Why can't my Android device play HTML5 video loaded as Blob via XHR?)。

所以我在Android中实现了一个视频下载器,并将本地文件URL解析为JavaScript。现在无需等待视频加载。

我的慢连接问题现在已经解决了!