5

I'm working on an Android project which relies on the WebView to browse multiple HTML pages stored on the device and submit the inputs toward the webview when it's needed for storing them in a database.

Each page contains controls that are bound with jQuery towards previous / next pages, each page contains inputs of differents types (checkboxes, textfields, etc.).

The last page contains a Submit buttons that uses the JSInterface to save the results inside a SQLite DB.

Another button (in a custom top navigation bar) offers the same system.

Results can be modified by accessing the first page with all the saved inputs, a jQuery system will fill the corresponding inputs.

For more details, I'm using the SDK 19 and compiling against 4.4.2, but I used to work with the SDK 15 and compiling against 4.2.2 where I didn't have the issue.

If someone needs to see what is done, in a simplified system, check this JSBin.


The issue

I'm using SessionStorage to store the inputs between the pages, I used to work with cookies but they became unreliable when there was over 150 key/values pairs.

My problem is that on some devices, the SessionStorage disappear between pages.


Test protocol

1st case - Staying on the first page only

If I stay on the first page only, fill the inputs then send the results, everything's fine. Coming back for modification offers me a fully filled first page.

2nd case - Moving between pages

After filling page 1, I move to page 2 and fill the new inputs then move between pages to see if the inputs are lost on each individual pages. Everything is in place, but if I send the results, only the current page inputs are transmitted.


Android versions test results

  • 3.2 - Works

  • 4.1.2 - Doesn't work

  • 4.2.1 - Doesn't work

  • 4.3 - Doesn't work

  • 4.4.2 - Works


Tested solutions

  • Overriding the WebViewClient's shouldOverrideUrlLoading method to return False - Doesn't work

  • Using LocalStorage instead of SessionStorage didn't change a thing

Insights

Switching from sessionStorage to localStorage did not help.

I found some useful informations about the WebKit versions used by Android :

Android 3.2.1 uses a quite old version but it works (v534.13)

Android versions ranging from 4.0 to 4.3 share the same WebKit engine (v534.30)

Android 4.4 uses a brand new version (v537.36) of it, which explains why it works

Not a single step toward a fix BUT it gives a more precise view of the problem and the device it affects.

Solution

Since the SDK 16, a new security setting has been forced to prevent Javascript code to access content from any origin.

if(Build.VERSION.SDK_INT >= 16) {
    setting.setAllowUniversalAccessFromFileURLs(true);
}

Kudos to ksasq for finding this !

[EDIT 18/02/2014]

After some testing, I pin pointed the problem to the TargetSdkVersion, the BuildTarget does not change anything.

It it's set to 15, the WebStorage works as intended.

If it's set to 16 or higher, the WebStorage is messing up.

Community
  • 1
  • 1
Ethenyl
  • 666
  • 11
  • 20
  • When it doesn't work,do you notice any errors or relevant messages in logcat? Also, can you create a reduced test case on something like jsbin? – ksasq Feb 09 '14 at 15:28
  • I will take some time to review the numerous logs from Logcat and I will also try to create a small test case but it will only show the process for one page. – Ethenyl Feb 10 '14 at 11:00
  • Nothing on the logs, only an **Unknown Chromium Error -6** which seems to be related to file URLs but I'm not missing anything in the pages. – Ethenyl Feb 10 '14 at 11:09
  • @ksasq This should give you a hint of what I'm doing back there http://jsbin.com/qaxoh/5/edit?html,js,output – Ethenyl Feb 10 '14 at 12:04
  • Can you share more details about how you move between pages? The fact that seems to be depending on the target SDK version is very odd though. Are you loading your content from a file:// URL or a remote server? – ksasq Feb 22 '14 at 10:03
  • Another idea for debugging. In your JSBin you are catching exceptions from the storage API but throwing them away - if you log in your exception handler do you see anything useful? You could also see if adding a StorageEvent listener to the page fires unexpectedly to remove or clear items as you navigate between pages. If that is happening, we can try to figure out why. – ksasq Feb 22 '14 at 10:08
  • I'll try this asap, maybe I'll finally get a hint of what's going on. – Ethenyl Feb 24 '14 at 08:12
  • I'm using the file system to load the pages, the page are navigated through a JS binding, with a simple **window.location={URL}** which is a path toward the next or previous page. – Ethenyl Feb 25 '14 at 08:13
  • 1
    Can you try calling WebSettings.setAllowFileAccessFromFileURLs(true) and if that doesn't work, WebSettings.setAllowUniversalAccessFromFileURLs(true) ? They both had a behavior change between ICS and JB, and relate to JS from file:// URLs. – ksasq Feb 25 '14 at 08:48

3 Answers3

4

Between ICS (SDK 15) and JellyBean (SDK 16) there were some changes in the WebView's security model and how it handles javascript from file:// origins. Please try to call

WebSettings.setAllowUniversalAccessFromFileURLs(true)

to acknowledge you are working from file:// URLs and trust the content you are displaying. I imagine that due to the upgrade to Chromium WebView in 4.4 something else changed in the underlying implementation to not require these settings.

ksasq
  • 4,424
  • 2
  • 18
  • 10
  • Thanks a lot, the `WebSettings.setAllowUniversalAccessFromFileURLs(true)` seems to solve the issue, I will do more tests but it might be the solution. – Ethenyl Feb 25 '14 at 11:49
  • Tested against every version between **SDK 15** and **SDK 19** and it works, I just had to add a little security check for the SDK < 16 but otherwise it's all good for me ! No more compatibilty mode ! – Ethenyl Feb 25 '14 at 12:34
2

I'm sorry to hear that webstorage api has an issue on Android, because I will be using this in next few days.

As you have investigated already, Android 4.4 uses a brandnew WebView which is based on the ChromeBrowser where lot of web technology such as webScoket etc other than localStorage api are already supported well.

Having said that, reading your post claims localStorage api has an issue for android4.0-4.2 (which I also aim as target devices), I thought using FileSystem api instead.

http://www.html5rocks.com/en/tutorials/file/filesystem/

However, looking at web, it is so uncertain if this api works well, and finally I found this.

Using local storage on Android webview

https://github.com/didimoo/AndroidLocalStorage

Community
  • 1
  • 1
  • Thanks a lot for the links. I've already seen the bottom ones and we're already implementing the **JSInterface** (we need it to allow communication between the web pages and the native App). – Ethenyl Feb 24 '14 at 08:10
1

My understanding is that session storage exists while the window that created it still open and local storage is persistent between sessions. So does the browser treats the window to remain open while navigating between two local files? This could be open to interpretation. Looking at your code it seems fairly easy to change it to use local storage rather than session storage, so would that be an option?

Chris Gunawardena
  • 6,246
  • 1
  • 29
  • 45
  • Thanks for the comment, I've already tried to use the LocalStorage (I will update the subject) but to no avail... I'm puzzled by this particular problem. As a workaround for our customers we went for the lower TargetedAPI while we're looking for a long term solution. – Ethenyl Feb 21 '14 at 08:59