Android web görünümünde tam ekranda HTML5 video oynatma


92

Pekala, birkaç gündür Android WebView'da HTML5 videosunun tam ekran modunda nasıl görüntüleneceğini araştırıyorum.

Web görünümümde HTML5 videoları oynatmayı başardım. Videoyu tam ekran modunda görüntülerken sorunlar ortaya çıkıyor.

Anladığım gibi, android'in <video> etiketini kullanmanın iki yolu vardır:

  1. <= 2.3.3 Android sürümlerinde , onShowCustomView yöntemi çalıştırılır ve VideoView örneğine sahip olabilir ve video tamamlandığında dinleyicileri ayarlayabilir, denetleyicileri ayarlayabilir vb. Şimdiye kadar çok iyi.

  2. ICS'de (ve muhtemelen 3.0 ve üzeri) , <video> farklı bir şekilde ele alınmış gibi görünüyor. HTML5 videosu oynatıldığında, onShowCustomView normal modda çağrılmıyor - Web Görünümü içinde videoyu oynatan dahili bir işletme var gibi görünüyor ve <video> etiketinde tanımlanan tüm kontroller gösteriliyor - I hiçbir şekilde erişemezsiniz. Aslında, video normal modda oynatılıyorsa sorun değil çünkü kontroller var ve çalışıyor.

Bu beni büyük soruna götürdü: videoyu tam ekran modunda görüntülerken onShowCustomView çağrılıyor - ancak ICS'de "view" parametresi VideoView'ın bir örneği değil.

Örneğin HTML5VideoFullScreen sınıfının özel bir iç sınıfı olan VideoSurfaceView olduğunu bulmayı başardım. Bu iç sınıfa erişebilmemizin tek yolu derinlemesine düşünmektir.

Bu sınıf için GrepCode'a baktıktan sonra, VideoView'dan farklı olarak HTML5VideoFullScreen $ VideoSurfaceView'in olaylarını dinleyebileceğim veya denetimlerine erişebileceğim bir MediaPlayer örneği tutmadığını öğrendim. Yapabileceğim tek şey, bu VideoSurfaceView'i olduğu gibi almak ve onu kontrol etmeden tam ekran bir düzen içine koymak.

Alt satır - Videoyu tam ekranda görüntülerken, videonun ne zaman bittiğini bilmiyorum, kontrolleri gösterilmiyor - bu oldukça üzücü. Tam ekranı kapatmak için tetiği alamıyorum.

Birkaç başarısız geçici çözümü denedim:

  1. Yansıma: İç sınıf VideoSurfaceView'dan bir MediaPlayer üyesi tutan HTML5VideoFullScreen örneğine ulaşmaya çalıştım. Bunu almayı başaramadım, bunun mümkün olduğundan emin değilim (ViewSurfaceView sahibinin örneğini tutmuyor).

  2. Javascript aracılığıyla video etkinliklerine kaydolun (örneğin, bir kez eklendi) ve JAVA'da ihtiyacım olanı JavascriptInterface aracılığıyla işleyin: Bu çözümün güvenilir olmadığını gördüm çünkü bunu yaparken başka bir sorunla karşılaştım: <video> etiketi yuvalanabilir bir. İframe kaynağı benim değil ve içeriğini alamıyorum (getElementById veya getElementsByTagName [i] boş değerlerdir) - yani iframe içindeki <video> öğesine erişemiyorum.

Hala bir çözüm arıyorum, bu konu hakkında çok az şey yazılıyor. Bunu çözmeyi başaran var mı? Yardım çok takdir edilecektir!

VideoView sınıfı: Burada (MediaPlayer var)

HTML5VideoFullScreen $ VideoSurfaceView sınıfı: Burada (MediaPlayer yok)


