Re: GWT WebApp and iOS 6 Safari

1,191 views
Skip to first unread message

Manuel Carrasco Moñino

unread,
Oct 2, 2012, 10:47:58 AM10/2/12
to google-we...@googlegroups.com
IOS6 is caching POST although HTML spec says not to cache it. 

I opened an issue in gwt sent a patch a couple of days ago, in the issue you can find some workarounds apart from patch gwt.


- Manolo

On Mon, Oct 1, 2012 at 7:59 PM, Enrico <enrico.be...@gmail.com> wrote:
I'm experimenting a problem accessing with iOS 6 Mobile Safari directly to an history mapped place of my GWT MVP Web Application.

Example URL is 127.0.0.1/webcontext/#register:email!code
where 'register' is the PlaceTokenizer prefix of RegisterPlace that is included in the AppPlaceHistoryMapper.

Accessing to that url by iOS 6 Mobile Safari results in a randomic behaviour: the browser simply load the application main page, without jumping to the correct view. After many retry and reloads, sometimes the right view is displayed correctly.

I'm aware of iOS 6 Mobile Safari AJAX related bugs, but this seems not to be related to any of them: the activity related to RegisterPlace is not placing any call to the server at start, just build and serve a registration form.

This was working without problems on iOS 5 Safari and still work good on Android Browser as well as all desktop based browsers (Firefox, Safari, Chrome).
Is there anyone else facing the same problem?

Thanks




--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/97xukYK1uwAJ.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Enrico

unread,
Oct 2, 2012, 11:06:42 AM10/2/12
to google-we...@googlegroups.com
Thanks Manolo,

I'm aware of iOS6 POST caching problem, but I don't think this behaviour is depending on that Safari bug.

This is the server access log I have when I open the URL with Firefox (where all is still working fine):

192.168.0.7 - - [02/Oct/2012:16:55:14 +0200] "GET /project/ HTTP/1.1" 200 4645
192.168.0.7 - - [02/Oct/2012:16:55:14 +0200] "GET /project/module/module.nocache.js HTTP/1.1" 200 8854
192.168.0.7 - - [02/Oct/2012:16:55:14 +0200] "GET /project/img/logo.png HTTP/1.1" 200 35447
192.168.0.7 - - [02/Oct/2012:16:55:14 +0200] "GET /project/module/gwt/chrome/chrome.css HTTP/1.1" 200 27141
192.168.0.7 - - [02/Oct/2012:16:55:14 +0200] "GET /project/module/37E7172BB090A1A4FE482E23A911163C.cache.js HTTP/1.1" 200 676628
192.168.0.7 - - [02/Oct/2012:16:55:14 +0200] "GET /project/img/main.png HTTP/1.1" 200 28327
192.168.0.7 - - [02/Oct/2012:16:55:14 +0200] "GET /project/module/gwt/chrome/images/corner.png HTTP/1.1" 200 1181
192.168.0.7 - - [02/Oct/2012:16:55:15 +0200] "GET /project/module/gwt/chrome/images/hborder.png HTTP/1.1" 200 1591
192.168.0.7 - - [02/Oct/2012:16:55:15 +0200] "GET /project/module/gwt/chrome/images/vborder.png HTTP/1.1" 200 188

As you see no POSTs are involved in loading the history mapped place related view.

Enrico

Manuel Carrasco Moñino

unread,
Oct 2, 2012, 11:43:19 AM10/2/12
to google-we...@googlegroups.com
I think your app is crashing somewhere. 
Do you have enabled logging and configured uncauchExceptionHandler ?
Take a look to the debug console in ios, or try sending some logging to the console or to the server.



--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

Enrico

unread,
Oct 3, 2012, 9:27:15 AM10/3/12
to google-we...@googlegroups.com
Hi Manolo,
yes the app is crashing and I finally found where it happen.
As I wrote in previous messages, this happen only when using iOS 6 Safari: I tested again with iOS 5 Safari and it works good.

The problem looks really strange:

