Android WebView Ajax GET inner text file error - android

In my case I am trying to read a text file by Ajax from within a WebView of an Android app.
This is a JS code:
$.ajax({
url: "data.txt",
dataType: 'text',
success: function (data) {
var response = data;
},
error: function (e) {
alert("Response error: " + e.status);
}
});
I tried it in different ways - synchronous and asynchronous, XmlHTTP and $.ajax and always e.status = 0;
As to Android's permissions, here they are:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().getAllowFileAccess();
webView.getSettings().getAllowFileAccessFromFileURLs();
webView.getSettings().getAllowUniversalAccessFromFileURLs();
webView.getSettings().setAllowContentAccess(true);
webView.getSettings().getAllowContentAccess();
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowFileAccessFromFileURLs(true);
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
What kind of problem this is?

Related

Flutter Error - FileSystemException: Creation failed, path = 'storage/emulated/0/myDir' (OS Error: Operation not permitted, errno = 1)

I am try to create a folder in my external android device's external storage (path: storage/emulated/0/myDir). But I keep getting the same error. I have searched everywhere on the internet for a solution and have not found one.
I have the following permissions in my Android Manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
And I have the following code the application tag of my Android Manifest
<application
android:requestLegacyExternalStorage="true"
</application>
Any suggestions of what is going wrong?
I solved this problem with the following solutions:
For android 10/Q, I have added this permission in the androidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
and add this line in application tag:
android:requestLegacyExternalStorage="true"
like this:
<application
...
android:requestLegacyExternalStorage="true">
For android 11/R, add this permission:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
In app-user permission handler I'm checking permissions with the following function:
Future<bool> _hasAcceptedPermissions() async {
if (Platform.isAndroid) {
if (await _requestPermission(Permission.storage) &&
// access media location needed for android 10/Q
await _requestPermission(Permission.accessMediaLocation) &&
// manage external storage needed for android 11/R
await _requestPermission(Permission.manageExternalStorage)) {
return true;
} else {
return false;
}
}
if (Platform.isIOS) {
if (await _requestPermission(Permission.photos)) {
return true;
} else {
return false;
}
} else {
// not android or ios
return false;
}}
Due to recent changes in android OS we have to evolve our appp,
I found the solution---
you have to enter the following in your project
in manifest- uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
in your app- user permission handler
bool permission =
await requestPermissionHelper(Permission.manageExternalStorage);
in All Manifest Files
1. <manifest xmlns:android="http://schemas.android.com/apk/res/android" **xmlns:tools="schemas.android.com/tools**"
2. <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>
Future getStoragePermission() async {
PermissionStatus status = await Permission.storage.request();
//PermissionStatus status1 = await Permission.accessMediaLocation.request();
PermissionStatus status2 = await Permission.manageExternalStorage.request();
print('status $status -> $status2');
if (status.isGranted && status2.isGranted) {
return true;
} else if (status.isPermanentlyDenied || status2.isPermanentlyDenied) {
await openAppSettings();
} else if (status.isDenied) {
print('Permission Denied');
}
}
Figured out the problem, android has updated android 11 to include scoped storage so requires an extra permission from the app user
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />

html5 video tag displays blank screen with only sound

