Problem:
- For an Android WebView, I need an html doc downloaded from a CDN.
- I need to periodically re-download the document to see if it's been updated.
- I want the WebView to load this document, but only load a new version if it is different from its current version to preserve page variables (I have no influence on the document and cannot change the way it runs).
My solution was to natively load the document using a HttpURLConnection and use webView.loadDataWithBaseURL(...). This way I can diff the document versions and only call this method when there's a new document. Also, this document can then fetch additional resources using the baseUrl.
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient(){ /*...*/ });
webView.setWebViewClient(new WebViewClient(){ /*...*/ });
String html = getHtmlDoc("http://somecdn.com/doc.html");
webView.loadDataWithBaseURL("http://somecdn.com/", html, "text/html", "utf-8", null);
The unexpected behavior:
D/Console(xxxx): onPageStarted:http://somecdn.com/doc.html
D/Console(xxxx): onLoadResource:http://somecdn.com/script.js
D/Console(xxxx): onPageFinished:http://somecdn.com/doc.html
But when I call:
webView.loadUrl("javascript:console.log(typeof some_object)");
Where some_object is defined in script.js, the following is printed:
D/Console(xxxx): undefined
There are no errors being reported by WebViewClient.onReceivedError(...). What am I missing? Is there a better means of loading the doc.html only if there's a new version? I don't have any access to the CDN outside of downloading content. I am currently testing on Android 4.1.1 but will need to support FROYO-KITKAT+
EDIT:
Solution:
Per marcin.kosiba's recommendation, I'm going to use a HEAD Request with If-Modified-Since
specified:
SimpleDateFormat ifModifiedFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
ifModifiedFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
final HttpURLConnection conn = (HttpURLConnection)(new URL("http://somecdn.com/doc.html")).openConnection();
conn.setRequestMethod("HEAD");
conn.setRequestProperty("If-Modified-Since", ifModifiedFormat.format(new Date(/* last fetched date */)));
conn.setRequestProperty("Accept-Encoding", "*");
conn.connect();
if(conn.getResponseCode() == 200) {
webView.reload();
}
There is a bug with HEAD requests in Android where an EOFException
is thrown, adding conn.setRequestProperty("Accept-Encoding", "*");
or conn.setRequestProperty("Accept-Encoding", "");
resolves this issue.