[OFFEN] Webview Cache funktioniert nicht

T

tefracky

App-Anbieter (kostenlos)
184
Hallo,

ich habe eine Webview App erstellt, mit der es ebenfalls möglich sein soll, die Webseite offline aufzurufen.

Dies würde ich insofern realisieren, als dass die Webseite im Cache gespeichert wird und dieser wieder aufgerufen wird, wenn keine Internetverbindung besteht. Allerdings ist es so, dass genau gar keine Datei in den Cache geladen wird. Ich habe testhalter den Pfad auf die interne SD Karte gelegt, um zu sehen, ob und welche Dateien gespeichert werden. Der Ordner wird zwar erstellt, aber eben keine Datei rein geschrieben. Damit kann auch keine Webseite offline aufgerufen werden.

Hier der Code, den ich verwende:

Code:
    public WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Self handle links
        mWebView = (WebView) findViewById(R.id.activity_main_webview);
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if(url.startsWith("http://")) {
                    return false;
                }
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                view.getContext().startActivity(intent);
                return true;
            }
        });

        // Enable Javascript
        mWebView.getSettings().setJavaScriptEnabled(true);

        // Caching
        String fileDir = getApplicationContext().getExternalFilesDir(null).getAbsolutePath();
        String cacheDir = fileDir + "/OfflineData";
        new File(fileDir, "/OfflineData").mkdir();


        WebSettings webviewSettings = mWebView.getSettings();
        webviewSettings.setDomStorageEnabled(true);
        webviewSettings.setAppCacheMaxSize(1024*1024*8);
        webviewSettings.setAppCachePath(fileDir);
        webviewSettings.setAllowFileAccess(true);
        webviewSettings.setAppCacheEnabled(true);
        webviewSettings.setCacheMode(WebSettings.LOAD_DEFAULT);

        // Offline Support
        /* if ( isNetworkAvailable() ) {
            webviewSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        } else {
            webviewSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
        } */

        // mWebView.loadUrl("http://www.tsg-wieseck.de?key=MTYyNDY2ODkxODU");
        mWebView.loadUrl("http://www.webseite");
    }

    private boolean isNetworkAvailable() {
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(getApplicationContext().CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
    }

    @Override
    public void onBackPressed() {
        if (mWebView.canGoBack()) {
            mWebView.goBack();
        } else {
            super.onBackPressed();
        }
    }
 
Hallo tef,

Hier nur ein paar Ansatzpunkte / Überlegungen

SD-Karte : Greifst du denn auf das gültige Mount zu ??
Ich gehe mal davon aus , dass du die Device Permisson Requests gesetzt hast ?
(Nicht die in der Manifest)

Was mir direkt aufgefallen ist :
Code:
getExternalFilesDir

Also dein CachePfad ist [packagename]/files/Offlinedata richtig ??
Wenn das so ist, dann würde webviewSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
keinen Sinn machen, da du deinen Cachepfad selbst bestimmst.

Wenn dann in etwa so

Code:
setAppCachePath(mContext.getCacheDir().getPath());
setCacheMode(WebSettings.LOAD_DEFAULT);

Und dann würde ich empfehlen , das Ganze eher erst im ChromeWebClient zu setzen
(onProgressChanged)




P.S Deinen ConnectivityManger solltest du in einem Broadcast-Listener auswerten.
Statisch wird dir i.d.R Mist zurückgeliefert.
 
Zuletzt bearbeitet:
Hallo Stefan,

also mit getExternalFilesDir ist die interne Speicherkarte gemeint, die man im Dateiexplorer sieht. Darauf zugreifen kann ich, da der Ordner "Offlinedata" angelegt wird. Wenn ich den Vorschlag von dir umsete, kann er mit Context nichts anfangen (cannot resolve symbol). Bei "Context" dasselbe Problem. Im Moment habe ich den Pfad nur auf den Speicher gelegt, damit ich sehen kann, ob und was gecached wird. Ich hatte es bereits einmal mit ".getCacheDir().getPath()" hinbekommen und da kam im "Offline-Modus" die Fehlermeldung "ERR_CACHE_MISS". Deshalb wollte ich es auf der Speicherkarte testen damit ich den Cache Ordner sehe.

swa00 schrieb:
P.S Deinen ConnectivityManger solltest du in einem Broadcast-Listener auswerten.
Statisch wird dir i.d.R Mist zurückgeliefert.

Was genau meinst Du damit?
 
Hallo Tel,
kann er mit Context nichts anfangen (cannot resolve symbol). Bei "Context" dasselbe Problem

Öhm, du solltest natürlich deinen gültigen Context nehmen, das war nur ein allgemein gültiger Platzhalter. :scared:
(Sorry, da du hier den Status "App Anbieter" hast, bin ich schon davon ausgegangen , dass Grundkenntnisse vorhanden sind)


Ich hatte es bereits einmal mit ".getCacheDir().getPath()" hinbekommen und da kam im "Offline-Modus" die Fehlermeldung "ERR_CACHE_MISS".

Deshalb musst du erst deinen Cache erstellen lassen und zwar erst im OnProgressChanged Callback.


Was genau meinst Du damit?
Der aktuelle Status wird dir i.d.R. NICHT wiedergegeben, wenn du ihn abfragst.
Dazu nimmst du dir den Broadcast und reagierst auf die Zustände.

Beispiel aus meinem Code :

Code:
 ///////////////////////////////////////////////////////////////////////
    public class _int_NetworkChangeReceiver extends BroadcastReceiver
    {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            mActivity = (Activity) context;
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            if (null != activeNetwork) {
                mCarrier = activeNetwork.getExtraInfo();
                mState   = activeNetwork.getState().toString();
                if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
                {
                    mWifi  = true;
                    mMobile = false;
                    mConnected = true;
                    if (onStatusListener != null) onStatusListener.onStatusChanged(mConnected,mWifi,mMobile,mCarrier,mState);
                    return;
                }

                if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
                {
                    mWifi   = false;
                    mMobile = true;
                    mConnected = true;
                    if (onStatusListener != null) onStatusListener.onStatusChanged(mConnected,mWifi,mMobile,mCarrier,mState);
                    return;
                }
            }
            mConnected = false;
            if (onStatusListener != null) onStatusListener.onStatusChanged(mConnected,mWifi,mMobile,mCarrier,mState);
        }

    }
 