Accessing to http://127.0.0.1/webcontext/#register:email!code result in Safari to download the GWT App and start onModuleLoad of my EntryPoint.
After that, PlaceHistoryHandler.handleCurrentHistory() raise an exception.
Following the code flow I found that the originating code line that raise the exception is in my RegisterPlace.Tokenizer (whose prefix is "register").

Here is my RegisterPlace class: the exception is raised where the tokenizer try to instanciate the RegisterPlace with the perfectly retrieved tokens.
Exception looks to be a ClassCastException, but I really don't understand why it's raised and why only on iOS 6 Safari.

package com.module.client.place;

import java.util.logging.Logger;

import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceTokenizer;
import com.google.gwt.place.shared.Prefix;

public class RegisterPlace extends Place {

        private final static Logger logger = Logger.getLogger(RegisterPlace.class.getName());

        private static final String SEPARATOR="!";
        
        private String email;
        private String code;

        public RegisterPlace(String email, String code) {
                this.email = email;
                this.code = code;
        }

        public String getEmail() {
                return email;
        }

        public String getCode() {
                return code;
        }

    @Override
    public boolean equals(Object obj) {
        
        if (this == obj ) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (    obj instanceof RegisterPlace && 
                        ((RegisterPlace)obj).getEmail() != null &&
                        ((RegisterPlace)obj).getCode() != null && 
                        ((RegisterPlace)obj).getEmail().equals(this.getEmail()) &&
                        ((RegisterPlace)obj).getCode().equals(this.getCode()) ) {
                return true;
        }
        return false;
    }
    


        @Override
        public String toString() {
                return "RegisterPlace [email=" + email + ", code=" + code + "]";
        }


        @Prefix("register")
        public static class Tokenizer implements PlaceTokenizer<RegisterPlace> {

                @Override
                public String getToken(RegisterPlace place) {
                        return place.getEmail() + SEPARATOR + place.getCode();
                }

                @Override
                public RegisterPlace getPlace(String token) {
                        String bits[] = token.split(SEPARATOR);
                        if (bits.length == 2) {
return new RegisterPlace(bits[0], bits[1]); } else { return new RegisterPlace(null,null); } } } }




Jens

unread,
Oct 3, 2012, 11:04:51 AM10/3/12
to google-we...@googlegroups.com
Hmm couldn't see why there should be a ClassCastException. As a side note, your equals() method is not correct, email/code can be null and two instances containing the same null variables are currently unequal (your if forbids null values). You should also overwrite hashcode() because you have overwritten equals().

Back to your problem: 

Have you tried to compile the app in PRETTY mode and then use Safari's remote debugging to see whats going on in Javascript? Maybe the compiler has generated webkit JS code that does not work as intended in Safari 6 on IOS 6. Do you have the same error when using Safari 6 on Mac OS? Although its not really the same situation but in http://code.google.com/p/google-web-toolkit/issues/detail?id=7392 I had a similar problem with a ClassCastException that should not occur. But would it be the situation as in the issue it should not work on Safari in general I think. But as a wild guess: Does your code work on IOS when you introduce a no-arg constructor to your place that is calling this(null, null) and setter methods you can call in your Tokenizer when using the no-arg constructor to create the place?

-- J.

Enrico

unread,
Oct 3, 2012, 1:21:12 PM10/3/12
to google-we...@googlegroups.com
Hi Jens,
thanks for hints.

I tried to compile the app in DETAILED, PRETTY and OBFUSCATED mode but the problem is still occurring.
With Safari 6 on OSX it's working good.
I already tried to introduce no-arg constructor of RegisterPlace with setters methods and using them in Tokenizer.getPlace() method: still having the exception.

