androidandroid-webviewandroid-permissions

net::ERR_ACCESS_DENIED despite setting all relevant WebView flags


I am trying to load an HTML file that I generate upon app's start, saved to:

/data/data/com.me.myapp/files/autogen.html

using:

public class FileUtils {

    public static void saveToInternalFile(Context ctx, String fname, String html) {
        try (var fos = Files.newOutputStream(
                Paths.get(ctx.getFilesDir().getAbsolutePath(), fname),
                StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
            fos.write(html.getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String constructInternalFileUrl(Context ctx, String filename) {
        return "file://" + new File(ctx.getFilesDir(), filename).getAbsolutePath();
    }
}

Using Device Explorer, I verified the file exists and is perfectly readable on Edge, Firefox and Chrome.

But attempting to load in the same app that created it (same runtime session) into WebView, as the following URL:

file:///data/user/0/com.me.myapp/files/autogen.html 

results in

The webpage at file:///data/user/0/com.me.myapp/files/autogen.html could not be loaded because: net::ERR_ACCESS_DENIED

This is despite taking care of settings the relevant WebView flags:

WebSettings webSettings = getSettings();
webSettings.setDomStorageEnabled(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);

What could I be missing?

Please note: This is not a duplicate of

because I have already implemented everything suggested on those threads, without much success.


Solution

  • From looking at Android's source code at:

    https://android.googlesource.com/platform/packages/apps/Browser2/+/master/src/org/chromium/webview_shell/WebViewBrowserActivity.java

    It appears that WebView settings are necessary but not sufficient:

        private void loadUrl(String url) {
            // Request read access if necessary
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                    && "file".equals(Uri.parse(url).getScheme())
                    && PackageManager.PERMISSION_DENIED
                            == checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
                requestPermissionsForPage(new FilePermissionRequest(url));
            }
            // If it is file:// and we don't have permission, they'll get the "Webpage not available"
            // "net::ERR_ACCESS_DENIED" page. When we get permission, FilePermissionRequest.grant()
            // will reload.
            mWebView.loadUrl(url);
            mWebView.requestFocus();
        }
    
    

    Did you include in your AndroidManifest.xml the following?

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

    Updating my answer as a response to the comment by the OP:

    You have almost all settings set properly for that :

    WebSettings webSettings = getSettings();
    
    webSettings.setJavaScriptEnabled(true);
    webSettings.setDomStorageEnabled(true);
    webSettings.setAllowFileAccess(true);
    webSettings.setAllowContentAccess(true);
    webSettings.setAllowFileAccessFromFileURLs(true);
    webSettings.setAllowUniversalAccessFromFileURLs(true);
    

    IOW, what you are (probably) missing is

    webSettings.setAllowFileAccess(true);