Abspielen von HTML5-Videos im Vollbildmodus in der Android-Webansicht

92

Nun, ich habe bereits einige Tage gesucht, wie man HTML5-Videos im Vollbildmodus auf Android WebView anzeigt.

Ich konnte HTML5-Videos in meiner Webansicht abspielen. Bei der Anzeige von Videos im Vollbildmodus treten Probleme auf.

Wie ich herausgefunden habe, hat Android zwei Möglichkeiten, mit dem <video> -Tag umzugehen:

  1. In Android-Versionen <= 2.3.3 wird die onShowCustomView-Methode ausgelöst, und ich kann die VideoView-Instanz verwenden und Listener einstellen, wenn das Video fertig ist, Controller usw. einstellen. Soweit so gut.

  2. Auf ICS (und wahrscheinlich 3.0 und höher) sieht es so aus, als würde das <Video> anders behandelt. Wenn das HTML5-Video abgespielt wird, wird onShowCustomView im normalen Modus nicht aufgerufen. Es sieht so aus, als ob sich in WebView ein internes Unternehmen befindet, das das Video wiedergibt, und alle im <video> -Tag definierten Steuerelemente werden angezeigt - I. kann in keiner Weise darauf zugreifen. Wenn das Video im normalen Modus abgespielt wird, ist dies in Ordnung, da die Steuerelemente vorhanden sind und funktionieren.

Das führte mich zu dem großen Problem: Wenn das Video im Vollbildmodus angezeigt wird, wird onShowCustomView aufgerufen - auf ICS ist der Parameter "view" jedoch keine Instanz von VideoView.

Ich konnte herausfinden, dass es sich bei der Instanz um VideoSurfaceView handelt, eine private innere Klasse der HTML5VideoFullScreen-Klasse. Der einzige Weg, wie wir auf diese innere Klasse zugreifen können, ist die Reflexion.

Nachdem ich mir GrepCode für diese Klasse angesehen hatte, stellte ich fest, dass HTML5VideoFullScreen $ VideoSurfaceView im Gegensatz zu VideoView keine MediaPlayer-Instanz enthält, mit der ich seine Ereignisse abhören oder auf seine Steuerelemente zugreifen kann. Das einzige, was ich tun kann, ist, dieses VideoSurfaceView so zu nehmen, wie es ist, und es in ein Vollbild-Layout einzufügen, ohne es zu steuern.

Fazit - Wenn ich Videos im Vollbildmodus anzeige, weiß ich nicht, wann das Video endet, seine Steuerelemente werden nicht angezeigt - das ist ziemlich traurig. Ich kann den Auslöser zum Schließen des Vollbilds nicht bekommen.