I succeded to replicate the problem using IOS 6 emulator (on IOS 5 emulator it's working good). And the problem seems to occur always when I try to access directly to any history mapped places of my app (so not only with the RegisterPlace).

I enabled IOS 6 Safari web inspector but I don't know why, when I replicate the problem (emulator or iphone), Safari console on my Mac doesn't help at all (it's showing the current session but not showing errors, javascripts debugging and log console). I succeded to debug what was happening (ClassCastException) using simple Window.alert messages.

Alert message on Exception is: "Exception: message=null, toString=java.lang.ClassException"
Did you know a way to gather more info about raised exception?


    @Prefix("register")
    public static class Tokenizer implements PlaceTokenizer<RegisterPlace> {

        @Override
        public String getToken(RegisterPlace place) {
            return place.getEmail() + SEPARATOR + place.getCode();
        }

        @Override
        public RegisterPlace getPlace(String token) {
            Window.alert("register place tokenizer getPlace with token=" + token);

            String bits[] = token.split(SEPARATOR);
            if (bits.length == 2) {
                Window.alert("received tokens: bits[0]=" + bits[0] + ", bits[1]=" + bits[1]);
                String email = bits[0];
                String code = bits[1];
                RegisterPlace place = null;
                try {
                    place = new RegisterPlace();
                } catch (Exception ex) {
                    Window.alert("Exception: message=" + ex.getMessage() + ", toString=" + ex.toString());
                }
                place.setEmail(email);
                place.setCode(code);
                return place;
            } else {
                return new RegisterPlace(null,null);
            }
        }
    }



Enrico

unread,
Oct 4, 2012, 1:57:24 PM10/4/12
to google-we...@googlegroups.com
Ok I finally found what's going on.

Removing the logger definition from RegisterPlace caused the exception not be thrown, but the app was still crashing (after RegisterPlace instantiation and before the related activity start, probably on PlaceController).

Setting logging disabled in my gwt.xml finally solve the issue:
<set-property name="gwt.logging.enabled" value="FALSE" />

Hard to believe but I figure that there is something in logging framework that is interfering with IOS 6 Safari.
I really think this is going to impact all GWT Apps that run on IOS 6 Safari.

Hope it helps.

Jens

unread,
Mar 12, 2013, 5:35:46 AM3/12/13
to google-we...@googlegroups.com

This is a bit old, but in the interest of linking information here's a blog post I found on this issue with another workaround: http://deploythoughts.blogspot.com/2012/11/gwt-webapp-and-ios-6-safari.html. That workaround did the trick for us.

I don't think thats a good workaround. You can still have issues in your app that you probably haven't noticed yet. Last time I looked at GWT JS code ClassCastExceptions are emulated by looking at a map which has stored information if class A can be treated/cast to class B. If this map lookup fails a ClassCastException is thrown. This lookup may fail because you really should not cast the two classes or it can fail because the information is available in the map (=you are allowed to cast) but could not be retrieved because of some other weird iOS Safari issues

One of these weird iOS Safari issues is a JS JIT compiler issue in WebKit's Nitro JS engine described at 


This bug has been reported to WebKit and is already fixed in WebKit nightly. The issue was that a++ and a-- did not work as expected when JIT compilation is active. The stackoverflow article also has a jsfiddle that you can try yourself in Safari. This issue can break everything pretty randomly, so disabling class cast checking in GWT may avoid your current issues but you can be pretty sure that things can still randomly fail in your app. Also note that its not just an iOS Safari issue. It also happens on Mac OS Desktop Safari versions.

The reason why the issue disappears when you connect to Safari via Development console is that JIT compilation is then automatically disabled. 

What we have done is to disable JIT compilation for WebKit based browsers entirely by wrapping every method in a try/catch block which disables JIT compilation for this method (as described in the stackoverflow article). Of course its a performance hit but at least in our app its not noticeable. We also tried rewriting a++ and a-- in the final JS code but that does not solve every issue for us. For more information you can take a look at: https://groups.google.com/forum/?fromgroups=#!topic/google-web-toolkit-contributors/O8JFu_D8Gjc

-- J.




Mike Brock

unread,
Mar 15, 2013, 11:49:03 AM3/15/13
to google-we...@googlegroups.com
We have found that using -XdisableClassCastChecking in GWT 2.5 appears to fix the problem on iOS 6 Safari.
Reply all
Reply to author
Forward
0 new messages