Zuletzt bearbeitet:
Vielen Dank für die schnelle Antwort!
Ich schaue es mir die Tage an und arbeite dann daran weiter und werde mich dann wieder melden.
 
Hallo ihr beiden,
die Lösung mit NetworkChangeReceiver von @swa00 ist veraltet, und viel zu umständlich (und langsam) und der Broadcast muss ab API 24 im Programmcode deklariert werden. @tefracky. deine Lösung entspricht der aktuellen Vorgehensweise, bleibe am besten dabei. Determining and Monitoring the Connectivity Status | Android Developers

Statt dem Externen Speicher kannst man auch den Internal Storage benutzen, wenn die Dateien nicht so groß sind. Saving Files | Android Developers
 
Alles klar, danke! Mein Problem ist eher noch, warum im Moment gar keine Daten gespeichert werden. Könnte es daran liegen, dass ich eine extra Klasse zum Anzeigen des WebViews verwende? Das muss leider sein, damit die Links im Webview Element funktionieren. Ich finde es irgendwie auch immer noch sehr verwirrend, dass sich "ExternalSDCard" auf die interne SD bezieht. Auf der externen SD existiert auch kein Ordner "OfflineDateien".
Gruß
 
@markus.tullius

die Lösung mit NetworkChangeReceiver von @swa00 ist veraltet,

Dann bitte ich um den besseren Vorschlag :)
Zumindest läuft dieser Code ohne Macken bei mir :)

Denn SEIN Vorschlag bietet bei mir enorme Probleme in der Praxis - besonders bei
FCM und Streaming und den hatte ich vorher auch schon drin .

Deshalb mein Einwand :)

Statisch wird dir i.d.R Mist zurückgeliefert
 
Die Lösung ist recht einfach, benutze kein Broadcast. Sonder frage den Status der Verbindung einfach im Code ab. Am besten bevor, du die Methode loadUrl aufrufst, statt dessen läd man dann den html string.


Und was ist daran statisch, in dem Code taucht kein Modifikator static auf.
Und sonst sollte Dir aufgefallen sein, dass spätestens seit Android 7 BrodcastReciver, die im Manifest deklariert werden, in Ungnade gefallen sind. Lösungen, die kein BroadcastReceiver brauchen, werden in der letzten Zeit in der Android Dokumentation bevorzugt.

Broadcasts | Android Developers
Broadcasts | Android Developers
 
