Search code examples
androidandroid-11

Android 11: AndroidProtocolHandler: WebView does not show local html file with local images via FileProvider


For many years my app downloaded files and linked images to e.g. the "/Download" folder with the Download Manager. I could show the HTML contents within a WebView.

Since Android 11 this solution is not possible anymore. The links to the locally stored images are broken. Of course I read many posts on this subject.

Downloading an HTML file was succesfully done to /Android/data/my.base.package/files worked. I can show it in a WebView.

When I also download the images to my mobile the WebView does not show the locally downloaded images. In my downloaded HTML file I converted all external URL's of the used images to local pathnames.

The simplified HTML file looked like:

<html...>... 
<img alt="some picture" src="file:///storage/emulated/0/Android/data/my.base.package/files/some-picture.png" />
</html>

Presenting the HTML in a WebView is simplified:

String baseUrl = null; // or "file:///storage/emulated/0/Android/data/base.package.name/files"
myWebView.setWebViewClient(new WebViewClient() {
    view.postDelayed(new Runnable() {
       public void run() { // will convert it to Lambda ;-)
           gcLongDescr.scrollTo(0, scrollPosition);
       }
    }, 300);
});
myWebView.loadDataWithBaseURL( baseUrl, the-html-string, "text/html", "utf-8", null);

QUESTION : Assume I can present the HTML file (as a string) in a WebView. How can I use a (relative) file pathnames to the downloaded pictures?

Try 1: use absolute pathnames in my HTML. Does not work.

Try 2: use the /Download folder. The methods like getExternalStorageDirectory() and getExternalStoragePublicDirectory() on Environment are deprecated.

Try 3: Use the file provider to store the image files.

UPDATE: The last method seems to be the correct method. But I now get the following error:

E/AndroidProtocolHandler: Unable to open content URL: content://nl.xyz.abc.provider/myimages/some-picture.png

Step 1: Make a file provider: in my AndroidManife

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="nl.xyx.abc.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

Add the provider paths to the XML folder:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    ...
    <files-path name="files" path="." />
    <files-path path="images" name="myimages" />
</paths>

Step 2: I copy the image files to the folder file:///storage/emulated/0/Android/data/my.base.package/files/images.

Step 3: In the downloaded HTML file I change the external image URL's to the local files via the FileProvider. An example is:

<img alt="some image" src="content://nl.xyz.abc.provider/myimages/some-picture.png" />

Solution

  • The problem was about 1 using right folders and [2] loading local images in WebView since Android 11.

    First, the downloaded images should be copied to a correct folder of the app, so /Android/data/etc.

    Second, the cause of the problem was that the webSetting.setAllowFileAccess method defaults to true in Android SDK 29 and earlier versions, and false in 30 and later versions. This is explained in this post.

    This did the trick:

    webView = (WebView) rootView.findViewById(R.id.geocahe_description_web_view);
    // webview settings ... 
    webView.getSettings().setAllowFileAccess(true);  // <----- added!
    

    The image files can be downloaded to e.g. /Android/data/my.base.package/files/images. I just refer to the via absolute file names, no prob!