i have created webview and updated android:hardwareAccelerated="true" in order to run embedded video tag but; only sound is running without video
mWebview = findViewById(R.id.webView);
mWebview.getSettings().setJavaScriptEnabled(true);
mChromeClient = new MyChromeClient(this);
mWebview.setWebChromeClient(mChromeClient);
mWebview.getSettings().setLoadWithOverviewMode(true);
mWebview.getSettings().setMediaPlaybackRequiresUserGesture(false);
mWebview.getSettings().setPluginState(WebSettings.PluginState.ON);
mWebview.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
mWebview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
mWebview.getSettings().setDomStorageEnabled(true);
mWebview.getSettings().setAllowFileAccess(true);
mWebview.getSettings().setSavePassword(false);
mWebview.getSettings().setUseWideViewPort(true);
mWebview.getSettings().setBuiltInZoomControls(false);
mWebview.getSettings().setSupportZoom(false);
mWebview.getSettings().setNeedInitialFocus(false);
mWebview.getSettings().setLoadWithOverviewMode(true);
mWebview.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
mWebview.getSettings().setLoadsImagesAutomatically(true);
CookieManager.getInstance().setAcceptCookie(true);
if (Build.VERSION.SDK_INT >= 17) {
mWebview.getSettings().setMediaPlaybackRequiresUserGesture(false);
}
mWebview.setLayerType(1, null);
mWebview.setWebViewClient(new MyWebviewClient());
String myvar = "";
String head = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, user-scalable=yes\" /></head>";
String summary = "<style>table{ height:100%;}td.height{height:100%;}</style><table width=100% height=100%> <tr><td class=\"height\" style=\"text-align: center; vertical-align: middle;\"><video id='my-video' poster=\"\" controls autoplay style=\"width: 300px; height: 250px;vertical-align: middle;\"><source src='http://techslides.com/demos/sample-videos/small.mp4' type='video/mp4' /></video></td></tr></table><script>var myvideo = document.getElementsByTagName('video')[0]; myvideo.play()</script>";
String html = head + "<body style='background-color:#000000;'>" + summary + "</body></html>";
mWebview.loadData(html, "text/html", null);
adb log:
09/16 22:39:14: Launching app
$ adb install-multiple -r -t -p com.example.ad.myapplication F:\new\MyApplication\app\build\outputs\apk\debug\app-debug.apk
Split APKs installed
$ adb shell am start -n "com.example.ad.myapplication/com.example.ad.myapplication.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Connected to process 3426 on device emulator-5554
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
D/MediaResourceGetter: no ethernet/wifi connection detected
W/MediaResourceGetter: non-file URI can't be read due to unsuitable network conditions
E/MediaResourceGetter: Unable to configure metadata extractor
[ 09-16 22:39:18.039 3426: 3478 D/ ]
HostConnection::get() New Host Connection established 0xa0f9b0b0, tid 3478
D/MediaPlayer: Couldn't open file on client side, trying server side
permissions :
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Please advice how to display video with sound not only sound i tried all my known solutions
Thx in advance
"How to display video together with sound, not just sound only..."
Don't use percentages for width/height. Use real numbers.
Test this setup and see if it displays a picture with sound:
String myvar = "";
String head = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, user-scalable=yes\" /></head>";
String summary = "<video id='my-video' controls autoplay><source src='http://techslides.com/demos/sample-videos/small.mp4' width='300' height='250' type='video/mp4' /></video>";
String html = head + "<body style='background-color:#000000;'>" + summary + "</body><script>var myvideo = document.getElementsByTagName('video')[0]; myvideo.play()</script></html>";
mWebview.loadData(html, "text/html", null);
Also note: <script> happens after <body> since the script needs that video element to exist first.

Handling error for individual items in webview

