I want a HTML/javascript
application, running in a WebView
to make AJAX
calls that are handled by the Java
code.
Idea
Good news everyone: With API level 11, they put in the shouldInterceptRequest
method into the WebViewClient
class. It also fires on requests the application inside the WebView
triggers. You can override it as follows:
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url)
{
if (magicallyMatch(url))
return new WebResourceResponse("application/json", "utf-8", magicallyGetSomeInputStream());
return null;
}
From the Android Reference:
public WebResourceResponse shouldInterceptRequest (WebView view, String url)
Since: API Level 11
Notify the host application of a resource request and allow the application to return the data. If the return value is null, the
WebView
will continue to load the resource as usual. Otherwise, the return response and data will be used. NOTE: This method is called by the network thread so clients should exercise caution when accessing private data.Parameters
view
TheWebView
that is requesting the resource.
url
The raw url of the resource.Returns
A
WebResourceResponse
containing the response information or null if theWebView
should load the resource itself.
Also check WebResourceResponse.
Hope this helps.
You can use the JavascriptInterface to intercept the AJAX calls along with JQuery methods ajaxStart
and ajaxComplete
in following way:
// our JavascriptInterface
public class AjaxHandler {
private static final String TAG = "AjaxHandler";
private final Context context;
public AjaxHandler(Context context) {
this.context = context;
}
public void ajaxBegin() {
Log.w(TAG, "AJAX Begin");
Toast.makeText(context, "AJAX Begin", Toast.LENGTH_SHORT).show();
}
public void ajaxDone() {
Log.w(TAG, "AJAX Done");
Toast.makeText(context, "AJAX Done", Toast.LENGTH_SHORT).show();
}
}
And here is how the AjaxHandler
is used in Activity
:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private WebView webView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// get web view
webView = (WebView) findViewById(R.id.web);
// configure web view
final WebSettings webSettings = webView.getSettings();
webSettings.setBuiltInZoomControls(true);
webSettings.setJavaScriptEnabled(true);
webView.loadUrl("http://foo.com");
// add javascript interface
webView.addJavascriptInterface(new AjaxHandler(this), "ajaxHandler");
// override onPageFinished method of WebViewClient to handle AJAX calls
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.loadUrl("javascript:$(document).ajaxStart(function (event, request, settings) { " +
"ajaxHandler.ajaxBegin(); " + // Event called when an AJAX call begins
"});");
view.loadUrl("javascript:$(document).ajaxComplete(function (event, request, settings) { " +
"ajaxHandler.ajaxDone(); " + // Event called when an AJAX call ends
"});");
});
}
}
The main idea is taken from here and presented with some tweaks.
Although its a little late to submit an answer but hope this helps others as well!
In the end I used the method described in the question anyway;
I intercepted some specific requests like: foo://bar/get/1?callback=foobar
then parsed the URL
and called a javascript callback function with the actual data.
The callback function was defined in the query-part of the URL
, so in the above example that would be: foobar();
Calling that function was easy, just use: yourWebView.loadUrl("javascript:foobar('somedata')");