Android webapp Ajax exception `INVALID_STATE_ERR: DOM Exception 11` - android

This is my first post on stack overflow, so I'll try to respect conventions and be as clear as possible.
Introduction :
For this project I'm trying to doing a web app with a local web server. My project is divide in two parts :
Local web server which transmit request to a real web server (it is a solution to resolve the Same origin policy)
A android web app which is the view. It's where the problem occurred.
When I'm trying to communicate with the server, using ajax request, the error INVALID_STATE_ERR: DOM Exception 11 occurred. However when I'm doing it on a firefox (with Apache), I haven't this problem.
Local web server :
The web server only stock or transmit data between web app and web server.
Webapp :
Initialization
In my android activity I'm starting my web app like that :
webview = new WebView(this);
MyJavaScriptInterface myJavaScriptInterface = new MyJavaScriptInterface(this);
webview.addJavascriptInterface(myJavaScriptInterface, "AndroidFunction");
// set settings
webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.getSettings().setAppCacheEnabled(false);
webview.setHorizontalScrollBarEnabled(false);
webview.setVerticalScrollBarEnabled(false);
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) // 16
{
// yourwebview, i use phonegap here
webview.getSettings().setAllowUniversalAccessFromFileURLs(true);
webview.getSettings().setAllowFileAccessFromFileURLs(true);
}
// start
uri = new URI("http://127.0.0.1:"+LocalServer.RECORDING_PORT+"/index.html");
webview.loadUrl(uri.toString());
Ajax
To save the data in my webapp I'm doing a basic XMLHttpRequest (also tried with JQuery but no message came out)
function saveObject(in_strAction, in_oData, fctCallback)
{
var l_strURL = 'http://127.0.0.1:8888/api/' + in_strAction;
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
try // line 46
{
console.log ("xmlhttp.readyState="+xmlhttp.readyState+" && xmlhttp.status="+xmlhttp.status);
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
fctCallback(xmlhttp.responseText);
}
}
}
xmlhttp.open("POST",l_strURL,true);
xmlhttp.send();
}
Responses
Answers received by the web app are json and headers are create by the web server.

Problem solved
The exception INVALID_STATE_ERR: DOM Exception 11 is up while reading an invalid status :
function saveObject(in_strAction, in_oData, fctCallback)
{
var l_strURL = 'http://127.0.0.1:8888/api/' + in_strAction;
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
try
{
// Don't read status here (on state 1 exception will be up)
console.log ("xmlhttp.readyState="+xmlhttp.readyState);
if (xmlhttp.readyState==4)
{
// Status can be read here.
console.log ("xmlhttp.status="+xmlhttp.status);
if (xmlhttp.status==200)
{
fctCallback(xmlhttp.responseText);
}
}
}
}
xmlhttp.open("POST",l_strURL,true);
xmlhttp.send();
}

Related

Websockets in WebViews failing to connect, returning code 1006

I have created a simple websocket in an HTML page that works great and connects fine in all of the web browsers. However, when I load it in a web view like in an Android App it fails to connect and returns the code 1006. It is trying to connect to a different URL/endpoint so I am thinking this might be a CORS issue. I am building for a minimum target of API 23.
<!DOCTYPE html>
<html>
<body>
<h1>Socket Connect</h1>
<div id="container"></div>
</body>
<script>
const div = document.getElementById('container');
try {
console.log('connect');
var ws = new WebSocket('wss://anotherserver.com:3000');
ws.binaryType = 'arraybuffer';
}
catch (err) {
}
ws.onerror = function (error) {
// error is always blank
console.log('error');
};
ws.onopen = function () {
div.textContent = 'Opened';
console.log('opened');
};
ws.onclose = function (error) {
// always = 1006
div.textContent = error.code;
console.log(error.code);
};
</script>
</html>
I have read a few other posts about setting some options in my code and I have done that. See here
myWebView.getSettings().setAppCacheEnabled(true);
myWebView.getSettings().setDatabaseEnabled(true);
myWebView.getSettings().setDomStorageEnabled(true);
myWebView.getSettings().setCacheMode(currentCacheMode); /* use cache if not expired */
myWebView.getSettings().setJavaScriptEnabled(true);
I have set cleartext in my manifest as well
It ended up being a CORS issue.

