0

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.

Community
  • 1
  • 1
Chadroid
  • 43
  • 5
  • Where are you checking that there is a new version? – greenapps May 17 '14 at 14:58
  • There's a comment in the html doc that has a publish date; however, @marcin.kosiba proposes a more resilient solution than me checking the publish date. I appreciate the assistance, though; thank you. – Chadroid May 19 '14 at 14:38

1 Answers1

0

Since you need to reload the page in the WebView anyway, instead of downloading the html by yourself you could just ask the server if it had changed and if it has ask the webview to reload it? See this answer https://stackoverflow.com/a/1938603/2977376 for how to use If-Modified-Since to do ask the server if the contents had changed.

Community
  • 1
  • 1
marcin.kosiba
  • 3,221
  • 14
  • 19