I have a webview which loads an offline HTML . My offline HTML contains
Text
Local Images
Embedded videos
All works fine but when user doesn't have the internet connection the 'text' and 'images' load fine but 'embedded videos' part shows an ugly NO INTERNET CONNECTION error.
My question is how do I handle this error and replace it with my own custom error.
I want to keep showing all the other contents in my html even if there is no internet connection but replace embedded video error message with custom error message.
Anyone knows how to achieve this?
Cheers
My webview code
webView.ClearCache(true);
webView.ClearHistory();
string HTML_DATA = "";
if (File.Exists(localPath))
{
string HTML_LOCAL = File.ReadAllText(localPath);
HTML_DATA = HTML_LOCAL;
}
webView.Settings.JavaScriptEnabled = true;
webView.Settings.LoadWithOverviewMode = true;
webView.Settings.UseWideViewPort = true;
webView.SetWebViewClient(new WebViewClientClass());
webView.LoadDataWithBaseURL("file:///android_asset/", HTML_DATA, "text/html", "UTF-8", null);
Now the results are the following
With internet
Without internet
My question is how do I handle this error and replace it with my own custom error.
You can handle it in WebViewClient like codes below, but it will replace the whole page of WebView with your error page:
public class MyClient:WebViewClient
{
public Context _context;
public MyClient(Context c)
{
_context = c;
}
public override void OnReceivedError(WebView view, IWebResourceRequest request, WebResourceError error)
{
base.OnReceivedError(view, request, error);
var errMsg = error.DescriptionFormatted;
Toast.MakeText(_context, errMsg, ToastLength.Long).Show();
string htmlData = $"<html><body><div align='center'>This is the description for the load fail : {errMsg}</div></body>";
view.LoadUrl("about:blank");
view.LoadDataWithBaseURL(null, htmlData, "text/html", "UTF-8", null);
view.Invalidate();
}
...
Alternatively, you can handle the error in Html, you can define an error window with the same size of your webview, and hide/show it according to the internet states:
<DOCTYPE>
<html>
<head></head>
<body>
<iframe id="mFrame" width="854" height="480" src="https://www.youtube.com/embed/a5GMRrEJaVo" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<div id="errorWindow" width="854" height="480">
This is the div for your custom error view
</div>
<script>
(function(){
"use strict"
var mIframe=document.getElementById("mFrame");
var errorWindow=document.getElementById("errorWindow");
if(navigator.onLine)
{
//internet available
mIframe.hidden=false;
errorWindow.hidden=true;
}else
{
//internet not available
mIframe.hidden=true;
errorWindow.hidden=false;
}
})()
</script>
</body>
Notes: you will have to define following permission to have navigator.onLine work:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Android webview geoposition database failed to open

I have website using javascript geolocation api and want it to open in a webview. I set up these permissions in the manifest file:
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
In my activity, I also set webview settings:
webview.getSettings().setDatabaseEnabled(true);
webview.getSettings().setDomStorageEnabled(true);
webview.getSettings().setGeolocationDatabasePath("/data/data/com.my.app/databases");
webview.getSettings().setGeolocationEnabled(true);
And I also handled javascript geolocation dialog:
webview.setWebChromeClient(new WebChromeClient(){
#Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
}
});
Geolocation itself is working, but I am not able to cache geoposition into the database. It should be doing it by itself into CachedGeoposition.db, but when I start the webview, i get this strange SQLite error:
E/SQLiteLog(22653): (14) cannot open file at line 30174 of [00bb9c9ce4]
E/SQLiteLog(22653): (14) os_unix.c:30174: (2) open(/CachedGeoposition.db) -
D/WebKit (22653): ERROR:
D/WebKit (22653): SQLite database failed to load from /CachedGeoposition.db
D/WebKit (22653): Cause - unable to open database file
D/WebKit (22653):
D/WebKit (22653): external/webkit/Source/WebCore/platform/sql/SQLiteDatabase.cp
p(71) : bool WebCore::SQLiteDatabase::open(const WTF::String&, bool)
When I check existence of CachedGeoposition.db file in File Explorer, it is always there,
and permissions of the db are set to -rw-------.
Did I miss something in settings what could cause database not to open correctly?
I'm new to Android and trying to find solution for 2 days now. Any help would be greatly appreciated. Thank you.
I'll post a solution that worked for me in the hope that it might provide some ideas on where the error might be. It would also help if you could provide details about the device(emulator)/os on which you're testing.
I tested on (with no errors):
(Emulator) Galaxy Nexus (2.3.3) (data/data/package.name/files/CachedGeoposition.db file created)
(Emulator) Galaxy Nexus (3.0) (data/data/package.name/files/CachedGeoposition.db file created)
HTC One S (4.1.1) (data/data/package.name/files/CachedGeoposition.db file created)
Galaxy S3 (4.3) (couldn't see the file since my phone is not rooted and there are some 'run-as' bugs on 4.3)
Nexus 7 (4.4.4) - the webview above KIT KAT has changed a bit and the
file is no longer there, but no error was shown (even when providing a wrong 'databases' folder path)
(Emulator) Galaxy S4 (5.0) (same as on 4.4.4)
AndroidManifest permissions (pretty much the same):
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Web view settings:
WebSettings webSettings = webview.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setGeolocationDatabasePath(getFilesDir().getPath());
webSettings.setGeolocationEnabled(true);
Web chrome client (the same):
webview.setWebChromeClient(new WebChromeClient(){
#Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
}
});
Test html file for getting the geolocation:
<!DOCTYPE html>
<html>
<head>
<script>
var x = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition, showError);
} else {
x.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
var latlon = position.coords.latitude + "," + position.coords.longitude;
document.getElementById("locationHolder").innerHTML = latlon;
}
function showError(error) {
switch(error.code) {
case error.PERMISSION_DENIED:
x.innerHTML = "User denied the request for Geolocation.";
break;
case error.POSITION_UNAVAILABLE:
x.innerHTML = "Location information is unavailable";
break;
case error.TIMEOUT:
x.innerHTML = "The request to get user location timed out.";
break;
case error.UNKNOWN_ERROR:
x.innerHTML = "An unknown error occurred.";
break;
}
}
</script>
</head>
<body>
<p id="demo">Click the button to get your position.</p>
<div id="locationHolder">No location</div>
<button onclick="getLocation()">Get position</button>
</body>
</html>
Also, for a local test, you could created a file containing the html under '/assets/www/index.html' and use the following code to load it into the webview:
try {
String html = readAssetFile("www/index.html");
webview.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null);
} catch (IOException e) {
}
Read asset file method:
private String readAssetFile(String filePath) throws IOException {
StringBuilder buffer = new StringBuilder();
InputStream fileInputStream = getAssets().open(filePath);
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"));
String str;
while ((str=bufferReader.readLine()) != null) {
buffer.append(str);
}
fileInputStream.close();
return buffer.toString();
}
I couldn't reproduce your error without providing a wrong hardcoded path to the 'databases' folder.
The line
D/WebKit (22653): SQLite database failed to load from /CachedGeoposition.db
is interesting
Try setting the appropriate DB path in WebSettings.setDatabasePath as well, it could be that this is used as the root for the geo db path
I know this is an old question but anyone with this issue might find interesting focusing on this function:
mWebView.getSettings().setGeolocationDatabasePath(getFilesDir().getPath());
Geolocation uses databases to persist cached positions and permissions between sessions.
This call sets the location of the database.
Instead of setting a fixed path as parameter you should get it dynamically calling:
getFilesDir().getPath()

GPS doesnt' work (Android web application)

I'm writing web application for mobile phones and I need to use geolocation.
I wrote: (javascript)
function GeoLocationStart(){
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(onSuccess,onError);
}
else{
alert("Functionality not available");
}
}
function onSuccess(position) {
var initialLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
map.setCenter(initialLocation);
var userMarker = new google.maps.Marker({
position: initialLocation,
map: map,
title: "You're here",
icon: face
});
userMarker.setMap(map);
var userhtml = "It's you!";
var UserInfoWindow = new google.maps.InfoWindow({content: userhtml});
google.maps.event.addListener(userMarker, 'click', function() {
UserInfoWindow.open(map, userMarker);
});
};
function onError(error) {
alert('code: ' + error.code + '\n' +
'message: ' + error.message + '\n');
}
It works fine but without GPS.
Though I set in Android manifest file permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
app doesn't start even searching sattelites. (Of course I checked GPS on my phone, it works in other applications)
How to switch GPS on?
Thanks
I found a solution.
After location had found using wireless network, GPS stopped to work because the goal has been achieved - location is defined!
To continue searching position I wrote
var watchID = navigator.geolocation.watchPosition(onSuccess, onError, { frequency: 3000 });
so GPS launched.

Categories

Resources