java - chrome - webview android studio
Android WebView Reproducción de video HTML5/h.264/mp4, Cómo llegar al MediaPlayer (2)
Tengo una Activity
que es una vista WebView
. Tengo un WebChromeClient
dentro de él. Dentro de eso, hay varias devoluciones de llamada que están destinadas a devolver el MediaPlayer
maneja los bits de video. Por ejemplo:
@Override
public void onPrepared(MediaPlayer mp) {
Log.i(TAG, " -------------> onPrepared");
}
Estos no se activan cuando cargo un flujo de MP4 en la WebView
utilizando etiquetas <video>
HTML (a través de inyección).
Cuando finish()
la actividad, el logcat informa de esto:
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.
Por más que lo intente, no puedo hacer que se detenga, a pesar de que la vista WebView
se borra y luego se destruye. Al cargar video usando etiquetas <video>
, no conozco ninguna forma de forzar a WebChromeClient
a usar un MediaPlayer
particular que creo para él. Parece determinado a usar algún oculto, que reporta lo anterior. ¿Hay alguna manera de ubicar el MediaPlayer
creado a través de una etiqueta <video>
en un WebView
?
--Actualizar
Aquí está el código para inicializar el 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);
El código de "marco" es un iframe para lanzar un video (al menos, tanto Vimeo como YouTube parecen adoptar este enfoque). He recortado esto un poco para evitar el crucero:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
<iframe src="-target.url.with.params-" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
</div>
</body>
</html>
Dentro de esa clase de WebView, existe esta clase:
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();
}
}
Y también esta clase:
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);
}
}
Y he anulado todos los sospechosos habituales, en caso de que tenga suerte y obtenga alguna respuesta del MediaPlayer:
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
// Jump up and down because we got a mp!
// never happens, so no jumping
}
Como nota al margen, me dediqué a hacer reflexiones y conseguí el MediaPlayer de esa manera, pero siempre me siento un poco mal después de hacer ese tipo de cosas. Y a pesar de que tengo el objeto MediaPlayer, me resisto a lanzarlo. Un poco de estudio del código fuente de MP sugiere que no pasaría nada malo, pero. . .
Esto no sucede en todos los dispositivos, me he dado cuenta. HTC parece comportarse mejor que Samsung, por ejemplo ("mismo" nivel de OS / API: no soy lo suficientemente ambicioso como para comparar los dos árboles de origen).
El comportamiento que se observa a continuación es molesto, pero solo para mí (quién está viendo la salida logcat. Para el usuario o la aplicación parece no tener ningún efecto. Es solo que realmente me disgusta la idea de que estoy iniciando una instancia de MediaPlayer, configuración se almacena en la memoria caché, y luego (si / cuando el usuario termina mi aplicación) dejando esa dingleberry colgando por ahí. Tengo mucho dinero atado a la terapia en este momento, y no parece estar ayudando.
Gracias por adelantado.
No hay manera de acceder a MediaPlayer sin reflexión: WebViewClient y WebChromeClient no lo exponen intencionalmente. Y tiene razón al decir que el uso de la reflexión podría hacer que rompa su aplicación o la WebView, ya que el código puede variar entre las versiones de Android e incluso entre los OEM.
Si desea hacer esto, deberá ubicar la instancia de HTML5VideoView que corresponde a su elemento de video. Este objeto crea y mantiene una instancia de MediaPlayer como "mPlayer". Consulte https://github.com/android/platform_frameworks_base/blob/jb-mr2-release/core/java/android/webkit/HTML5VideoView.java .
en tu clase
private class MyWebChromeClient extends WebChromeClient
implements ..... MediaPlayer.onCompletion {
}
añadiendo
@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
mp.release();
}
se deshace de los mensajes de error para mí después del cierre de la vista web.
Ahora solo si pudiera obtener la vista web para reproducir / transmitir videos de vimeo :(