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
Opening a File from Assets Folder in Android
Partial Invalidation in Custom Android View with Hardware Acceleration
Using Android Studio with Vuforia
Get Color Value Programmatically When It's a Reference (Theme)
Boot Broadcastreceiver Does Not Work on Xiaomi Devices
Black Screen Before Splash Screen Appear in Android
How to Adjust Text Kerning in Android Textview
Startactivityforresult from Activitygroup
Android: Textcolor of Disabled Button in Selector Not Showing
How to Set Up Gradle and Android Studio to Do Release Build
How to Get Code Coverage Using Android Studio
How to Change The Navigationview's Item Text Size
Cordova "Hello World" App Won't Display
How to Implement Zoom Effect for Image View in Android
Why to Use Handlers While Runonuithread Does The Same
How to Load The Listview "Smoothly" in Android
Couldn't Get Connection Factory Client - Fighting with Google Maps