Domanda

Sto mettendo insieme un'app economica che tra le altre cose "incornicia" alcuni dei nostri siti web...Abbastanza semplice con il WebViewClient.finché non ho raggiunto il video.

Il video è fatto come HTML5 elementi, e questi funzionano bene e alla grande su Chrome, iPhone e ora che abbiamo risolto i problemi di codifica, funziona benissimo su Android nel browser nativo.

Ora il problema: WebView non gli piace.Affatto.Posso fare clic sull'immagine del poster e non succede nulla.

Cercando su Google, ho trovato Questo che è simile, ma sembra essere basato su un 'link' (come in a href...) invece che su un elemento video.(onDownloadListener non sembra essere richiamato su elementi video...)

Vedo anche riferimenti all'override di onShowCustomView, ma sembra che non venga richiamato sugli elementi video...né dovrebbeOverrideUrlLoading..

Preferirei non entrare in "estrai xml dal server, riformattalo nell'app".Mantenendo il layout della storia sul server, posso controllare un po' meglio il contenuto senza costringere le persone a continuare ad aggiornare un'app.Quindi, se riesco a convincere WebView a gestire i tag come il browser nativo, sarebbe la cosa migliore.

Chiaramente mi manca qualcosa di ovvio..ma non ho idea di cosa.

È stato utile?

Soluzione

I rispondere a questa discussione in caso qualcuno lo lesse e si interessa sul risultato. E 'possibile visualizzare un elemento video (tag HTML5 video) all'interno di una WebView, ma devo dire che ho avuto a che fare con esso per pochi giorni. Questi sono i passi ho dovuto seguire fino ad ora:

-Trova un video codificato correttamente

-Quando l'inizializzazione del WebView, impostare il JavaScript, i plug-in del WebViewClient e la WebChromeClient.

url = new String("http://broken-links.com/tests/video/"); 
mWebView = (WebView) findViewById(R.id.webview);
mWebView.setWebChromeClient(chromeClient);
mWebView.setWebViewClient(wvClient);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setPluginState(PluginState.ON);
mWebView.loadUrl(url);

-Maniglia l'onShowCustomView nell'oggetto WebChromeClient.

@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
    super.onShowCustomView(view, callback);
    if (view instanceof FrameLayout){
        FrameLayout frame = (FrameLayout) view;
        if (frame.getFocusedChild() instanceof VideoView){
            VideoView video = (VideoView) frame.getFocusedChild();
            frame.removeView(video);
            a.setContentView(video);
            video.setOnCompletionListener(this);
            video.setOnErrorListener(this);
            video.start();
        }
    }
}

-Maniglia l'onCompletion e gli eventi OnError per il video, al fine di tornare alla visualizzazione Web.

public void onCompletion(MediaPlayer mp) {
    Log.d(TAG, "Video completo");
    a.setContentView(R.layout.main);
    WebView wb = (WebView) a.findViewById(R.id.webview);
    a.initWebView();
}

Ma ora devo dire che ci sono ancora un problema importante. Posso giocare solo una volta. La seconda volta clicco sul video dispatcher (sia il manifesto o qualche pulsante di riproduzione), non fa nulla.

Vorrei anche il video di giocare all'interno del telaio WebView, invece di aprire la finestra di Media Player, ma questo è per me un problema secondario.

Spero che aiuta qualcuno, e vorrei anche ringraziare ogni commento o suggerimento.

Saludos, terrícolas.

Altri suggerimenti

Dopo lunghe ricerche, ho questa cosa di lavoro. Vedere il seguente codice:

Test.java

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;

public class Test extends Activity {

    HTML5WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mWebView = new HTML5WebView(this);

        if (savedInstanceState != null) {
            mWebView.restoreState(savedInstanceState);
        } else {    
            mWebView.loadUrl("http://192.168.1.18/xxxxxxxxxxxxxxxx/");
        }

        setContentView(mWebView.getLayout());
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mWebView.saveState(outState);
    }

    @Override
    public void onStop() {
        super.onStop();
        mWebView.stopLoading();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (mWebView.inCustomView()) {
                mWebView.hideCustomView();
            //  mWebView.goBack();
                //mWebView.goBack();
                return true;
            }

        }
        return super.onKeyDown(keyCode, event);
    }
}

HTML% VIDEO.java

package com.ivz.idemandtest;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;

public class HTML5WebView extends WebView {

    private Context                             mContext;
    private MyWebChromeClient                   mWebChromeClient;
    private View                                mCustomView;
    private FrameLayout                         mCustomViewContainer;
    private WebChromeClient.CustomViewCallback  mCustomViewCallback;

    private FrameLayout                         mContentView;
    private FrameLayout                         mBrowserFrameLayout;
    private FrameLayout                         mLayout;

