Save Webview Content to Android Storage and Load It

Save webview content to android storage and load it

You can use a Javascript interface for the WebView to return the entirety of the HTML source when the page is finished loading. To do this, you'll need to assign your own WebViewClient to the WebView.

To do this, use something similar to the following in your Activity class -- Make sure your Activity implements Observer:

public void onCreate(Bundle savedInstanceState) {
// ...

webView.setWebViewClient(new MyWebViewClient());
HtmlJSInterface htmlJSInterface = new HtmlJSInterface();
webView.addJavascriptInterface(htmlJSInterface, "HTMLOUT");
htmlJSInterface.addObserver(this);

// ...
}

// Called when our JavaScript Interface Observables are updated.
@Override
public void update(Observable observable, Object observation) {

// Got full page source.
if (observable instanceof HtmlJSInterface) {
html = (String) observation;
onHtmlChanged();
}
}

private void onHtmlChanged() {
// Do stuff here...
}

private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}

@Override
public void onPageFinished(WebView view, String url) {
// When each page is finished we're going to inject our custom
// JavaScript which allows us to
// communicate to the JS Interfaces. Responsible for sending full
// HTML over to the
// HtmlJSInterface...
isStarted = false;
isLoaded = true;
timeoutTimer.cancel();
view.loadUrl("javascript:(function() { "
+ "window.HTMLOUT.setHtml('<html>'+"
+ "document.getElementsByTagName('html')[0].innerHTML+'</html>');})();");
}
}
}

Then, you're going to want to create the HtmlJSInterface class, as such:

   public class HtmlJSInterface extends Observable {
private String html;

/**
* @return The most recent HTML received by the interface
*/
public String getHtml() {
return this.html;
}

/**
* Sets most recent HTML and notifies observers.
*
* @param html
* The full HTML of a page
*/
public void setHtml(String html) {
this.html = html;
setChanged();
notifyObservers(html);
}
}

saving webview into local storage automatically

Save your page as a web archive to your SD card storage in public Documents folder as,

File file;
String filenameExternal = "mypage";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED{
file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), filenameExternal);
}

chem1.saveWebArchive(file.toString()+".mht");

then, save the file name/path using shared preferences when the user leaves the app by overriding @OnStop method.
Finally, load your saved page by reading the file path from shared preference when the user re-opens the app.

if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
chem1.loadUrl(file.toString()+".mht");
} else {

loadOfflinePageBelowKitKat(position);
}

loadOfflinePageBelowKitKat method

public void loadOfflinePageBelowKitKat(){

String rawData = null;
try{
rawData = getStringFromFile(file.toString()+".mht");
}catch (Exception e){
e.printStackTrace();
}

chem1.loadDataWithBaseURL(null, rawData, "application/x-webarchive-xml", "UTF-8", null);

}

getStringFromFile method

public String getStringFromFile(String filePath) throws Exception{
File file = new File(filePath);
FileInputStream fInputStream = new FileInputStream(file);
String wantedString = convertStreamToString(fInputStream);
fInputStream.close();
return wantedString;
}

I assumed you're familiar with working on shared preferences and Files.

Android - Save data from WebView

I am answering my own question I thought it might be helpful to others.

Finally I have solve my problem through Caching in Internal and External Storage(Save data to External Storage if available)

First I have created custom Application class which creates cache storage path in internal or external storage.

MyApplication.java

import android.app.Application;
import android.os.Environment;

import java.io.File;

public class MyApplication extends Application {

protected File extStorageAppBasePath;
protected File extStorageAppCachePath;

@Override
public void onCreate() {
super.onCreate();
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File externalStorageDir = Environment.getExternalStorageDirectory();
if (externalStorageDir != null) {
extStorageAppBasePath = new File(externalStorageDir.getAbsolutePath() +
File.separator + "Android" + File.separator + "data" +
File.separator + getPackageName());
}

if (extStorageAppBasePath != null) {
extStorageAppCachePath = new File(extStorageAppBasePath.getAbsolutePath() +
File.separator + "cache");

boolean isCachePathAvailable = true;

if (!extStorageAppCachePath.exists()) {
isCachePathAvailable = extStorageAppCachePath.mkdirs();
}

if (!isCachePathAvailable) {
extStorageAppCachePath = null;
}
}
}
}

@Override
public File getCacheDir() {
if (extStorageAppCachePath != null) {
return extStorageAppCachePath;
}
else {
return super.getCacheDir();
}
}

}

In Android Manifest file I have given following permission and Application name under application tag.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:name=".MyApplication"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
........................................
</application>

Then final enable cache to load from storage if cache is available.

mWebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

Load file into webView with scoped storage

At first, have you granted the read and write storage permission? The file is in the app's private folder. Generally speaking, the app can access it directly.

In addition, if user update to the API 30, you can use preserveLegacyExternalStorage=true and android:requestLegacyExternalStorage=true to keep and use the old storage model.

Finally, you can add some changes of the WebView's Settings. Such as:

 Control.Settings.AllowFileAccess = true;

For the api 29, the default value of it is true. And api 30 is false.

You can check the official document:
https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccess(boolean)



Related Topics



Leave a reply



Submit