Ich widerspreche dir ja gar nicht .

Fakt ist nur , dass ich explizit auf die oben angebende Methode wechseln MUSSTE, damit es stabil läuft.
und mit statisch meinte ich nicht static - sondern die direkte statische Abfrage des Status.

Und sonst sollte Dir aufgefallen sein, dass spätestens seit Android 7 BrodcastReciver, die im Manifest deklariert werden, in Ungnade gefallen sind

Die sind auch für die oben genannte Lösung NICHT notwenig ..
 
Zuletzt bearbeitet:
Was machst du, wenn getType() = TYPE_WIMAX, TYPE_VPN, TYPE_ETHERNET, TYPE_BLUETOOTH usw. ist? Ethernet und Bluethooth hatte ich schon mal. So liefert Dir der BroadcastReciever falsche Werte zurück:
mWifi = ?; (Kann false oder true sein, der Wert wird im Receiver nicht geändert)
mMobile = ?; (Kann false oder true sein, der Wert wird im Receiver nicht geändert)
mConnected = false;

Mir fallen noch ein paar andere Fälle ein, wo der Broadcast falsche Daten zurück liefert (z.B im Ausland)
[doublepost=1509667729,1509667201][/doublepost]Nachtrag:
Denn Begriff statisch verstehe in dem Kontext ich dann nicht. Er will doch nur wissen, ob eine Verbindung existiert, bevor er die URL lädt.
 
Er will doch nur wissen, ob eine Verbindung existiert, bevor er die URL lädt.

Richtig, und ich habe mir lediglich erlaubt , ihn darauf hinzuweisen, dass diverse Apps , die ich bereits in der Praxis habe
mit der von ihm angewendeten Vorgehensweise nicht zuverlässig arbeiten.
Da gibt es z.b. Streaming-Abbrüche, die nicht rechtzeitig wieder aufgesetzt werden,
FCM's werden verschluckt usw usw.

Es sei denn du, pollst in einem Thread - eine unnötige Resourceverschwendung

Aus diesem Grunde ist es mir eigentlich recht unverständlich, dass Du grundsätzlich dies als falsch bezeichnest,
dich auf das reine theoretisch Geschriebene beziehst und auch noch davon ausgehst , dass ein Manifest Eintrag
benötigt wird, obwohl das nicht der Fall ist. (Hatte ich auch überhaupt nicht erwähnt)

mWifi = ?; (Kann false oder true sein, der Wert wird im Receiver nicht geändert)
mMobile = ?; (Kann false oder true sein, der Wert wird im Receiver nicht geändert)

Natürlich werden die Werte zuverlässig geändert - wie kommst du darauf ?

Sei bitte so lieb und probiere es erst mal selbst aus - Und zwar im Feld, nicht auf dem Papier

Mir fallen noch ein paar andere Fälle ein, wo der Broadcast falsche Daten zurück liefert (z.B im Ausland)

An dieser Stelle würde es mich schon interessieren , warum ein hardware-getriggerter Broadcast im
Ausland nicht laufen sollte ? - Das wäre mir dann neu.

Bis dato hatte ich weder in den USA , noch in südlichen europäischen Ländern einen
Defizit feststellen können.
 
Zuletzt bearbeitet:
Hallo ihr Beiden,

ich werde meine Lösung erst einmal lassen, wie sie ist und testen, ob es nennenswerte Fälle gibt, bei Denne ein Verbesserungsbedarf herrscht.

Aber zurück zu meiner Frage: Wieso wird kein Cache gespeichert? Wenn ich den Cache Pfad auf den geschützten "getappcache" Pfad setze, wird beim Laden ohne Internet nichts angezeigt. Da ich mein Hand nicht gerootet habe, sehe ich auch leider nicht, ob und welche Daten angelegt werden.

Kann ich vielleicht beim Android Emulator Root Zugriff erhalten, um da weiter zu schauen? Oder kann ich einem mein Projekt als GIT oder von mir aus auch als ZIP zukommen lassen? Ich möchte ungerne alles hier veröffentlichen, aber es wurmt mich sehr, dass es nicht geht.

Gruß
 

Ähnliche Themen

SaniMatthias
Antworten
19
Aufrufe
959
swa00
swa00
K
Antworten
3
Aufrufe
1.168
Kapikalaani
K
O
Antworten
15
Aufrufe
2.970
ORHUX
O
Zurück
Oben Unten