27
votes

I have an app that uses WebViews. I've changed my targetAPI from 18 to 19 and I'm currently testing on the new 4.4. For some reason I'm getting this error: Not allowed to load local resource: file:///android_asset/webkit/android-weberror.png on 4.4 but not on 4.3, does somebody have clue why?

Since I don't really know where to start looking I can't give the complete code. It might have something to do with the shouldInterceptRequest(Webview, String) method in the WebViewClient but I'm not really sure. If I know more, I'll update the question.

8
How are you loading the initial page? Is it from a server or is it a html file in the APK?Matt Gaunt
Hello @dumazy! Did you find any solution to this?rahulritesh
@rahulritesh not really, it had something to do with shouldInterceptRequest but I didn't find the right solution so I've decided to take another approach...dumazy
Can you please tell me what you did? I am unable to load my cached data in my app, with Android 4.4rahulritesh
I had this same problem when I forgot to turn on my WiFi, so you might just need to make sure you have an internet connection.sellmaurer

8 Answers

25
votes

I found that I had this problem on KitKat when I used webview.loadData(). If I instead used webview.loadDataWithBaseURL() (I used "file:///android_asset/" as the baseURL), then the problem went away.

The methods setAllowFileAccess(), setAllowFileAccessFromFileURLs(), and setAllowUniversalAccessFromFileURLs() did not have any affect that I could see.

22
votes

A bit of an intrusive hack, but I worked around this issue by introducing a "unique token" and implementing the WebViewClient with a shouldInterceptRequest override.

First, change the URL from file:///android/asset to a relative path with a uniquely identifying token:

<script src="**injection**www/scripts.js"></script>

Then, override shouldInterceptRequest as follows:

// Injection token as specified in HTML source
private static final String INJECTION_TOKEN = "**injection**";

webView.setWebViewClient(new WebViewClient() {

    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        WebResourceResponse response = super.shouldInterceptRequest(view, url);
        if(url != null && url.contains(INJECTION_TOKEN)) {
            String assetPath = url.substring(url.indexOf(INJECTION_TOKEN) + INJECTION_TOKEN.length(), url.length());
            try {
                response = new WebResourceResponse(
                        "application/javascript",
                        "UTF8",
                        getContext().getAssets().open(assetPath)
                );
            } catch (IOException e) {
                e.printStackTrace(); // Failed to load asset file
            }
        }
        return response;
    }
});

This is likely to degrade WebView performance slightly as we are calling the contains() on each resource which is attempted to be loaded, but it's the only workaround I've found to this issue.

9
votes

"Not allowed to load local resource" is a security origin error. The KitKat WebView has stronger security restrictions and it seems like these are kicking in. FWIW I tried just loading a file:///android_asset URL and it worked fine.

Did you call any of the file-related WebSettings APIs (like setAllowFileAccess(false)) by any chance? Are you trying to load the resource from an https: URL?

5
votes

HERE IS THE SOLUTION: This problem occurs when you try to load a file from library projects. If your app depends on a library where webview and html files reside, then you need include assets from that library project into main application project while compiling. For example, IntelliJ has an option to do this. In the compiler settings "Include assets from dependencies into APK", but make sure that your asset files should have different names than main application has. You don't want library project's index.html to be overridden by main app.

1
votes

It may be needed to add a permission

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

to a manifest.

This permission is enforced starting in API level 19.

1
votes

The solution below works for me.

webview.loadDataWithBaseURL( baseUrl, htmlStr, "text/html", "UTF-8", "");

where baseUrl is your external domain, not file:///android_asset/ (i.e. http://a.domain.com ).

1
votes

Not available at the time, this now works (though it's not recommended):

webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

Here's what the doc says about setMixedContentMode:

Configures the WebView's behavior when a secure origin attempts to load a resource from an insecure origin. By default, apps that target KITKAT or below default to MIXED_CONTENT_ALWAYS_ALLOW. Apps targeting LOLLIPOP default to MIXED_CONTENT_NEVER_ALLOW. The preferred and most secure mode of operation for the WebView is MIXED_CONTENT_NEVER_ALLOW and use of MIXED_CONTENT_ALWAYS_ALLOW is strongly discouraged.

However, this might not answer the original question; it looks like the restriction only started with Lollipop.

0
votes

I've found a nice workaround in this link : http://trentmilton.com/android-webview.html

A summary of the solution is something like:

WebView webView = new WebView(this); // this is the context
webView.getSettings().setDomStorageEnabled(true);

Hope that helps