    static final String LOGTAG = "HTML5WebView";

    private void init(Context context) {
        mContext = context;     
        Activity a = (Activity) mContext;

        mLayout = new FrameLayout(context);

        mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(a).inflate(R.layout.custom_screen, null);
        mContentView = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.main_content);
        mCustomViewContainer = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.fullscreen_custom_content);

        mLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);

        // Configure the webview
        WebSettings s = getSettings();
        s.setBuiltInZoomControls(true);
        s.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
        s.setUseWideViewPort(true);
        s.setLoadWithOverviewMode(true);
      //  s.setSavePassword(true);
        s.setSaveFormData(true);
        s.setJavaScriptEnabled(true);
        mWebChromeClient = new MyWebChromeClient();
        setWebChromeClient(mWebChromeClient);

        setWebViewClient(new WebViewClient());

setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);

        // enable navigator.geolocation 
       // s.setGeolocationEnabled(true);
       // s.setGeolocationDatabasePath("/data/data/org.itri.html5webview/databases/");

        // enable Web Storage: localStorage, sessionStorage
        s.setDomStorageEnabled(true);

        mContentView.addView(this);
    }

    public HTML5WebView(Context context) {
        super(context);
        init(context);
    }

    public HTML5WebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public HTML5WebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public FrameLayout getLayout() {
        return mLayout;
    }

    public boolean inCustomView() {
        return (mCustomView != null);
    }

    public void hideCustomView() {
        mWebChromeClient.onHideCustomView();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if ((mCustomView == null) && canGoBack()){
                goBack();
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    private class MyWebChromeClient extends WebChromeClient {
        private Bitmap      mDefaultVideoPoster;
        private View        mVideoProgressView;

        @Override
        public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback)
        {
            //Log.i(LOGTAG, "here in on ShowCustomView");
            HTML5WebView.this.setVisibility(View.GONE);

            // if a view already exists then immediately terminate the new one
            if (mCustomView != null) {
                callback.onCustomViewHidden();
                return;
            }

            mCustomViewContainer.addView(view);
            mCustomView = view;
            mCustomViewCallback = callback;
            mCustomViewContainer.setVisibility(View.VISIBLE);
        }

        @Override
        public void onHideCustomView() {
            System.out.println("customview hideeeeeeeeeeeeeeeeeeeeeeeeeee");
            if (mCustomView == null)
                return;        

            // Hide the custom view.
            mCustomView.setVisibility(View.GONE);

            // Remove the custom view from its container.
            mCustomViewContainer.removeView(mCustomView);
            mCustomView = null;
            mCustomViewContainer.setVisibility(View.GONE);
            mCustomViewCallback.onCustomViewHidden();

            HTML5WebView.this.setVisibility(View.VISIBLE);
            HTML5WebView.this.goBack();
            //Log.i(LOGTAG, "set it to webVew");
        }


        @Override
        public View getVideoLoadingProgressView() {
            //Log.i(LOGTAG, "here in on getVideoLoadingPregressView");

            if (mVideoProgressView == null) {
                LayoutInflater inflater = LayoutInflater.from(mContext);
                mVideoProgressView = inflater.inflate(R.layout.video_loading_progress, null);
            }
            return mVideoProgressView; 
        }

         @Override
         public void onReceivedTitle(WebView view, String title) {
            ((Activity) mContext).setTitle(title);
         }

         @Override
         public void onProgressChanged(WebView view, int newProgress) {
             ((Activity) mContext).getWindow().setFeatureInt(Window.FEATURE_PROGRESS, newProgress*100);
         }

         @Override
         public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
             callback.invoke(origin, true, false);
         }
    }


    static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS =
        new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}

custom_screen.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android">
    <FrameLayout android:id="@+id/fullscreen_custom_content"
        android:visibility="gone"
        android:background="@color/black"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    />
    <LinearLayout android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout android:id="@+id/error_console"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
        />

        <FrameLayout android:id="@+id/main_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
        />
    </LinearLayout>
</FrameLayout>

video_loading_progress.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/progress_indicator"
         android:orientation="vertical"
         android:layout_centerInParent="true"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content">

       <ProgressBar android:id="@android:id/progress"
           style="?android:attr/progressBarStyleLarge"
           android:layout_gravity="center"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content" />

       <TextView android:paddingTop="5dip"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:text="@string/loading_video" android:textSize="14sp"
           android:textColor="?android:attr/textColorPrimary" />
 </LinearLayout>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/any/http_authentication_colors.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
** you may not use this file except in compliance with the License. 
** You may obtain a copy of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** Unless required by applicable law or agreed to in writing, software 
** distributed under the License is distributed on an "AS IS" BASIS, 
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
** See the License for the specific language governing permissions and 
** limitations under the License.
*/
-->
<!-- FIXME: Change the name of this file!  It is now being used generically
    for the browser -->