Ich habe einige erfolglose Problemumgehungen versucht:

  1. Reflexion: Ich habe versucht, die HTML5VideoFullScreen-Instanz, die ein MediaPlayer-Mitglied enthält, über die VideoSurfaceView der inneren Klasse zu erreichen. Ich habe es nicht geschafft, ich bin mir nicht sicher, ob dies möglich ist (ViewSurfaceView enthält nicht die Instanz seines Besitzers).

  2. Registrieren Sie sich für die Videoereignisse über Javascript (z. B. onended) und erledigen Sie das, was ich in JAVA benötige, über JavascriptInterface: Ich habe festgestellt, dass diese Lösung nicht zuverlässig ist, da dabei ein anderes Problem aufgetreten ist: Das <video> -Tag kann verschachtelt werden in einem (n . Die iframe-Quelle gehört nicht mir und ich kann ihren Inhalt nicht abrufen (getElementById oder getElementsByTagName [i] sind Nullen). Dies bedeutet, dass ich das <video> -Element im iframe nicht erreichen kann.

Ich bin immer noch auf der Suche nach einer Lösung, über dieses Problem ist sehr wenig geschrieben. Hat es jemand geschafft, es zu lösen? Hilfe wäre sehr dankbar!

VideoView- Klasse: Hier (hat MediaPlayer)

HTML5VideoFullScreen $ VideoSurfaceView- Klasse: Hier (ohne MediaPlayer)

nbtk
quelle
Das gleiche Problem wie Sie und auch zu den gleichen Schlussfolgerungen gelangt. Ich habe ungefähr 20 Stunden daran gearbeitet, werde aber mindestens 20 Stunden nicht mehr aufgeben (echte Arbeitsstunden, meine ich). Ich werde Ihnen sagen, ob ich die Lösung finde. Versuchen Sie in der Zwischenzeit, da diese Frage vor 20 Tagen gestellt wurde, immer noch, sie zu lösen, oder haben Sie eine andere Problemumgehung angewendet?
cprcrack
Ein kurzer Blick auf den Quellcode von HTML5VideoFullScreen zeigte übrigens, dass die übergeordnete Klasse HTML5VideoView einen MediaPlayer enthält.
cprcrack

Antworten:

176

Edit 2014/10: Auf vielfachen Wunsch pflege ich dies und verschiebe es auf GitHub. Bitte überprüfen Sie cprcrack / VideoEnabledWebView für die letzte Version. Bewahrt diese Antwort nur als Referenz auf.

Bearbeiten 2014/01: Verbesserte Beispielnutzung um die Ansichten Nicht-VideoLayout, VideoLayout und VideoLoading für Benutzer, die mehr Beispielcode zum besseren Verständnis anfordern.

Edit 2013/12: Einige Fehlerbehebungen im Zusammenhang mit der Kompatibilität von Sony Xperia-Geräten, die jedoch tatsächlich alle Geräte betrafen.

Edit 2013/11: Nach der Veröffentlichung von Android 4.4 KitKat (API Level 19) mit seiner neuen Chromium-Webansicht musste ich wieder hart arbeiten. Es wurden mehrere Verbesserungen vorgenommen. Sie sollten auf diese neue Version aktualisieren. Ich veröffentliche diese Quelle unter WTFPL .

Edit 2013/04: Nach 1 Woche harter Arbeit habe ich endlich alles erreicht, was ich brauchte. Ich denke, diese zwei generischen Klassen, die ich erstellt habe, können alle Ihre Probleme lösen.

VideoEnabledWebChromeClientkann alleine verwendet werden, wenn Sie die hinzugefügte Funktionalität nicht benötigen VideoEnabledWebView. VideoEnabledWebViewMuss sich aber immer auf a verlassen VideoEnabledWebChromeClient. Bitte lesen Sie alle Kommentare der beiden Klassen sorgfältig durch.

VideoEnabledWebChromeClient-Klasse

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;
        }
    }

}

VideoEnabledWebView-Klasse

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;
        }
    }

}

Anwendungsbeispiel:

Haupt Layout activity_main.xml , in dem wir eine VideoEnabledWebView und andere gebrauchte Ansichten setzen:

<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>

Die Aktivität ist onCreate () , in der wir sie initialisieren:

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");
}

Und vergessen Sie nicht, onBackPressed () aufzurufen :

@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();
        }
    }
}
cprcrack
quelle
1
Was Sie vorgeschlagen haben, wird benachrichtigt, wenn das Video nur auf API <= 10 endet. Bei> = 11 registriert nichts den onCompletionListener ...
nbtk
4
Danke für Ihr Bemühen! Wenn sich das <video> jedoch unter einem <iframe> befindet, können wir es nicht erreichen, sodass der Javacsript-Teil nicht perfekt ist. Ihr Code ist sehr professionell und beeindruckend.
nbtk
3
Durch das Einfügen des Codes dieser Antwort stackoverflow.com/questions/20379478/… wird das oben gestellte Problem gelöst.
Wienke Giezeman
2
Benötigen Sie ein Upgrade, arbeiten Sie nicht mit Android v4.4.4 +, fügen Sie bitte die Option zum Onplay hinzu, gehen Sie automatisch zum Vollbildmodus. Sie können vimeo für diesen Code implementieren? Vielen Dank, dass Sie den Code auf github geteilt haben. @cprcrack
Florida
2
es funktioniert nicht in den neuesten Android-Versionen ... über 5.0, 6.0,7.0
UMAR-MOBITSOLUTIONS
10

Getestet auf Android 9.0 Version

Keine der Antworten hat bei mir funktioniert. Dies ist das Letzte, was funktioniert hat

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);
    }
}

In AndroidManifest.xml

<activity
  android:name=".MainActivity"
  android:configChanges="orientation|screenSize" />

Quelle Monster Techno

Manohar Reddy
quelle
Das Hinzufügen von android: configChanges = "Orientierung | Bildschirmgröße" hat bei mir perfekt funktioniert. Danke für die Hilfe!!!
Burak
Das Festlegen des benutzerdefinierten WebChromeClient hat das Problem für mich gelöst. Vielen Dank!
Vato
5

