Edytuj 2014/10: na popularne żądanie utrzymuję i przenoszę to do GitHub. Sprawdź ostatnią wersję cprcrack / VideoEnabledWebView . Zachowa tę odpowiedź tylko w celach informacyjnych.
Edytuj 2014/01: ulepszone przykładowe użycie, aby uwzględnić widoki nonVideoLayout, videoLayout i videoLoading, dla tych użytkowników, którzy żądają więcej przykładowego kodu w celu lepszego zrozumienia.
Edytuj 2013/12: kilka poprawek błędów związanych ze zgodnością urządzeń Sony Xperia, które w rzeczywistości dotyczyły wszystkich urządzeń.
Edycja 2013/11: po wydaniu Androida 4.4 KitKat (poziom API 19) z nowym widokiem na przeglądarkę internetową Chromium musiałem znowu ciężko pracować. Wprowadzono kilka ulepszeń. Należy zaktualizować do tej nowej wersji. Udostępniam to źródło pod WTFPL .
Edycja 2013/04: po 1 tygodniu ciężkiej pracy w końcu osiągnąłem wszystko, czego potrzebowałem. Myślę, że te dwie ogólne klasy, które stworzyłem, mogą rozwiązać wszystkie Twoje problemy.
VideoEnabledWebChromeClient
może być używany samodzielnie, jeśli nie potrzebujesz funkcji, która VideoEnabledWebView
dodaje. Ale VideoEnabledWebView
zawsze musi polegać na VideoEnabledWebChromeClient
. Prosimy o uważne przeczytanie wszystkich komentarzy obu zajęć.
VideoEnabledWebChromeClient, klasa
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebChromeClient;
import android.widget.FrameLayout;
public class VideoEnabledWebChromeClient extends WebChromeClient implements OnPreparedListener, OnCompletionListener, OnErrorListener
{
public interface ToggledFullscreenCallback
{
public void toggledFullscreen(boolean fullscreen);
}
private View activityNonVideoView;
private ViewGroup activityVideoView;
private View loadingView;
private VideoEnabledWebView webView;
private boolean isVideoFullscreen;
private FrameLayout videoViewContainer;
private CustomViewCallback videoViewCallback;
private ToggledFullscreenCallback toggledFullscreenCallback;
@SuppressWarnings("unused")
public VideoEnabledWebChromeClient()
{
}
@SuppressWarnings("unused")
public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView)
{
this.activityNonVideoView = activityNonVideoView;
this.activityVideoView = activityVideoView;
this.loadingView = null;
this.webView = null;
this.isVideoFullscreen = false;
}
@SuppressWarnings("unused")
public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView)
{
this.activityNonVideoView = activityNonVideoView;
this.activityVideoView = activityVideoView;
this.loadingView = loadingView;
this.webView = null;
this.isVideoFullscreen = false;
}
public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView, VideoEnabledWebView webView)
{
this.activityNonVideoView = activityNonVideoView;
this.activityVideoView = activityVideoView;
this.loadingView = loadingView;
this.webView = webView;
this.isVideoFullscreen = false;
}
public boolean isVideoFullscreen()
{
return isVideoFullscreen;
}
public void setOnToggledFullscreen(ToggledFullscreenCallback callback)
{
this.toggledFullscreenCallback = callback;
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback)
{
if (view instanceof FrameLayout)
{
FrameLayout frameLayout = (FrameLayout) view;
View focusedChild = frameLayout.getFocusedChild();
this.isVideoFullscreen = true;
this.videoViewContainer = frameLayout;
this.videoViewCallback = callback;
activityNonVideoView.setVisibility(View.INVISIBLE);
activityVideoView.addView(videoViewContainer, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
activityVideoView.setVisibility(View.VISIBLE);
if (focusedChild instanceof android.widget.VideoView)
{
android.widget.VideoView videoView = (android.widget.VideoView) focusedChild;
videoView.setOnPreparedListener(this);
videoView.setOnCompletionListener(this);
videoView.setOnErrorListener(this);
}
else
{
if (webView != null && webView.getSettings().getJavaScriptEnabled() && focusedChild instanceof SurfaceView)
{
String js = "javascript:";
js += "var _ytrp_html5_video_last;";
js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";
js += "if (_ytrp_html5_video != undefined && _ytrp_html5_video != _ytrp_html5_video_last) {";
{
js += "_ytrp_html5_video_last = _ytrp_html5_video;";
js += "function _ytrp_html5_video_ended() {";
{
js += "_VideoEnabledWebView.notifyVideoEnd();";
}
js += "}";
js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";
}
js += "}";
webView.loadUrl(js);
}
}
if (toggledFullscreenCallback != null)
{
toggledFullscreenCallback.toggledFullscreen(true);
}
}
}
@Override @SuppressWarnings("deprecation")
public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback)
{
onShowCustomView(view, callback);
}
@Override
public void onHideCustomView()
{
if (isVideoFullscreen)
{
activityVideoView.setVisibility(View.INVISIBLE);
activityVideoView.removeView(videoViewContainer);
activityNonVideoView.setVisibility(View.VISIBLE);
if (videoViewCallback != null && !videoViewCallback.getClass().getName().contains(".chromium."))
{
videoViewCallback.onCustomViewHidden();
}
isVideoFullscreen = false;
videoViewContainer = null;
videoViewCallback = null;
if (toggledFullscreenCallback != null)
{
toggledFullscreenCallback.toggledFullscreen(false);
}
}
}
@Override
public View getVideoLoadingProgressView()
{
if (loadingView != null)
{
loadingView.setVisibility(View.VISIBLE);
return loadingView;
}
else
{
return super.getVideoLoadingProgressView();
}
}
@Override
public void onPrepared(MediaPlayer mp)
{
if (loadingView != null)
{
loadingView.setVisibility(View.GONE);
}
}
@Override
public void onCompletion(MediaPlayer mp)
{
onHideCustomView();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra)
{
return false;
}
public boolean onBackPressed()
{
if (isVideoFullscreen)
{
onHideCustomView();
return true;
}
else
{
return false;
}
}
}
VideoEnabledWebView, klasa
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import java.util.Map;
public class VideoEnabledWebView extends WebView
{
public class JavascriptInterface
{
@android.webkit.JavascriptInterface
public void notifyVideoEnd()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
@Override
public void run()
{
if (videoEnabledWebChromeClient != null)
{
videoEnabledWebChromeClient.onHideCustomView();
}
}
});
}
}
private VideoEnabledWebChromeClient videoEnabledWebChromeClient;
private boolean addedJavascriptInterface;
public VideoEnabledWebView(Context context)
{
super(context);
addedJavascriptInterface = false;
}
@SuppressWarnings("unused")
public VideoEnabledWebView(Context context, AttributeSet attrs)
{
super(context, attrs);
addedJavascriptInterface = false;
}
@SuppressWarnings("unused")
public VideoEnabledWebView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
addedJavascriptInterface = false;
}
public boolean isVideoFullscreen()
{
return videoEnabledWebChromeClient != null && videoEnabledWebChromeClient.isVideoFullscreen();
}
@Override @SuppressLint("SetJavaScriptEnabled")
public void setWebChromeClient(WebChromeClient client)
{
getSettings().setJavaScriptEnabled(true);
if (client instanceof VideoEnabledWebChromeClient)
{
this.videoEnabledWebChromeClient = (VideoEnabledWebChromeClient) client;
}
super.setWebChromeClient(client);
}
@Override
public void loadData(String data, String mimeType, String encoding)
{
addJavascriptInterface();
super.loadData(data, mimeType, encoding);
}
@Override
public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)
{
addJavascriptInterface();
super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
@Override
public void loadUrl(String url)
{
addJavascriptInterface();
super.loadUrl(url);
}
@Override
public void loadUrl(String url, Map<String, String> additionalHttpHeaders)
{
addJavascriptInterface();
super.loadUrl(url, additionalHttpHeaders);
}
private void addJavascriptInterface()
{
if (!addedJavascriptInterface)
{
addJavascriptInterface(new JavascriptInterface(), "_VideoEnabledWebView");
addedJavascriptInterface = true;
}
}
}
Przykładowe użycie:
Główny układ activity_main.xml, w którym umieściliśmy VideoEnabledWebView i inne używane widoki:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<RelativeLayout
android:id="@+id/nonVideoLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<your.package.VideoEnabledWebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/videoLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<View
android:id="@+id/videoLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="invisible" />
</RelativeLayout>
</RelativeLayout>
Aktywność onCreate () , w której ją inicjujemy:
private VideoEnabledWebView webView;
private VideoEnabledWebChromeClient webChromeClient;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (VideoEnabledWebView) findViewById(R.id.webView);
View nonVideoLayout = findViewById(R.id.nonVideoLayout);
ViewGroup videoLayout = (ViewGroup) findViewById(R.id.videoLayout);
View loadingView = getLayoutInflater().inflate(R.layout.view_loading_video, null);
webChromeClient = new VideoEnabledWebChromeClient(nonVideoLayout, videoLayout, loadingView, webView)
{
@Override
public void onProgressChanged(WebView view, int progress)
{
}
};
webChromeClient.setOnToggledFullscreen(new VideoEnabledWebChromeClient.ToggledFullscreenCallback()
{
@Override
public void toggledFullscreen(boolean fullscreen)
{
if (fullscreen)
{
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
getWindow().setAttributes(attrs);
if (android.os.Build.VERSION.SDK_INT >= 14)
{
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
}
else
{
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
getWindow().setAttributes(attrs);
if (android.os.Build.VERSION.SDK_INT >= 14)
{
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
}
});
webView.setWebChromeClient(webChromeClient);
webView.loadUrl("http://m.youtube.com");
}
I nie zapomnij zadzwonić do OnBackPressed () :
@Override
public void onBackPressed()
{
if (!webChromeClient.onBackPressed())
{
if (webView.canGoBack())
{
webView.goBack();
}
else
{
super.onBackPressed();
}
}
}