<resources>
    <color name="username_text">#ffffffff</color>
    <color name="username_edit">#ff000000</color>

    <color name="password_text">#ffffffff</color>
    <color name="password_edit">#ff000000</color>

    <color name="ssl_text_label">#ffffffff</color>
    <color name="ssl_text_value">#ffffffff</color>

    <color name="white">#ffffffff</color>
    <color name="black">#ff000000</color>



    <color name="geolocation_permissions_prompt_background">#ffdddddd</color>
</resources>

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.test"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".Test"
                  android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:configChanges="orientation|keyboardHidden|keyboard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>  
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
</manifest>

In attesa resto delle cose si può capire.

La risposta di mdelolmo era incredibilmente disponibile, ma, come ha detto, il video viene riprodotto una sola volta e poi non è possibile aprirlo di nuovo.

Ho guardato in questo un po 'e qui è quello che ho trovato, nel caso in cui qualsiasi viaggiatori WebView stanchi come me inciampare su questo post in futuro.

Prima di tutto, ho guardato il VideoView e MediaPlayer 's documentazione "http://developer.android.com/reference/android/media/MediaPlayer.html" rel = "noreferrer" e ottenuto un senso migliore di come quelli di lavoro. Consiglio vivamente quelli.

Poi, ho guardato il codice sorgente per vedere come il Browser Android lo fa. Fare una pagina di ritrovamento e andare a vedere come gestire onShowCustomView(). Mantengono un riferimento al CustomViewCallbackand per la visualizzazione personalizzata.

Con tutto ciò, e con la risposta di mdelolmo in mente, quando si è fatto con il video, tutto quello che dovete fare è due cose. In primo luogo, il VideoView che si è salvato un riferimento a, chiamata stopPlayback() che rilascerà il MediaPlayer per essere utilizzato in seguito altrove. Lo si può vedere nel VideoView codice sorgente. In secondo luogo, sulla CustomViewCallback è stato salvato un riferimento alla chiamata CustomViewCallback.onCustomViewHidden().

Dopo aver fatto queste due cose, è possibile fare clic sullo stesso video o qualsiasi altro video e si aprirà come prima. Non c'è bisogno di riavviare l'intero WebView.

La speranza che aiuta.

In realtà, sembra sufficiente allegare meramente uno stock WebChromeClient alla vista del cliente, ala

mWebView.setWebChromeClient(new WebChromeClient());

e avete bisogno di avere accelerazione hardware attivata!

Almeno, se non è necessario per riprodurre un video a schermo intero, non c'è bisogno di tirare il VideoView fuori dal WebView e spingerlo in vista della attività. Si giocherà in rect assegnato dell'elemento video.

Tutte le idee su come intercettare il pulsante VIDEO Espandi?

So che questa discussione è diversi mesi, ma ho trovato una soluzione per la riproduzione del video all'interno del WebView senza farlo a schermo intero (ma ancora nel lettore multimediale ...). Finora, non ho trovato alcun accenno su questo in Internet in modo forse questo è interessante anche per gli altri. Sto ancora lottando su alcune questioni (cioè ponendo il lettore multimediale nella sezione a destra dello schermo, non so perché sto facendo male, ma è un relativamente piccolo problema credo ...).

Nel ChromeClient personalizzato specificare LayoutParams:

// 768x512 is the size of my video
FrameLayout.LayoutParams LayoutParameters = 
                                     new FrameLayout.LayoutParams (768, 512); 

Il mio metodo onShowCustomView aspetto:

public void onShowCustomView(final View view, final CustomViewCallback callback) {
     // super.onShowCustomView(view, callback);
     if (view instanceof FrameLayout) {
         this.mCustomViewContainer = (FrameLayout) view;
         this.mCustomViewCallback = callback;
         this.mContentView = (WebView) this.kameha.findViewById(R.id.webview);
         if (this.mCustomViewContainer.getFocusedChild() instanceof VideoView) {
             this.mCustomVideoView = (VideoView) 
                                     this.mCustomViewContainer.getFocusedChild();
             this.mCustomViewContainer.setVisibility(View.VISIBLE);
             final int viewWidth = this.mContentView.getWidth();
             final int viewLeft = (viewWidth - 1024) / 2;
             // get the x-position for the video (I'm porting an iPad-Webapp to Xoom, 
             // so I can use those numbers... you have to find your own of course...
             this.LayoutParameters.leftMargin = viewLeft + 256; 
             this.LayoutParameters.topMargin = 128;
             // just add this view so the webview underneath will still be visible, 
             // but apply the LayoutParameters specified above
             this.kameha.addContentView(this.mCustomViewContainer, 
                                             this.LayoutParameters); 
             this.mCustomVideoView.setOnCompletionListener(this);
             this.mCustomVideoView.setOnErrorListener(this);
             // handle clicks on the screen (turning off the video) so you can still
             // navigate in your WebView without having the video lying over it
             this.mCustomVideoView.setOnFocusChangeListener(this); 
             this.mCustomVideoView.start();
         }
     }
 }

