さて、私は既に数日、HTML [5]ビデオをAndroid WebViewでフルスクリーンモードで表示する方法を検索しています。
ウェブビューでHTML5ビデオを再生できました。ビデオをフルスクリーンモードで表示すると問題が発生します。
私が理解したように、Androidには<video>タグを処理する2つの方法があります。
Androidバージョン<= 2.3.3、onShowCustomViewメソッドが起動され、VideoViewインスタンスを使用して、ビデオの完了時にリスナーを設定したり、コントローラーを設定したりできます。
ICS(およびおそらく3.0以上)、<video>は異なる方法で処理されているようです。 HTML5ビデオが再生されるとき、onShowCustomViewは通常モードで呼び出されません-ビデオを再生するWebView内に内部ビジネスがあるように見え、<video>タグで定義されているすべてのコントロールが表示されます-Iどうしてもアクセスできません。実際には、ビデオが通常モードで再生される場合、コントロールが存在し、機能しているため、これは問題ありません。
それが大きな問題につながりました。フルスクリーンモードでビデオを表示するときにonShowCustomViewが呼び出されますが、ICSでは、「view」パラメーターはVideoViewのインスタンスではありません。
インスタンスがVideoSurfaceViewであり、HTML5VideoFullScreenクラスのプライベートな内部クラスであることがわかりました。この内部クラスにアクセスできる唯一の方法は、リフレクションを使用することです。
このクラスのGrepCodeを確認した後、VideoViewとは異なり、HTML5VideoFullScreen $ VideoSurfaceViewはイベントをリッスンしたりコントロールにアクセスできるMediaPlayerインスタンスを保持していないことを学びました。私ができる唯一のことは、このVideoSurfaceViewをそのまま使用し、それを制御せずにフルスクリーンレイアウト内に配置することです。
ボトムライン-ビデオをフルスクリーンで表示するとき、ビデオがいつ終了するかわかりません、そのコントロールは表示されません-これはかなり悲しいです。フルスクリーンを閉じるためのトリガーを取得できません。
私はいくつかの失敗した回避策を試しました:
リフレクション:内部クラスのVideoSurfaceViewから、MediaPlayerメンバーを保持するHTML5VideoFullScreenインスタンスに到達しようとしました。私はそれを取得することができませんでした、これが可能かどうかわかりません(ViewSurfaceViewはその所有者のインスタンスを保持しません)。
JavaScriptを介してビデオイベントに登録し(たとえば、修正済み)、JavascriptInterfaceを介してJavaに必要なものを処理します。 video>タグはにネストできます。 iframeソースは私のものではなく、そのコンテンツを取得できません(getElementByIdまたはgetElementsByTagName [i]はnullです)-つまり、iframe内の<video>要素に到達できません。
私はまだ解決策を探していますが、この問題についてはほとんど書かれていません。誰かがそれを解決できましたか?ヘルプは大歓迎です!
VideoView クラス: ここ (MediaPlayerがあります)
HTML5VideoFullScreen $ VideoSurfaceView クラス: ここ (MediaPlayerはありません)
2014/01の編集:サンプルの使用法を改善して、非ビデオレイアウト、videoLayout、およびvideoLoadingビューを含めるようにしました。
2013/12の編集:Sony Xperiaデバイスの互換性に関連するいくつかのバグ修正が、実際にはすべてのデバイスに影響しました。
2013/11の編集:新しいChromium WebビューでAndroid 4.4 KitKat(APIレベル19)をリリースした後、私は再び一生懸命働かなければなりませんでした。いくつかの改善が行われました。この新しいバージョンに更新する必要があります。 WTFPL でこのソースをリリースします。
2013/04の編集:1週間のハードワークの後、ようやく必要なすべてを達成しました。私が作成したこの2つの汎用クラスは、すべての問題を解決できると思います。
VideoEnabledWebChromeClient
が追加する機能が必要ない場合は、VideoEnabledWebView
を単独で使用できます。ただし、VideoEnabledWebView
は常にVideoEnabledWebChromeClient
に依存する必要があります。 all両方のクラスのコメントを注意深く読んでください。
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;
/**
* This class serves as a WebChromeClient to be set to a WebView, allowing it to play video.
* Video will play differently depending on target API level (in-line, fullscreen, or both).
*
* It has been tested with the following video classes:
* - Android.widget.VideoView (typically API level <11)
* - Android.webkit.HTML5VideoFullScreen$VideoSurfaceView/VideoTextureView (typically API level 11-18)
* - com.Android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView (typically API level 19+)
*
* Important notes:
* - For API level 11+, Android:hardwareAccelerated="true" must be set in the application manifest.
* - The invoking activity must call VideoEnabledWebChromeClient's onBackPressed() inside of its own onBackPressed().
* - Tested in Android API levels 8-19. Only tested on http://m.youtube.com.
*
* @author Cristian Perez (http://cpr.name)
*
*/
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; // Indicates if the video is being displayed using a custom view (typically full-screen)
private FrameLayout videoViewContainer;
private CustomViewCallback videoViewCallback;
private ToggledFullscreenCallback toggledFullscreenCallback;
/**
* Never use this constructor alone.
* This constructor allows this class to be defined as an inline inner class in which the user can override methods
*/
@SuppressWarnings("unused")
public VideoEnabledWebChromeClient()
{
}
/**
* Builds a video enabled WebChromeClient.
* @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen.
* @param activityVideoView A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout.
*/
@SuppressWarnings("unused")
public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView)
{
this.activityNonVideoView = activityNonVideoView;
this.activityVideoView = activityVideoView;
this.loadingView = null;
this.webView = null;
this.isVideoFullscreen = false;
}
/**
* Builds a video enabled WebChromeClient.
* @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen.
* @param activityVideoView A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout.
* @param loadingView A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and without a parent view.
*/
@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;
}
/**
* Builds a video enabled WebChromeClient.
* @param activityNonVideoView A View in the activity's layout that contains every other view that should be hidden when the video goes full-screen.
* @param activityVideoView A ViewGroup in the activity's layout that will display the video. Typically you would like this to fill the whole layout.
* @param loadingView A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and without a parent view.
* @param webView The owner VideoEnabledWebView. Passing it will enable the VideoEnabledWebChromeClient to detect the HTML5 video ended event and exit full-screen.
* Note: The web page must only contain one video tag in order for the HTML5 video ended event to work. This could be improved if needed (see Javascript code).
*/
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;
}
/**
* Indicates if the video is being displayed using a custom view (typically full-screen)
* @return true it the video is being displayed using a custom view (typically full-screen)
*/
public boolean isVideoFullscreen()
{
return isVideoFullscreen;
}
/**
* Set a callback that will be fired when the video starts or finishes displaying using a custom view (typically full-screen)
* @param callback A VideoEnabledWebChromeClient.ToggledFullscreenCallback callback
*/
public void setOnToggledFullscreen(ToggledFullscreenCallback callback)
{
this.toggledFullscreenCallback = callback;
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback)
{
if (view instanceof FrameLayout)
{
// A video wants to be shown
FrameLayout frameLayout = (FrameLayout) view;
View focusedChild = frameLayout.getFocusedChild();
// Save video related variables
this.isVideoFullscreen = true;
this.videoViewContainer = frameLayout;
this.videoViewCallback = callback;
// Hide the non-video view, add the video view, and show it
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 (typically API level <11)
Android.widget.VideoView videoView = (Android.widget.VideoView) focusedChild;
// Handle all the required events
videoView.setOnPreparedListener(this);
videoView.setOnCompletionListener(this);
videoView.setOnErrorListener(this);
}
else
{
// Other classes, including:
// - Android.webkit.HTML5VideoFullScreen$VideoSurfaceView, which inherits from Android.view.SurfaceView (typically API level 11-18)
// - Android.webkit.HTML5VideoFullScreen$VideoTextureView, which inherits from Android.view.TextureView (typically API level 11-18)
// - com.Android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView, which inherits from Android.view.SurfaceView (typically API level 19+)
// Handle HTML5 video ended event only if the class is a SurfaceView
// Test case: TextureView of Sony Xperia T API level 16 doesn't work fullscreen when loading the javascript below
if (webView != null && webView.getSettings().getJavaScriptEnabled() && focusedChild instanceof SurfaceView)
{
// Run javascript code that detects the video end and notifies the Javascript interface
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();"; // Must match Javascript interface name and method of VideoEnableWebView
}
js += "}";
js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";
}
js += "}";
webView.loadUrl(js);
}
}
// Notify full-screen change
if (toggledFullscreenCallback != null)
{
toggledFullscreenCallback.toggledFullscreen(true);
}
}
}
@Override @SuppressWarnings("deprecation")
public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) // Available in API level 14+, deprecated in API level 18+
{
onShowCustomView(view, callback);
}
@Override
public void onHideCustomView()
{
// This method should be manually called on video end in all cases because it's not always called automatically.
// This method must be manually called on back key press (from this class' onBackPressed() method).
if (isVideoFullscreen)
{
// Hide the video view, remove it, and show the non-video view
activityVideoView.setVisibility(View.INVISIBLE);
activityVideoView.removeView(videoViewContainer);
activityNonVideoView.setVisibility(View.VISIBLE);
// Call back (only in API level <19, because in API level 19+ with chromium webview it crashes)
if (videoViewCallback != null && !videoViewCallback.getClass().getName().contains(".chromium."))
{
videoViewCallback.onCustomViewHidden();
}
// Reset video related variables
isVideoFullscreen = false;
videoViewContainer = null;
videoViewCallback = null;
// Notify full-screen change
if (toggledFullscreenCallback != null)
{
toggledFullscreenCallback.toggledFullscreen(false);
}
}
}
@Override
public View getVideoLoadingProgressView() // Video will start loading
{
if (loadingView != null)
{
loadingView.setVisibility(View.VISIBLE);
return loadingView;
}
else
{
return super.getVideoLoadingProgressView();
}
}
@Override
public void onPrepared(MediaPlayer mp) // Video will start playing, only called in the case of Android.widget.VideoView (typically API level <11)
{
if (loadingView != null)
{
loadingView.setVisibility(View.GONE);
}
}
@Override
public void onCompletion(MediaPlayer mp) // Video finished playing, only called in the case of Android.widget.VideoView (typically API level <11)
{
onHideCustomView();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) // Error while playing video, only called in the case of Android.widget.VideoView (typically API level <11)
{
return false; // By returning false, onCompletion() will be called
}
/**
* Notifies the class that the back key has been pressed by the user.
* This must be called from the Activity's onBackPressed(), and if it returns false, the activity itself should handle it. Otherwise don't do anything.
* @return Returns true if the event was handled, and false if was not (video view is not visible)
*/
public boolean onBackPressed()
{
if (isVideoFullscreen)
{
onHideCustomView();
return true;
}
else
{
return false;
}
}
}
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;
/**
* This class serves as a WebView to be used in conjunction with a VideoEnabledWebChromeClient.
* It makes possible:
* - To detect the HTML5 video ended event so that the VideoEnabledWebChromeClient can exit full-screen.
*
* Important notes:
* - Javascript is enabled by default and must not be disabled with getSettings().setJavaScriptEnabled(false).
* - setWebChromeClient() must be called before any loadData(), loadDataWithBaseURL() or loadUrl() method.
*
* @author Cristian Perez (http://cpr.name)
*
*/
public class VideoEnabledWebView extends WebView
{
public class JavascriptInterface
{
@Android.webkit.JavascriptInterface
public void notifyVideoEnd() // Must match Javascript interface method of VideoEnabledWebChromeClient
{
// This code is not executed in the UI thread, so we must force that to happen
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;
}
/**
* Indicates if the video is being displayed using a custom view (typically full-screen)
* @return true it the video is being displayed using a custom view (typically full-screen)
*/
public boolean isVideoFullscreen()
{
return videoEnabledWebChromeClient != null && videoEnabledWebChromeClient.isVideoFullscreen();
}
/**
* Pass only a VideoEnabledWebChromeClient instance.
*/
@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)
{
// Add javascript interface to be called when the video ends (must be done before page load)
addJavascriptInterface(new JavascriptInterface(), "_VideoEnabledWebView"); // Must match Javascript interface name of VideoEnabledWebChromeClient
addedJavascriptInterface = true;
}
}
}
メインレイアウトactivity_main.xml VideoEnabledWebViewおよびその他の使用済みビューを配置します。
<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" >
<!-- View that will be hidden when video goes fullscreen -->
<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>
<!-- View where the video will be shown when video goes fullscreen -->
<RelativeLayout
Android:id="@+id/videoLayout"
Android:layout_width="match_parent"
Android:layout_height="match_parent" >
<!-- View that will be shown while the fullscreen video loads (maybe include a spinner and a "Loading..." message) -->
<View
Android:id="@+id/videoLoading"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_centerInParent="true"
Android:visibility="invisible" />
</RelativeLayout>
</RelativeLayout>
アクティビティのonCreate()、ここで初期化します:
private VideoEnabledWebView webView;
private VideoEnabledWebChromeClient webChromeClient;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Set layout
setContentView(R.layout.activity_main);
// Save the web view
webView = (VideoEnabledWebView) findViewById(R.id.webView);
// Initialize the VideoEnabledWebChromeClient and set event handlers
View nonVideoLayout = findViewById(R.id.nonVideoLayout); // Your own view, read class comments
ViewGroup videoLayout = (ViewGroup) findViewById(R.id.videoLayout); // Your own view, read class comments
View loadingView = getLayoutInflater().inflate(R.layout.view_loading_video, null); // Your own view, read class comments
webChromeClient = new VideoEnabledWebChromeClient(nonVideoLayout, videoLayout, loadingView, webView) // See all available constructors...
{
// Subscribe to standard events, such as onProgressChanged()...
@Override
public void onProgressChanged(WebView view, int progress)
{
// Your code...
}
};
webChromeClient.setOnToggledFullscreen(new VideoEnabledWebChromeClient.ToggledFullscreenCallback()
{
@Override
public void toggledFullscreen(boolean fullscreen)
{
// Your code to handle the full-screen change, for example showing and hiding the title bar. Example:
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);
// Navigate everywhere you want, this classes have only been tested on YouTube's mobile site
webView.loadUrl("http://m.youtube.com");
}
onBackPressed()を呼び出すことを忘れないでください:
@Override
public void onBackPressed()
{
// Notify the VideoEnabledWebChromeClient, and handle it ourselves if it doesn't handle it
if (!webChromeClient.onBackPressed())
{
if (webView.canGoBack())
{
webView.goBack();
}
else
{
// Close app (presumably)
super.onBackPressed();
}
}
}
編集: 他の答え をご覧ください。おそらく今は必要ないでしょう。
あなたが言ったように、APIレベル11+では、HTML5VideoFullScreen $ VideoSurfaceViewが渡されます。しかし、「MediaPlayerがない」と言うとき、あなたは正しいとは思いません。
これは、reflectionを使用してHTML5VideoFullScreen $ VideoSurfaceViewインスタンスからMediaPlayerインスタンスに到達する方法です。
@SuppressWarnings("rawtypes")
Class c1 = Class.forName("Android.webkit.HTML5VideoFullScreen$VideoSurfaceView");
Field f1 = c1.getDeclaredField("this$0");
f1.setAccessible(true);
@SuppressWarnings("rawtypes")
Class c2 = f1.getType().getSuperclass();
Field f2 = c2.getDeclaredField("mPlayer");
f2.setAccessible(true);
Object ___html5VideoViewInstance = f1.get(focusedChild); // Look at the code in my other answer to this same question to see whats focusedChild
Object ___mpInstance = f2.get(___html5VideoViewInstance); // This is the MediaPlayer instance.
したがって、MediaPlayerインスタンスのonCompletionリスナーを次のように設定できます。
OnCompletionListener ocl = new OnCompletionListener()
{
@Override
public void onCompletion(MediaPlayer mp)
{
// Do stuff
}
};
Method m1 = f2.getType().getMethod("setOnCompletionListener", new Class[] { Class.forName("Android.media.MediaPlayer$OnCompletionListener") });
m1.invoke(___mpInstance, ocl);
コードは失敗しませんが、そのonCompletionリスナーが実際に呼び出されるのか、それがあなたの状況に役立つかどうかは完全にはわかりません。ただし、誰かがそれを試してみたい場合に備えて。
設定するだけmWebView.setWebChromeClient(new WebChromeClient());
通常のようにビデオを再生するには、カスタムビューは必要ありません。
クリスティアン、そのクラスを本当にありがとう。
カスタムロードビューが次のようにオプションになるように、マイナーな調整を行いました。
@Override
public View getVideoLoadingProgressView() // Video will start loading, only called in the case of VideoView (typically API level 10-)
{
if (loadingView == null)
{
return super.getVideoLoadingProgressView();
}
else
{
loadingView.setVisibility(View.VISIBLE);
return loadingView;
}
}
また、2つのパラメーターのみを受け取る新しいコンストラクターも追加しました。とにかく、読み込みビューが必要ない場合は、ちょっとした単純化です。これを提供してくれてありがとう。
テスト済みAndroid 9.0バージョン
答えはどれも私には役に立たなかった。これが最後の作業です
import Android.annotation.SuppressLint;
import Android.content.Context;
import Android.graphics.Bitmap;
import Android.graphics.BitmapFactory;
import Android.net.ConnectivityManager;
import Android.net.NetworkInfo;
import Android.support.v7.app.AppCompatActivity;
import Android.os.Bundle;
import Android.view.View;
import Android.webkit.WebChromeClient;
import Android.webkit.WebSettings;
import Android.webkit.WebView;
import Android.webkit.WebViewClient;
import Android.widget.FrameLayout;
import Android.widget.ProgressBar;
public class MainActivity extends AppCompatActivity {
WebView mWebView;
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webView);
mWebView.setWebViewClient(new WebViewClient());
mWebView.setWebChromeClient(new MyChrome());
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setAppCacheEnabled(true);
if (savedInstanceState == null) {
mWebView.loadUrl("https://www.youtube.com/");
}
}
private class MyChrome extends WebChromeClient {
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
protected FrameLayout mFullscreenContainer;
private int mOriginalOrientation;
private int mOriginalSystemUiVisibility;
MyChrome() {}
public Bitmap getDefaultVideoPoster()
{
if (mCustomView == null) {
return null;
}
return BitmapFactory.decodeResource(getApplicationContext().getResources(), 2130837573);
}
public void onHideCustomView()
{
((FrameLayout)getWindow().getDecorView()).removeView(this.mCustomView);
this.mCustomView = null;
getWindow().getDecorView().setSystemUiVisibility(this.mOriginalSystemUiVisibility);
setRequestedOrientation(this.mOriginalOrientation);
this.mCustomViewCallback.onCustomViewHidden();
this.mCustomViewCallback = null;
}
public void onShowCustomView(View paramView, WebChromeClient.CustomViewCallback paramCustomViewCallback)
{
if (this.mCustomView != null)
{
onHideCustomView();
return;
}
this.mCustomView = paramView;
this.mOriginalSystemUiVisibility = getWindow().getDecorView().getSystemUiVisibility();
this.mOriginalOrientation = getRequestedOrientation();
this.mCustomViewCallback = paramCustomViewCallback;
((FrameLayout)getWindow().getDecorView()).addView(this.mCustomView, new FrameLayout.LayoutParams(-1, -1));
getWindow().getDecorView().setSystemUiVisibility(3846 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mWebView.saveState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mWebView.restoreState(savedInstanceState);
}
}
AndroidManifest.xml
<activity
Android:name=".MainActivity"
Android:configChanges="orientation|screenSize" />
ソース Monster Techno
これは素晴らしい。ただし、アプリ自体でWebサイトリンクを開く場合は、ExampleActivity.Javaに次のコードを追加します。
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().endsWith("yourwebsite.com")) {
return false;
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
view.getContext().startActivity(intent);
return true;
}
});
Lollipop以上(または単に異なるWebViewバージョン)では、cprcrack's
onHideCustomView()
メソッドの呼び出しが機能しないようです。フルスクリーンの終了ボタンから呼び出された場合は機能しますが、メソッドを具体的に呼び出すと、フルスクリーンのみが終了しますが、webView
は空白のままです。これを回避する方法は、次のコード行をonHideCustomView()
に追加するだけです。
String js = "javascript:";
js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";
js += "_ytrp_html5_video.webkitExitFullscreen();";
webView.loadUrl(js);
これにより、フルスクリーンが終了したことがwebViewに通知されます。
Cprcrackの答えは、APIレベル19以下で非常にうまく機能します。 cprcrackのonShowCustomView
にほんの少し追加するだけで、APIレベル21+で動作します
if (Build.VERSION.SDK_INT >= 21) {
videoViewContainer.setBackgroundColor(Color.BLACK);
((ViewGroup) webView.getParent()).addView(videoViewContainer);
webView.scrollTo(0,0); // centers full screen view
} else {
activityNonVideoView.setVisibility(View.INVISIBLE);
ViewGroup.LayoutParams vg = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
activityVideoView.addView(videoViewContainer,vg);
activityVideoView.setVisibility(View.VISIBLE);
}
また、onHideCustomView
の変更を反映する必要があります。