Android WebView "No 'Access-Control-Allow-Origin' header is present on the requested resource"

I'm trying to load a test web page (in my server). Page is:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<iframe width="420" height="315" src="http://www.youtube.com/embed/XGSy3_Czz8k?autoplay=1"/>
</body>
</html>
But webView is not loading page. Not even onProgressChanged called after %40-50
Also, this problem occurs all sites that loads js script from url. Including youtube, fb etc.
WebConsole: XMLHttpRequest cannot load https://googleads.g.doubleclick.net/pagead/id. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.youtube.com' is therefore not allowed access.
Here my settings
FrameLayout contentFrame = (FrameLayout) findViewById(R.id.ContentFrame);
WebView mWebView = new WebView(this);
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.setWebViewClient(new WebViewClient());
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setAllowUniversalAccessFromFileURLs(true);
mWebView.getSettings().setAllowFileAccessFromFileURLs(true);
mWebView.loadUrl("http://ozgur.dk/browser.html");
contentFrame.removeAllViews();
contentFrame.addView(mWebView);
Layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="#+id/ContentFrame"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
You can solve this by enabling a WebSetting called setAllowUniversalAccessFromFileURLs
This is happening on the Javascript layer.
You can read up about it here : CORS
Are you sure you are not pausing timers in somewhere? Because this happens when you call mWebView.pauseTimers() when page loading.
You're trying to do a cross-domain request, which is impossible since it's on a different domain than your page is on.
There is however a workaround that.
Using CORS - tutorial by Monsur Hossain
An example using CORS (By Monsur Hossain):
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Check if the XMLHttpRequest object has a "withCredentials" property.
// "withCredentials" only exists on XMLHTTPRequest2 objects.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// Otherwise, check if XDomainRequest.
// XDomainRequest only exists in IE, and is IE's way of making CORS requests.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// Otherwise, CORS is not supported by the browser.
xhr = null;
}
return xhr;
}
var xhr = createCORSRequest('GET', url);
if (!xhr) {
throw new Error('CORS not supported');
}
As a side note, if you want to run JavaScript on Android:
Execute JavaScript in Android without WebView - tutorial by Wesley Lin
An example using Rhino (by Wesley Lin):
Object[] params = new Object[] { "javaScriptParam" };
// Every Rhino VM begins with the enter()
// This Context is not Android's Context
Context rhino = Context.enter();
// Turn off optimization to make Rhino Android compatible
rhino.setOptimizationLevel(-1);
try {
Scriptable scope = rhino.initStandardObjects();
// Note the forth argument is 1, which means the JavaScript source has
// been compressed to only one line using something like YUI
rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);
// Get the functionName defined in JavaScriptCode
Object obj = scope.get(functionNameInJavaScriptCode, scope);
if (obj instanceof Function) {
Function jsFunction = (Function) obj;
// Call the function with params
Object jsResult = jsFunction.call(rhino, scope, scope, params);
// Parse the jsResult object to a String
String result = Context.toString(jsResult);
}
} finally {
Context.exit();
}
Starting with Android 9 (API level 28), cleartext support is disabled by default.
Better install security certificate on your server.
still
To circumvent add following line in Manifest
<application
...
android:label="#string/app_name"
android:usesCleartextTraffic="true"
...
viola...

error of shouldInterceptRequest in *.apk ( Ionic with asp.net mvc OAuth )