Sizinle aynı sorun ve aynı sonuçlara da vardınız. Bunun üzerinde yaklaşık 20 saat çalıştım ama en az 20 saat daha pes etmeyeceğim (gerçek çalışma saatleri demek istiyorum). Çözümü bulursam sana söyleyeceğim. Bu arada, bu soru 20 gün önce sorulduğu gibi, hala çözmeye mi çalışıyorsunuz yoksa başka bir geçici çözüm uyguladınız mı?
cprcrack

Bu arada, HTML5VideoFullScreen'in kaynak koduna hızlı bir bakış, HTML5VideoView üst sınıfının bir MediaPlayer içerdiğini gösterdi.
cprcrack

Yanıtlar:


177

2014/10 Düzenleme: Popüler talep üzerine bunu sürdürüyorum ve GitHub'a taşıyorum. Lütfen son sürüm için cprcrack / VideoEnabledWebView'a bakın. Bu cevabı sadece referans için saklayacağız.

2014/01 Düzenlemesi: Daha iyi yorumlama için daha fazla örnek kod isteyen kullanıcılar için nonVideoLayout, videoLayout ve videoLoading görünümlerini içerecek şekilde geliştirilmiş örnek kullanımı.

Edit 2013/12: Sony Xperia cihazlarının uyumluluğuyla ilgili, ancak aslında tüm cihazları etkileyen bazı hata düzeltmeleri.

2013/11 Düzenleme: Android 4.4 KitKat'ın (API seviyesi 19) yeni Chromium web görünümüyle piyasaya sürülmesinden sonra, tekrar çok çalışmak zorunda kaldım. Birkaç iyileştirme yapıldı. Bu yeni sürüme güncellemelisiniz. Bu kaynağı WTFPL altında yayınlıyorum .

Düzenleme 2013/04: 1 haftalık sıkı çalışmanın ardından nihayet ihtiyacım olan her şeyi elde ettim. Sanırım oluşturduğum bu iki genel sınıf tüm problemlerinizi çözebilir.

VideoEnabledWebChromeClientVideoEnabledWebViewekleyen işlevselliğe ihtiyaç duymuyorsanız tek başına kullanılabilir . Ancak VideoEnabledWebViewher zaman a VideoEnabledWebChromeClient. Lütfen her iki sınıfın tüm yorumlarını dikkatlice okuyunuz .

VideoEnabledWebChromeClient sınıfı

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 sınıfı

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

}

Örnek kullanım:

Bir VideoEnabledWebView ve diğer kullanılan görünümleri koyduğumuz ana düzen activity_main.xml :

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

Activity's onCreate () , onu başlattığımız yer:

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

Ve onBackPressed () ' i çağırmayı unutmayın :

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

1
Ne sen önerdi bildirir yalnızca API video uçları <= 10. Açık> = 11, hiçbir şey kayıtları onCompletionListener ...
nbtk

4
Çabaların için teşekkürler! Ancak <video> bir <iframe> altındaysa, ona ulaşamayız, bu nedenle javacsript kısmı mükemmel değildir. Kodunuz çok profesyonel ve etkileyici.
nbtk

3
Bu cevabın kodunu stackoverflow.com/questions/20379478/… dahil etmek yukarıda ortaya koyduğum sorunu çözecektir.
Wienke Giezeman

3
Yükseltmeniz gerekiyor, android v4.4.4 + üzerinde çalışmayın, lütfen onplay için seçenek ekleyin, otomatik olarak tam ekrana gidin. Vimeo'yu bu koda uygulayabilir misiniz? Kodu github'da paylaştığınız için teşekkürler. @cprcrack
Florida

3
en son adroid sürümlerinde çalışmaz ... 5.0, 6.0,7.0 üstü
UMAR-MOBITSOLUTIONS

15

Android 9.0 sürümünde test edildi

Cevapların hiçbiri benim için işe yaramadı. Bu işe yarayan son şey

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

Kaynak Monster Techno


Android: configChanges = "orientation | screenSize" eklemek benim için mükemmel çalıştı. Yardım için teşekkürler!!!
Burak

