Android Question Webview- Access Denied with API 30

anglia

Member
Licensed User
Longtime User
I’m working on an app that creates a simple html file for users to view in a webview.
I’m trying to cater for all users including those with API 30 devices.

My html file is stored in the DirInternal folder which I thought was available to all users regardless of their Android version.

When I set the TargetSdkversion to 29 there is no problem and the web page displays correctly. However, setting the TargetSdkversion to 30 causes a problem.

I’m using a very simple html file named hello.html for a simple demonstration app.

No errors shown in the log but the message on the device is-

Web Page Not available
The web page at file:///data/data/b4aexample/files/hello.html could not be loaded because:
Net:ERR_ACCESS_DENIED



I’ve tried everything I can think of without success.

If anyone could tell me where I’m going wrong, I’d be very grateful.
 

drgottjr

Expert
Licensed User
Longtime User
the file:// url has been turned off as of api 30.
i think you can probably to turn it back on temporarily with webview extras 2.
the method is setfileallowaccess( true|false ).
enjoy it while it lasts. android doesn't want you to use it, which means you
will soon not be allowed to use it.

you can load your html this way, irrespective of api:
B4X:
webview.loadhtml( file.readstring( file.dirinternal, "file.html" ))

there is a new, dedicated api to handle file:// type urls:
androidx.webkit.WebViewAssetLoader. my guess is after the complaining
dies down, it will ultimately be the only way to load a webview from a file on
one's device.

------------------------------------------------------------------------------------------------
UPDATE:
this is what assetloader looks like, and this is one example of how google wants you to do it:

B4X:
 webview.LoadUrl("https://appassets.androidplatform.net/assets/test.html")


i've tested it (both inline and as part of a library); it's easy to set up and works as expected.
but it would be cleaner if someone maintaining an important library here
(eg, webviewextras or even the core) were to include it there, rather than adding a random
inline snippet which ends up conflicting with such a library. (the assetloader api requires a
webviewclient. if you have a custom webviewclient, you nullify the webviewclient created
in, eg, webviewextras.)

EDIT:

if you don't need webviewextras then you're free to create your own and implement the
assetloader api.


even if you don't use webviewextras, our core webview provides functionality which is nullified
with a custom webviewclient. you would have to add those methods to your custom class if you
really wanted to use the webviewassetloader api and still use the standard webview.

for the purposes of a test, i only made a custom webviewclient. if google decides to do away
with file:// url's to load a webview, assetloader will be required.
 
Last edited:
Upvote 0

anglia

Member
Licensed User
Longtime User
Thanks to both of you for your suggestions.

The LoadHtml - file.readstring suggestion from drgottjr worked perfectly!
Do you think that this Loadhtml way of loading an HTML file will continue to be allowed by Google?


I only have a simple web page to display with no hyperlinks etc. and I’ll stick with this method for the time being.
I’ll need to study the Assetloader option a lot more before I try to use it.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
the file:// url's pose a potential security problem, per google. hence
the new scheme based on https:// (and the availability of a google-supplied
domain to be used in lieu of file://. you are not required to use that domain,
but if you're loading locally kept files in a webview, that's what you would use.)

loading anything is a potential security problem; there is no way to know when
google decides to deprecate and then disallow something as a security risk.
nothing is forever.

normally i would say it's best to embrace whatever new scheme google devises,
since however you're doing things now, you will probably be forced to change.
in this case, it's a little tricky for the reason i mentioned previously.

you may be part of a very small minority using file:// url's (or yugo vehicles), and no
one might ever find it appropriate to incorporate the assetloader api into b4a.
while you wait, the best option is probably the loadhtml(file.readstring()) solution. second
choice would be using webviewextras 2 and turn on setallowfileaccess (true). third
would be a custom fix (so long as you never need webviewextras or similar).

a highly influential point of view here is that webviews should not be used.
also, it's your responsibility to keep abreast of changes in android. "it worked in 29 but
not in 30" should be a big red flag for you.
 
Upvote 0

JohnC

Expert
Licensed User
Longtime User
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
ask our leader. if he's said it once, he's said it, ahhh, a lot more than once. it is kind of a mess and causes a lot of trouble for a number of users (they think it's a drop-in replacement for a browser and get annoyed when they find out it isn't). it's fun when you make it do stuff (with executejavascript); that's probably what freaks google out.
 
Upvote 0

JohnC

Expert
Licensed User
Longtime User
causes a lot of trouble for a number of users (they think it's a drop-in replacement for a browser and get annoyed when they find out it isn't).
I totally agree with that - when the B4x developer doesn't have control over the contents they are trying to display in the webview, all sorts of problems can happen.

However, when a B4x developer has control over the webpage being displayed in the webview, then any issue can be fixed on the backend. And that is exactly why MANY apps use webview because it allows them to change the UI or even fix some issues of an app by simply changing the backend webpage instead of having to re-submit another version of the app to the play store.

So, at least for me, as long as you are not trying to display someone else's webpage, webview can be a very powerful control.
 
Last edited:
Upvote 0

Ferdari

Active Member
Licensed User
Longtime User
How to load from cache url?, my app downloads data to local cache and then displays a preview in webview from cache
I tried without success:
https://appassets.androidplatform.net/public/cache/"& subdir &"/"& filename
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Ferdari

Active Member
Licensed User
Longtime User
How is this domain related to a (webview) cache-folder?
On API 30, you need to use this domain to access data from your app, "file://" urls don't work anymore, can't load data from your app assets or Internal in webview.
New way:
webview.LoadUrl("https://appassets.androidplatform.net/assets/test.html")
But not possible to load files from cache folder, only Internal and Assets
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Ivica Golubovic

Active Member
Licensed User
Opening a file from File.DirInternal or File.DirAssets causes an error because Android 11 uses Scoped Storage. One option is to copy the File to a shared folder using the FileProvider class. Example:

Example::
Dim provider As FileProvider
Dim FileName As String="test.html"
provider.Initialize
File.Copy(File.DirAssets,FileName,provider.SharedFolder,FileName)
Dim FullPath As String=provider.SharedFolder & "/" & FileName
Dim jo As JavaObject=Me
Dim FileUrl As String=jo.RunMethod("fileToUrl",Array(FullPath))
WebView1.LoadUrl(FileUrl)


#If Java
import java.net.URL;
import java.io.File;
import android.net.Uri;

public String fileToUrl(String filePath){
    try{
        File myFile=new File(filePath);
        URL myUrl = myFile.toURI().toURL();
        return myUrl.toString();
    }catch(Exception ex){
        return "";
    }
}

#End If

The above example works for me on two devices with SDK30 (Android 11).
 
Upvote 0
Top