I just builded an app by ionic-framework. The server side is:
bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity
All function works fine in the PC chrome browser, authorization pass and request all get correct response.
Request success screen
but once we builded the html5 and angularjs files into apk, function fails.
ionic build android
ionic run android
Got the Error screen by chrome inspect plugin.
There a similar question here. I also tried that way but also can't work.
Client-Via:shouldInterceptRequest
In index.html file there a cross domain js reference also failed.
I find this might relate to shouldInterceptRequest method in SystemWEbViewClient.java
I common few no use code and just direct response the result, finally the js reference successed.
but the auth request still failed
and I am not sure whether this is a best way to solve the problem.
I just comment the code below which in shouldInterceptRequest method, then it all works.
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
// Check the against the whitelist and lock out access to the WebView directory
// Changing this will cause problems for your application
// *********************** below four lines of code commented.-----
// if (!parentEngine.pluginManager.shouldAllowRequest(url)) {
// LOG.w(TAG, "URL blocked by whitelist: " + url);
// Results in a 404.
// return new WebResourceResponse("text/plain", "UTF-8", null);
// }
CordovaResourceApi resourceApi = parentEngine.resourceApi;
Uri origUri = Uri.parse(url);
// Allow plugins to intercept WebView requests.
Uri remappedUri = resourceApi.remapUri(origUri);
if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri) || needsKitKatContentUrlFix(origUri)) {
CordovaResourceApi.OpenForReadResult result = resourceApi.openForRead(remappedUri, true);
return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
}
// If we don't need to special-case the request, let the browser load it.
return null;
} catch (IOException e) {
if (!(e instanceof FileNotFoundException)) {
LOG.e(TAG, "Error occurred while loading a file (returning a 404).", e);
}
// Results in a 404.
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}

Android- Sharing local storage on multiple WebViews/Windows

I'm developping a mobile application, which should connect to a web server. The application is written with jQM and simply imported in an android web view. I tried to solve this problem using the jStorage plugin, but it seems that it's impossible to share the local storage between the different pages. So I tried to implement this, but it does not work and continues sending null.
Here are my code samples:
Javascript:
function getToken(authCode) {
var jsonUrl = mainUrl + "/auth/authorizeToken?grant_type=authorization_code&client_id=bc89fb879a64eb8e422b94d5c39&client_secret=b5c2974b78f7f3f7aee2bed182&redirect_uri=redirection&code="+authCode;
$.ajax({
url: jsonUrl,
type: "GET",
dataType: "jsonp",
success: function(data) {
localStorage.setItem( "access_token", data.access_token);
localStorage.setItem( "refresh_token", data.refresh_token);
localStorage.setItem( "logged", "true");
}
});
}
function valTokens() {
access_token = localStorage.getItem("access_token");
refresh_token = localStorage.getItem("refresh_token");
}
After that the values are set to null. The .java files are the same as in the sample from the link given.

Jsoup select() return nothing in Android application

I'm making an Android app for my board community. The board provider gives me RSS feeds from general categories but don't generate feeds from topics. So I retreive topics URLs from these feeds and want to parse HTML with Jsoup and give it to a WebView.
It works nice except with the select() function which returns nothing.
The "HTML RETREIVED" log gives me : <html><head><title>The topic title</title></head><body></body></html>
h1 tags are in the code on test purpose : it displays well on WebView and the title of the parsed webpage too.
I also putted the log line right after the select() line. It returns nothing too.
I've tried in a pure Java project to parse with Jsoup only and it goes well.
So I assumed something's wrong with Android.
PS : Internet permission is active in the manifest.
Did I miss something ?
Here is the code :
String html;
Bundle param = this.getIntent().getExtras();
String url = param.getString("url");
try {
Document doc = Jsoup.connect(url).get();
doc.select(".topic .clear").remove();
String title = doc.title().toString();
html = doc.select(".username strong, .entry-content").toString();
html = "<html><head><title>"+title+"</title></head><body><h1>"+title+"</h1>"+html+"</body></html>";
WebView webview = new WebView(this);
getWindow().requestFeature(Window.FEATURE_PROGRESS);
setContentView(webview);
webview.getSettings().setJavaScriptEnabled(true);
final Activity activity = this;
webview.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
activity.setProgress(progress * 1000);
Log.d("LOADING",""+ progress);
}
});
webview.loadData(html, "text/html", "UTF-8");
//webview.loadUrl(url);
Log.i("HTML RETREIVED", ""+html);
} catch (IOException e) {
Log.e("ERROR", "Error while generate topic");
}
Ok I've found out something interesting.
The class I wanted to select was not here because I'm getting the mobile version of the webpage. It appears Android App use a mobile user-agent, which is quite normal but not said anywhere.
Anyway I know what thinking about now.

Categories

Resources