Özel WebChromeClient'i ayarlamak sorunu benim için çözdü. Teşekkürler!
vato

Teşekkürler! UniteGallery'nin Android WebView'da çalıştırılmasına da yardımcı oldu .
Jan-Peter Schmidt

5

Düzenleme: Lütfen şimdi buna ihtiyacınız olmadığından diğer cevabıma bakın .

Dediğiniz gibi, 11+ API seviyelerinde bir HTML5VideoFullScreen $ VideoSurfaceView geçilir. Ama "MediaPlayer yok" dediğinizde haklı olduğunuzu sanmıyorum.

Bu, yansıma kullanarak HTML5VideoFullScreen $ VideoSurfaceView örneğinden MediaPlayer örneğine ulaşmanın yoludur :

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

Şimdi, MediaPlayer örneğinin onCompletion dinleyicisini şu şekilde ayarlayabilirsiniz:

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

Kod başarısız olmuyor, ancak o onCompletion dinleyicisinin gerçekten çağrılıp çağrılmayacağından veya sizin durumunuz için yararlı olup olamayacağından tam olarak emin değilim. Ama birisinin denemek isteme ihtimaline karşı.


1
Yardımınız için teşekkürler Bu kodu denedim - ilk önce tüm cihazların bir şekilde VideoSurfaceView kullanmadığını görebiliyorum - HTC One X, muhtemelen kendi özel sınıfları olan VideoTextureView'e sahiptir (android belgelerinde değil). Diğer cihazlarda denedim ve hiçbirinde tamamlama dinleyicisi çalıştırıldı.
nbtk

Seçenekle açıyorum, aynı aktivitede youtube videosu oynatmak istiyorum. Ben ne yaparım?
asok Buzz

Merhaba, video bazı devides yığınlarında tam ekrana geçtiğinde istisna oluyorum buradadır pastebin.com/9Gn9jmc2 Yanlış bir şey yapıyorsam
Rajnish Mishra

@cprcrack videoda tam ekran tıklandığında etkinlik yönünü dikeyden yataya değiştirmeye zorlamak mümkün müdür?
Muhammed

1

O ders için çok teşekkür ederim, Cristian.

Özel yükleme görünümünün isteğe bağlı olması için küçük bir değişiklik yaptım, örneğin:

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

Ayrıca sadece iki parametre alan yeni bir kurucu ekledim. Her neyse, yükleme görünümüne ihtiyacınız yoksa sadece küçük bir basitleştirme. Bunu sağladığınız için tekrar teşekkürler.


1

Sadece ayarla
mWebView.setWebChromeClient(new WebChromeClient());

ve normalde olduğu gibi video oynatma özel bir görünüme ihtiyaç duymaz.


8
Ne yazık ki, benim durumumda yardımcı olmadı
resource8218

0

Bu harika. Ancak web sitesi bağlantılarınızın uygulamanın kendisinde açılmasını istiyorsanız, bu kodu ExampleActivity.java dosyanıza ekleyin:

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

0

Cprcrack'in cevabı API seviyeleri 19 ve altı için çok iyi çalışıyor. Cprcrack'lere sadece küçük bir ekleme, onShowCustomViewonu API seviyesi 21+ üzerinde çalıştıracaktır.

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

Ayrıca, içindeki değişiklikleri de yansıtmanız gerekecektir. onHideCustomView


0

Lolipop ve üstü sürümlerde (veya belki sadece farklı bir WebView Sürümü) arama cprcrack's onHideCustomView()yönteminin çalışmadığı anlaşılıyor . Tam ekrandan çık düğmesinden çağrılırsa çalışır, ancak özellikle yöntemi çağırdığınızda yalnızca tam ekrandan çıkacak, ancak webViewboş kalacaktır. Bunun bir yolu, bu kod satırlarını aşağıdakilere eklemektir onHideCustomView():

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

Bu, webView'a tam ekrandan çıkıldığını bildirir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.