4

This might seem to be a weird problem, but I am curious to know if it would work. I am working on a POC, and hence have to either prove or disprove that this works or not.

The UI in the Android app would be native (Java + XML layouts) + some other device features access like (Camera/File system etc).

There is a JS library that I have built, that has a few functions which do Ajax post and get requests.

In the app, I have an invisible Webview, where I load a blank HTML (referencing this JS library). And into that WebView, I have injected a JavascripInterface. So, essentially, the UI would be native, and you would never see the Webview. That's just a host which provides access to my JS library to the native code.

Now, on some action on my UI, I call the JS functions on the Webview, which in turn tries to make an ajax call (loadUrl calls ex. javascipt:functionName()). But, those calls fail, without any visible errors.

Note: This same HTML file works, if I load it up on my desktop browser. The AJAX calls succeed.

But, when I initiate Ajax calls through the JavascriptInterface(or webview.loadUrl() calls), they fail, with a reponse status 0.

Things apart from AJAX, like simple function calls, alerts, and callbacks through javascript interface work fine though.

Q: I know this is a weird and an unpractical way to do things. But, would it/should it work?

Update: Even after setting the

setBlockNetworkLoads(false)
, it still doesn't work.

I tried logging the JS calls and errors, and got this error.

Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers.

Any idea how to solve this?

Kumar Bibek
  • 9,016
  • 2
  • 39
  • 68
  • 1. Do you have `android.permission.INTERNET` in the permissions? 2. Paste a link to the page you're requesting or the beginning of the .html file or whatever gets loaded in the `WebView`. 3. Are you using : http://developer.android.com/reference/android/webkit/WebViewClient.html#shouldInterceptRequest%28android.webkit.WebView,%20java.lang.String%29 – g00dy Jul 29 '13 at 09:03
  • might be a threading issue - problems between the UI thread (of the view) and the one used for the ajax request – uriz Jul 29 '13 at 09:23
  • I have the permission. Why would I need to use WebViewClient here? – Kumar Bibek Jul 29 '13 at 09:30
  • @uriz Didn't quite get the problem you have mentioned. Could you please elaborate on that? – Kumar Bibek Jul 29 '13 at 09:31
  • The UI runs on the UI thread. And I'm assuming your callback is on another thread. from the callback thread you would need to explicitly use runOnUiThread to "get back" to the UI. Just wanted to make sure that the issue is indeed with the ajax failing, and not with the presentation of its response. – uriz Jul 29 '13 at 09:37
  • Callback is fine. The Ajax request is always failing. Fail callbacks are working fine. – Kumar Bibek Jul 29 '13 at 09:41
  • This sounds like a workaround for using `AsyncTask`. Why not just use [droidQuery](http://bit.ly/droidquery), and just port your `Ajax` requests to use `AjaxOptions`? – Phil Aug 07 '13 at 20:34

2 Answers2

1

It seems that your are trying to do a cross domain ajax request.

Cross domain requests are not allowed by same origin policy and so the requests will be blocked. If you are loading a local file in webView and then sending ajax requests from it to other domains, this will be the case.

You if that is the case and it is the same origin policy causing you trouble then you might want to look at Cross-origin Resource Sharing (CORS) or JSONP to workaround it.

Given the error you get it seems that your problem is similar to one discussed here: Cross-Domain AJAX doesn't send X-Requested-With header

You might want to change server settings to allow X-Requested-With header.

Also it seems that from API level 16, webSettings added a method setAllowFileAccessFromFileURLs(). Setting this to true for the webView might solve the problem as well.

Community
  • 1
  • 1
P V
  • 46
  • 3
  • Will CORS or JSONP work for POST requests as well? I think I read somewhere that JSONP doesn't work for POST – Kumar Bibek Aug 29 '13 at 03:03
  • Seems like a CORS issue. Currently, I don't have a way to fix the server side to check this though. But, I have debugged the Javascript console on my browser side, and also the server logs. – Kumar Bibek Nov 13 '13 at 11:18
0

I had a similar issue where I was loading a "web-app" locally into a WebView, just doing Ajax remotely. I observed a similar problem where Javascript alerts etc worked fine, but AJAX calls didn't. It turned out that by default the WebView blocks "network loads".

Make sure you do this:

webView.getSettings().setBlockNetworkLoads(false);

That did it for me. Just to clarify, I wasn't using a Javascriptinterface - just loading a web-app as-is using webView.loadDataWithBaseUrl() - the baseUrl parameter passed to this method was where I perform all my AJAX calls (since this method respects the same origin policy)

curioustechizen
  • 10,572
  • 10
  • 61
  • 110
  • The docs say that the default value is false if you have INTERNET permission. I have INTERNET permission. Still the same result. What has to be used as the baseURL here? – Kumar Bibek Jul 31 '13 at 04:56
  • I had INTERNET permission and if IIRC, the value was still `true`. Why don't you print the value of `getBlockNetworkLoads()` in a log statement and find out? Regarding baseUrl - that should be the domain or IP address from where your AJAX requests are served. The relative paths that you use in your AJAX requests are appended to the baseUrl to form the complete URL. Your AJAX calls will be restricted to this domain only - you won't be able to make AJAX calls to other domains (this is in keeping with the same origin policy) – curioustechizen Jul 31 '13 at 05:36
  • For my requests, I do post request, and there is only one URL. There are no url paths. – Kumar Bibek Jul 31 '13 at 06:02
  • Let's take Github API as an example: `POST https://api.github.com/user/repos` will create a new repo. In JS, you would just pass `/user/repos` to XHR's `open` method. That is the path. The `https://api.github.com` portion is the baseUrl. You will only be allowed to make calls to API's at that domain. You won't, for example, be allowed to make calls to StackOverflow API's. – curioustechizen Jul 31 '13 at 06:14
  • Also, did you try logging the value of `getBlockNetworkLoads()` method? I remember getting `true` for that. I had to explicitly set it to `false` to get things working. – curioustechizen Jul 31 '13 at 06:16
  • I haven't logged, but I have set it explicitly to false now. Still, no luck. Updating the answer with more details. – Kumar Bibek Jul 31 '13 at 07:14