There was another way to display local files - by overriding WebViewClient.shouldOverrideUrlLoading, but since 1.0 SDK it's gone.
Right now community agrees that a relatively easy way to make WebView display local files is through a custom ContentProvider.
It's not quite obvious what needs to be overridden for this specific task. I couldn't find a complete example online. So I decided to share mine.
There are 2 steps
- Create new class that extends ContentProvider and override essentially 1 method openFile. Method onCreate can be empty returning true and the rest can just throw UnsupportedOperationException.
- Add a provider entry to AndroidManifest.xml.
Note, that method constructUri is just a utility method that can be used to construct provider specific URI out of a file path.
package com.tourizo.android.content;
import java.io.*;
import android.content.*;
import android.database.*;
import android.net.*;
import android.os.*;
public class LocalFileContentProvider extends ContentProvider {
private static final String URI_PREFIX = "content://com.tourizo.android.localfile";
public static String constructUri(String url) {
Uri uri = Uri.parse(url);
return uri.isAbsolute() ? url : URI_PREFIX + url;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File file = new File(uri.getPath());
ParcelFileDescriptor parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
return parcel;
}
@Override
public boolean onCreate() {
return true;
}
@Override
public int delete(Uri uri, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public String getType(Uri uri) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public Uri insert(Uri uri, ContentValues contentvalues) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) {
throw new UnsupportedOperationException("Not supported by this provider");
}
@Override
public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
}
AndroidManifest.xml entry under application tag
<provider android:name=".content.LocalFileContentProvider"
android:authorities="com.tourizo.android.localfile"
/>
I hope this was helpful.
Happy hacking! :)
Hi, thanks for sharing! I've been searching everywhere for this information. But I think there is one missing step: how exactly do you load the html file into the webview? webview.loadUrl('???:???') How does it refer to the sdcard? And is there an 8kb limit? I want to show some html documentation which is downloaded from the server and stored in the sdcard. It can change over time, so I don't want to embed it as resources. Strange that one needs to 'hack' to display local html files.
ReplyDeleteAbe, for an example for how to hook it up with WebView, see
ReplyDeletehttp://www.techjini.com/blog/2009/01/10/android-tip-1-contentprovider-accessing-local-file-system-from-webview-showing-image-in-webview-using-content/
I think if your HTML data can have a link like
<img src=content://com.tourizo.android.localfile/foo.jpg>
Hello, about this, what do I need to change to access files on the internal memory of the phone? Like in the cache folder of my application for instance.. is that possible?
ReplyDeleteThank you
Hello, any one explain me how to use the code in my project . which method i want to call or any one provide sample app code with contentprovider .
ReplyDeleteThanks,
"AndroidManifest.xml entry under application tag" is a little confusing. It better says "AndroidManifest.xml entry inside application tag".
ReplyDeleteIf you just want to read a file you have embbed in you .apk, there is a much simpler way to do it.
ReplyDeleteJust add your file in a folder named "assets" in your project
and you can get your file at the url:
file:///android_asset/your_file
sample code here:
http://developer.android.com/resources/articles/using-webviews.html
final String mimeType = "text/html";
ReplyDeletefinal String encoding = "utf-8";
WebView wv;
try {
InputStream is = getAssets().open("test.html");
int size = is.available();
// Read the entire asset into a local byte buffer.
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
// Convert the buffer into a string.
String strContent = new String(buffer);
wv = (WebView) findViewById(R.id.webview);
wv.loadData(strContent, mimeType, encoding);
} catch (IOException e) {
// Should never happen!
throw new RuntimeException(e);
}
}
Hi,
ReplyDeletethanks for the write-up. We have this method in our code for images and it works. What I did see in the log was that first Android tries to call query() on the content provider. This throws the expected UnsupportedOperationException, but after that everything works fine. I guess Android calls query() first and then openFile(). Is there a way to prevent this? So Android only calls openFile()?
Cheers
Marc
Is it works for pdf files??
ReplyDeletehow can i display only a string in web view.(not read from file ).
ReplyDeleteis it work on jelly bean ?
ReplyDelete