Java Android WebView播放HTML5/h.264/mp4视频,如何使用MediaPlayer

Java Android WebView播放HTML5/h.264/mp4视频,如何使用MediaPlayer,java,android,webview,android-mediaplayer,webchromeclient,Java,Android,Webview,Android Mediaplayer,Webchromeclient,我有一个活动,它是一个网络视图。我有一个WebChromeClient。其中有几个回调,用于返回处理视频位的MediaPlayer。例如: @Override public void onPrepared(MediaPlayer mp) { Log.i(TAG, " -------------> onPrepared"); } 当我使用HTML标记(通过注入)将MP4流加载到WebView时,这些命令无法触发 当我finish()该活动时,logcat会报告以下内容: 09-13

我有一个
活动
,它是一个
网络视图
。我有一个
WebChromeClient
。其中有几个回调,用于返回处理视频位的
MediaPlayer
。例如:

@Override
public void onPrepared(MediaPlayer mp) {
    Log.i(TAG, " -------------> onPrepared");
}
当我使用HTML
标记(通过注入)将MP4流加载到
WebView
时,这些命令无法触发

当我
finish()
该活动时,logcat会报告以下内容:

09-13 23:55:24.590: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:24.680: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:24.680: E/MediaPlayer(7949): mOnVideoSizeChangedListener is null. Failed to send MEDIA_SET_VIDEO_SIZE message.
09-13 23:55:25.675: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:26.735: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:27.755: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:28.705: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
尽管我可以尝试,但我无法让它停止,即使
WebView
被清除,然后被销毁。当使用
标签加载视频时,我不知道有什么方法可以强制
WebChromeClient
使用我为其创建的特定
MediaPlayer
。它似乎决定使用一些隐藏的,其中报告了上述。是否有办法通过
网络视图上的
标记找到从中创建的
MediaPlayer

--更新

以下是初始化WebView的代码:

        mWebView = new WebView(mContext);

        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setPluginState(PluginState.OFF);
        mWebView.setVisibility(View.INVISIBLE);
        mWebView.getSettings().setDefaultZoom(WebSettings.ZoomDensity.FAR);
        mWebView.getSettings().setBuiltInZoomControls(false);
        mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        mWebView.getSettings().setLoadWithOverviewMode(true);
        mWebView.getSettings().setUseWideViewPort(true);
        mWebView.clearHistory();
        mWebView.clearFormData();
        mWebView.clearCache(true);
        mWebView.getSettings().setAllowFileAccess(true);
        mWebView.getSettings().setUserAgentString("Android Mozilla/5.0 AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");

        chrome = new MyWebChromeClient();
        mWebView.setWebChromeClient(chrome);

        wvc = new MyWebViewClient();
        mWebView.setWebViewClient(wvc);

        mDomain = "http://foo.bar.com";
        mWebView.requestFocus(View.FOCUS_DOWN);

        String meat = genMainHTML(R.raw.frame);

        mWebView.loadDataWithBaseURL(mDomain, meat, "text/html", "utf-8", null);
“frame”代码是一个iframe,用于启动一些视频(至少Vimeo和YouTube似乎都采用了这种方法)。为了避免弄脏,我对其进行了一些修剪:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
     <iframe src="-target.url.with.params-" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
     </iframe>
</div>
</body>
</html>
还有这个班:

private class MyWebViewClient extends WebViewClient {

    @Override
    public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            String injection = injectPageMonitor();
            if(injection != null && !injectionComplete) {
                // Log.i(TAG, " ---------------> Page Loaded . . .");
                view.loadUrl(injection);
                injectionComplete = true;
        }
    }

    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Log.d(TAG, "*** Error ["+description+"] ["+failingUrl+"]");
        Toast.makeText(mContext, description, Toast.LENGTH_SHORT).show();
    }

}
    private class MyWebChromeClient extends WebChromeClient implements MediaPlayer.OnInfoListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnErrorListener, MediaPlayer.OnVideoSizeChangedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnBufferingUpdateListener {

       @Override
       public void onProgressChanged(WebView view, int progress) {
           //Log.e(TAG, " -------------> Progress Changed . . . . ["+progress+"] mWebView ["+mWebView+"] ["+view+"]");
           if(progress == 100) {
                               // Do something really interesting
           }  else  {
               updateBuffering(UPDATE_PERCENT_LAUNCH_EXTRACTOR + (progress / 2));
           }
       }

       @Override
       public boolean onConsoleMessage(ConsoleMessage cm) {
                       // Spit out lots of console messages here
           return(true);
       }
   }
我已经推翻了所有通常的嫌疑犯,以防万一我运气好,从MediaPlayer得到一些回应:

        @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        // Jump up and down because we got a mp!
                    // never happens, so no jumping
    }
顺便说一句,我确实使用了反射,并通过这种方式找到了MediaPlayer,但在做了这种事情之后,我总是觉得有点不对劲。即使我有MediaPlayer对象,我也不愿意仅仅释放它。对MP源代码的一点研究表明不会发生什么坏事,但是

我注意到,并非所有设备都会出现这种情况。例如,HTC的表现似乎比三星好(“相同的”OS/API级别——我没有足够的雄心壮志来比较这两个源代码树)

下面提到的行为很烦人,但只对我(正在观看logcat输出的人)而言。对用户或应用程序而言,这似乎没有任何影响。只是我真的不喜欢这样的想法,即我启动MediaPlayer实例,将其设置为忙着缓存,然后(如果/当用户终止我的应用程序时)把那个小家伙留在那里。我现在有很多钱都花在了治疗上,而且似乎没有什么帮助


提前感谢。

如果没有反射,就无法访问MediaPlayer-WebViewClient和WebChromeClient不会故意公开它。你说的没错,使用反射可能会导致你破坏你的应用程序或WebView,因为代码可能因Android版本而异,甚至因OEM而异

如果要执行此操作,必须找到与视频元素相对应的HTML5VideoView实例。此对象创建并维护MediaPlayer的实例“mPlayer”。请参见类中的。

private class MyWebChromeClient extends WebChromeClient 
                                implements ..... MediaPlayer.onCompletion {
}
添加

@Override
public void onCompletion(MediaPlayer mp) {
    // TODO Auto-generated method stub
    mp.release();           
}
在webview关闭后为我清除错误消息


现在,如果我能让webview播放/流式播放vimeo视频就好了:(

看一下这篇文章:似乎是一个类似的问题。请看这篇文章:Marky-非常感谢。正如你所建议的,我已经把我的评论转移到你提出的问题上。在这篇文章中,“Tony”提出的正是我想采用的方法。但是我似乎无法在没有思考的情况下找到
MediaPlayer
ays让我想去绅士家洗个澡。你说“尽管我努力,但我无法阻止它,即使网络视图被清除,然后被销毁”-你怎么知道它被销毁了?取消对WebView的引用可能还不够,我想你可能需要取消WebViewClient和任何其他引用,然后才能将其销毁/垃圾收集?很好。我会试试。很抱歉延迟了响应。这很有帮助,但是,HTML5VideoViewProxy似乎每次都为空我偷看了一下。所以,我继续筛选。但是谢谢!Url已经不存在了。这很好,但是如何在Android 5中实现它呢?HTML5VideoView已经不存在了。我尝试获取mPlayer和mUri,但是Android 5中不再有这个类了。有更新的答案吗?因为API 21+这似乎不再是一个选项;h他们有没有公开一种获得MediaPlayer的方法?谢谢。我应该想到这一点。有一个非常大的解决方案,就是使用这种方法:拯救我的白马王子