views:

41

answers:

2

Hello,

I'm trying to load/reference images from the app's assets folder from within a HTML page in a WebView. Unlike in most of the examples the HTML page itself is not located in the assets folder but is loaded from a server via http. The background of this question are some performance improvements which should reduce the loading time (and the amount of transferred data) by loading static images directly from the device. I'm not sure if Android has some restrictions here because there's a certain possibility to exploit the app by allowing access to the local file storage from a remotely loaded webpage.

I first tried to load images using <img src="file:///android_asset/myimage.png"> but this failed (for obvious reasons). My next attempt was to use a ContentProvider class and reference images using <img src="content://com.myapp.assetcontentprovider/myimage.png">. This ContentProvider is implemented as follows:

public class AssetContentProvider extends ContentProvider
{
private static final String URI_PREFIX = "content://com.myapp.assetcontentprovider";

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 {
    Log.d("AssetContentProvider", uri.getPath());
    try {
        return getContext().getAssets().openFd(uri.getPath().substring(1)).getParcelFileDescriptor();
    } catch (IOException e) {
        Log.d("AssetContentProvider", "IOException for " + uri.getPath());
        throw new FileNotFoundException();
    }
}

// more methods irrelevant for this post
}

When loading the HTML page I can see in the debug log that openFile() is actually triggered from the WebView and it returns a valid ParcelFileDescriptor object but still the image is not displayed. There are no error messages shown in the log which would tell me that WebView refused to load/display the image. Any ideas if and how this could work?

A: 

This is how I do on the java part:

String myHTML = "< img src=\"file:///android_asset/myimage.jpg\""; myWebView.loadDataWithBaseURL("file:///android_asset/", myHTML, "text/html", "UTF-8", "");

cheers

mufumbo
Thanks for your answer but it's not quite the solution that I was looking for. In my app the HTML page is loaded from an URL over HTTP with myWebView.loadUrl().Or do you propose to load the HTML code with something like org.apache.http and then manually put it into the webview with loadDataWithBaseURL()?
brotherli
A: 

OK, thanks to mufumbo's answer I now found a working hack to mix local assets in remotely loaded HTML pages. Pages loaded using the WebView's loadUrl() method do not load images linked with file:///android_asset/... As a workaround you can fetch the HTML page using org.apache.http.client.methods.HttpGet.HttpGet() and then pass it to the WebView with loadDataWithBaseURL(). In this case the WebView will load resources linked with file:///android_asset/ as well as images and scripts via HTTP. Here's my customized webview code:

public class CustomWebView extends WebView {
    private String mURL;

    public void loadUrlWithAssets(final String url) {
        // copy url to member to allow inner classes accessing it
        mURL = url;

        new Thread(new Runnable() {
            public void run() {
                String html;
                try {
                    html = NetUtil.httpGETResponse(mURL);

                    // replace some file paths in html with file:///android_asset/...

                    loadDataWithBaseURL(mURL, html, "text/html", "UTF-8", "");
                }
                catch (IOException e) {
                    Log.e("CustomWebView.loadUrlWithAssets", "IOException", e);
                }
            }
        }).start();
    }
}

Please note that the whole http fetching is wrapped in the home-grown utility class NetUtil.

With this class it's possible to render HTML pages from a webserver and have some static resources like images or stylesheets loaded from the app's asset folder in order to improve loading speed and to save bandwidth.

brotherli