I've got a library included in my project, which exposes some assets in assets directory.
When running the app on Android 7, it works great and webview loads the assets fine. Today I have tested the app on Kitkat (API 19), and the resources loaded like file://android_asset/someAsset.png are not loaded.
I have checked the aar file created for my library and it contains those files [obviously, since the APK works fine on Android 7].
Here are my web settings:
WebSettings s = getSettings();
s.setAllowFileAccess(true);
s.setSupportZoom(false);
s.setBuiltInZoomControls(false);
s.setDomStorageEnabled(true);
s.setJavaScriptCanOpenWindowsAutomatically(true);
s.setUseWideViewPort(true);
s.setLoadWithOverviewMode(true);
s.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
s.setJavaScriptEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
s.setMediaPlaybackRequiresUserGesture(false);
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
s.setAllowFileAccessFromFileURLs(true);
s.setAllowUniversalAccessFromFileURLs(true);
}
s.setGeolocationEnabled(false);
The error I get when debugging chrome is: File not found.
I have read some questions posted on SO, which refer to an IntelliJ setting: "Include assets from dependencies into APK" which is not there in Android Studio anymore. I have found however this doc page: https://developer.android.com/studio/projects/android-library.html which indicate, that adding
dependencies {
compile project(':myLib')
}
is enough to provide the assets to the main project [and it clearly does, hence the AAR contents].
Still, I cannot get those resources to show up.
I have also tried to copy the assets directory from the library to the main project, but still no luck. They are not loaded by webview and I get the same error.
I am going to answer my own question, because however stupid the problem is, who knows, maybe someone will stumble upon a similar issue.
I use shouldInterceptRequest method of WebViewClient to load files for WebView, as all of the content is encrypted and I have to decrypt it first.
Starting with Lollipop, the method has a different signature:
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
instead of
public WebResourceResponse shouldInterceptRequest(final WebView view, String url)
Since I have wrote my code using new devices, I simply had:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { ... }
and it worked fine. When testing on old device, the method was not triggered at all and it would not find the file where it expected it.
After I have added support for this method, it all started to work.
Thanks #CommonsWare for the comment.
Related
I have been working on an android application, using Kotlin. Recently, I have been trying to implement video calls using Javascript with the help of Webview in android, the problem is that when loading the activity in which the Webview is in, it does not show the HTML page.
As far as I know, everything is in place, and the code from what I've researched should be fine. I have already rebuilt the application and it still does not work.
That code box below shows the supposed correct way to load the page, but I only get a: "ERR_FILE_NOT_FOUND"
val filePath = "file:///android_asset/Content/call.html"
webView.loadUrl(filePath)
Then I tried to access the page using the following syntax for the filepath:
val filePath = "./src/main/assets/Content/call.html"
And it worked, it stopped showing the error, but this is a problem, because it doesn't work like that on physical devices.
There is also this error that shows in logcat:
E/AndroidProtocolHandler: Unable to open asset URL: file:///android_asset/Content/call.html
I have also tried moving the files outside of the Content folder, does not work.
This is perhaps a very simple mistake, but I can't find the solution. It would be highly appreciated if any of you could help me, thank you.
You should be using a WebViewAssetLoader. This is the android recommended way to load static webpages and you should not be using file path.
WebviewAssetLoader will host the files in the below path - http(s)://appassets.androidplatform.net/assets/...
In your case it would be - https://appassets.androidplatform.net/assets/Content/call.html
Sample code :
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
.addPathHandler("/assets/", new AssetsPathHandler(this))
.build();
webView.setWebViewClient(new WebViewClient() {
#Override
#RequiresApi(21)
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(request.getUrl());
}
#Override
#SuppressWarnings("deprecation") // for API < 21
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(Uri.parse(request));
}
});
WebSettings webViewSettings = webView.getSettings();
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.setAllowFileAccessFromFileURLs(false);
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.setAllowUniversalAccessFromFileURLs(false);
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.setAllowFileAccess(false);
webViewSettings.setAllowContentAccess(false);
// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webview.loadUrl("https://appassets.androidplatform.net/assets/www/index.html");
I just solved my specific problem.
It turns out that my "assets" folder was not inside the "main" folder, but inside a different folder in "src". I just created a new assets folder inside "main" and placed the files there, now the HTML page loads properly. Had to go into project view.
I'm using the standard Android SDK with Ecliple as provided from the Android website.
What I want to to is to have an activity display a WebView that loads a local HTML-file. Everything works fine until I try to load the webview.
I've placed all the index-files I've tried in the project's assets-folder.
This is the code in my activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("file:///android_assets/www/index.html");
setContentView(webView);
}
When I run the app over ADB, I get the following message in the WebView:
Webpage not available
The webpage at file:///android_assets/www/index.html might be temporarily down or it may have moved permanently to a new web address.
I know this problem has been posted before, and I've tried every single solution out there. But it just won't load. It displays online http-addresses just fine, but it doesn't seem to find any of the local files.
Please help me, this drives me mad.
Change this line:
webView.loadUrl("file:///android_assets/www/index.html");
to this :
webView.loadUrl("file:///android_asset/www/index.html");
is android_asset not android_assets :D. Good Luck
I have an App that uses custom schemes in Android WebViewClient's shouldInterceptRequest(WebView view, String url) and shouldOverrideUrlLoading(WebView view, String url) to intercept requests in a web application and use a native library to fetch resources from elsewhere in shouldInterceptRequest. This has worked fine up until Android 4.4 KitKat, where Google has made some crucial changes to the webView component.
http://developer.android.com/guide/webapps/migrating.html#URLs
Now the url received in shouldOverrideUrlLoading suddenly gets invalid, looking like this; custom-scheme:////my.pathname.com/. First I suspected the extra slashes were because Android did not think the url were valid RFC3986, but in a series of resource fetches (css, js, images), the url starts off correct and suddenly changes to the invalid format. The webView in Android 4.3 kept the url correctly as custom-scheme://my.pathname.com/. It seems like the base url suddenly changes to '/' instead of 'my.pathname.com'.
Then my attention changed to the fact that the webView 4.4 migration guide talks about:
If you call methods on WebView from any thread other than your app's UI thread, it can cause unexpected results. http://developer.android.com/guide/webapps/migrating.html#Threads
This also might be what I am experiencing, but I have not yet come up with a solution where I can use runOnUiThread() to fetch data with the native api and return it to the webView inside shouldInterceptRequest. Has anyone experienced something similar?
Here is a simplified version of my shouldInterceptRequest code:
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (urlStartsWithKnownPrefix(url)) {
UrlFetchResult fetchRes = api.fetchUrl(url);
String charset = "utf-8";
String mime = fetchRes.getMimetype();
WebResourceResponse res = new WebResourceResponse(mime, charset, new ByteArrayInputStream(fetchRes.getResult()));
return res;
}
return null;
}
Are you using jquery-mobile by any chance? This sounds very similar to: How can I use relative urls in ajax requests within trigger.io apps on Android 4.4 (kitkat)?
My native app includes a WebView, and the WebView loads a web page off web. For example, the html is loaded from
http://dongshengcn.com/test.html
It seems any page loaded from web (instead of local) can not load any file from local device.
My question is:
Is it possible for a http://dongsheng.com/test.html loaded to a webview (as part of native app) to access file on local device?
Here are a couple of things to try:
To use local files you need to place them in your project's assets folder and invoke them using URLs such as file:///android_asset/. For example, if you add mypage.html in your assets folder, then you can invoke it in the webview with file:///android_asset/mypage.html.
Check to make sure that you have the appropriate webview permissions in your Manifest. For the webview to work correctly, you need:
<uses-permission android:name="android.permission.INTERNET" />
Take a look at the following app on Github, which as a bonus also fixes a couple of bugs with the webview in Honeycomb and ICS. It is a full example on how to use the webview with local files:
https://github.com/bricolsoftconsulting/WebViewIssue17535FixDemo
EDIT: Addendum after question clarification:
Yes, it is possible to load a local page from the web, but you must use a trick to bypass the browser's security measures.
Replace the file://android_asset/ portion of the URLs with a custom scheme (e.g. file///android_asset/mypage.html becomes myscheme:///mypage.html), and place these custom scheme URLs in your page. Implement WebViewClient's shouldOverrideUrlLoading, check if the URL begins with the custom scheme and if so redirect to the local page using webview.loadUrl.
mWebView.setWebViewClient(new WebViewClient()
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (url != null && url.startsWith("myscheme://"))
{
String newUrl = url.replace("myscheme://", "file://android_asset/");
mWebView.loadUrl(newUrl);
return true;
}
return false;
}
}
I have a Flash file played in an Android application and interacting with it.
The Android version of this application is 2.3 .
The Flash file is embedded in an Android's WebView and interacting with the application through the: shouldInterceptRequest method of the: WebViewClient:
WebView web_Player;
web_Player.setWebViewClient(new WebViewClient() {
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
//CODE CODE CODE
}
}
The problem:
I need this code to support Android 2.2, which doesn't know the shouldInterceptRequest method.
How can I overcome this issue? In what other way can the Flash file communicate with the application in Android 2.2?
I've ended up using:
public void onLoadResource(WebView view, String url){}
Works perfectly.