Quindi, spero che ho potuto fare ... troppo ho dovuto giocare con il video-codifica e ho visto diversi tipi di utilizzare il WebView con video HTML5 - alla fine il mio codice di lavoro è stato un mix selvaggio di codici diverse parti ho trovato in internet e alcune cose che ho dovuto capire da solo. E 'stato davvero una rottura di un *.

Questo approccio funziona bene molto fino a 2.3 Ed aggiungendo hardwareaccelerated = true funziona anche da 3,0 a ICS Un problema che sto affrontando attualmente è su secondo lancio di applicazione media player è sempre caduto perché non ho smesso di riproduzione e rilasciato lettore multimediale. Come oggetto VideoSurfaceView, che si ottiene in funzione onShowCustomView da 3,0 OS, sono specifici al browser e non un oggetto VideoView come in, fino a 2.3 OS Come posso accedervi e stopPlayback e liberare le risorse?

AM L'è simile a quello che il BrowerActivity fa. per       FrameLayout.LayoutParams LayoutParameters = new FrameLayout.LayoutParams (768, 512);

Credo che possiamo usare

FrameLayout.LayoutParams LayoutParameters = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,
            FrameLayout.LayoutParams.FILL_PARENT) 

, invece.

Un altro problema che ho incontrato è se il video è in riproduzione, e l'utente fa clic sul pulsante indietro, la prossima volta, si va a questa attività (singleTop uno) e non può riprodurre il video. per risolvere questo problema, ho chiamato il

try { 
    mCustomVideoView.stopPlayback();  
    mCustomViewCallback.onCustomViewHidden();
} catch(Throwable e) { //ignore }

nel metodo onBackPressed della propria attività.

So che questo è un molto vecchia questione, ma hai provato la bandiera manifesta hardwareAccelerated="true" per la vostra applicazione o attività?

Con questo set, sembra funzionare senza alcuna modifica WebChromeClient (che mi aspetterei da un DOM-elemento.)

html5webview per risolvere questo problem.Download e metterlo nel progetto allora si può codificare proprio come questo.

private HTML5WebView mWebView;
String url = "SOMEURL";
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mWebView = new HTML5WebView(this);
    if (savedInstanceState != null) {
            mWebView.restoreState(savedInstanceState);
    } else {
            mWebView.loadUrl(url);
    }
    setContentView(mWebView.getLayout());
}
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mWebView.saveState(outState);
}

Per rendere il video ruotabile, mettere Android: configChanges = codice "orientamento" nella vostra attività per esempio (AndroidManifest.xml)

<activity android:name=".ui.HTML5Activity" android:configChanges="orientation"/>

e l'override del metodo onConfigurationChanged.

@Override
public void onConfigurationChanged(Configuration newConfig) {
     super.onConfigurationChanged(newConfig);
}

Questa domanda è anni, ma forse la mia risposta sarà aiutare le persone come me che hanno per sostenere vecchia versione di Android. Ho provato un sacco di diversi approcci che hanno lavorato su alcune versioni di Android, tuttavia, non su tutti. La soluzione migliore che ho trovato è quello di utilizzare la pedonale Webview che è ottimizzato per l'HTML5 funzione di supporto e funziona su Android 4.1 e più alto. E 'semplice da utilizzare come predefinito di Android WebView. Non vi resta che includere la libreria. Qui potete trovare un semplice tutorial su come usarlo: https://diego.org/2015/01/07/embedding-crosswalk-in-android-studio/

Bene, a quanto pare questo non è possibile senza utilizzare una JNI per registrare un plugin per ottenere l'evento video.(Personalmente, sto evitando JNI poiché non voglio davvero avere a che fare con un pasticcio quando i tablet Android basati su Atom usciranno nei prossimi mesi, perdendo la portabilità di Java.)

L'unica vera alternativa sembra essere quella di creare una nuova pagina Web solo per WebView e realizzare video alla vecchia maniera con un collegamento A HREF, come citato nell'URL Codelark sopra.

Schifoso.

In uso a nido d'ape e hardwareaccelerated=true pluginstate.on_demand sembra funzionare

Ho avuto un problema simile. Ho avuto i file HTML e video nella attivi cartella del mio app.

Quindi i video si trovavano all'interno della APK. Perché l'APK è in realtà un file ZIP, la WebView non era in grado di leggere i video-file.

Copia tutto HTML- e video-file sulla SD-Card ha lavorato per me.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top