Bearbeiten: Bitte sehen Sie meine andere Antwort , da Sie diese jetzt wahrscheinlich nicht brauchen.

Wie Sie sagten, wird in API-Levels 11+ ein HTML5VideoFullScreen $ VideoSurfaceView übergeben. Aber ich glaube nicht, dass Sie Recht haben, wenn Sie sagen, dass "es keinen MediaPlayer gibt".

Auf diese Weise erreichen Sie die MediaPlayer-Instanz über die HTML5VideoFullScreen $ VideoSurfaceView-Instanz mithilfe von Reflection :

@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.

Jetzt können Sie den onCompletion-Listener der MediaPlayer-Instanz folgendermaßen einstellen:

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);

Der Code schlägt nicht fehl, aber ich bin nicht ganz sicher, ob dieser onCompletion-Listener wirklich aufgerufen wird oder ob er für Ihre Situation nützlich sein könnte. Aber nur für den Fall, dass jemand es versuchen möchte.

cprcrack
quelle
1
Vielen Dank für Ihre Hilfe. Ich habe diesen Code ausprobiert. Zuerst kann ich feststellen, dass nicht alle Geräte VideoSurfaceView verwenden. Das HTC One X verfügt über VideoTextureView, das wahrscheinlich die benutzerdefinierte Klasse ist (nicht in den Android-Dokumenten). Ich habe es auf anderen Geräten versucht und auf keinem von ihnen wurde der Completion Listener aufgerufen.
nbtk
Ich öffne mich mit Option, ich möchte YouTube-Video mit der gleichen Aktivität abspielen. Was mache ich?
Asok Buzz
Hallo, ich bekomme eine Ausnahme, wenn das Video auf einigen Teilen des Stacktraces im Vollbildmodus angezeigt wird. Pastebin.com/9Gn9jmc2 Wenn ich etwas falsch mache
Rajnish Mishra
@cprcrack Ist es möglich, das Ändern der Aktivitätsausrichtung von Hochformat zu Querformat zu erzwingen, wenn der Vollbildmodus auf Video geklickt wird?
Muhammad
1

Vielen Dank für diese Klasse, Cristian.

Ich habe eine kleine Änderung daran vorgenommen, damit die benutzerdefinierte Ladeansicht optional ist, wie folgt:

  @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;
        }
    }

Ich habe auch einen neuen Konstruktor hinzugefügt, der nur zwei Parameter akzeptiert. Wie auch immer, nur eine kleine Vereinfachung, wenn Sie die Ladeansicht nicht benötigen. Nochmals vielen Dank für die Bereitstellung.

Scott Schafer
quelle
1

Einfach einstellen
mWebView.setWebChromeClient(new WebChromeClient());

und Videowiedergabe wie gewohnt benötigt keine benutzerdefinierte Ansicht.

Pranav
quelle
7
Leider hat in meinem Fall nicht geholfen
resource8218
0

Das ist toll. Wenn Sie jedoch möchten, dass Ihre Website-Links in der App selbst geöffnet werden, fügen Sie diesen Code in Ihre ExampleActivity.java ein:

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;
        }
    });
Sid
quelle
0

Die Antwort von Cprcrack funktioniert sehr gut für API-Level 19 und darunter. Mit nur einer kleinen Ergänzung zu cprcrack onShowCustomViewfunktioniert es auf API-Level 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);
}

Sie müssen auch die Änderungen in widerspiegeln onHideCustomView

Grux
quelle
0

Es scheint, dass in lollipop und höher (oder vielleicht nur in einer anderen WebView-Version) diese aufrufende cprcrack's onHideCustomView()Methode nicht funktioniert. Es funktioniert, wenn es über die Schaltfläche "Vollbild beenden" aufgerufen wird. Wenn Sie jedoch die Methode speziell aufrufen, wird nur der Vollbildmodus beendet, das Feld webViewbleibt jedoch leer. Eine Möglichkeit, dies zu umgehen, besteht darin, diese Codezeilen einfach hinzuzufügen zu onHideCustomView():

String js = "javascript:";
js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";
js += "_ytrp_html5_video.webkitExitFullscreen();";
webView.loadUrl(js);

Dadurch wird das WebView darüber informiert, dass der Vollbildmodus beendet wurde.

Michael Kern
quelle