Monday, April 30, 2012

GWT RPC with Phonegap revisited

This post is part of a series of blog post that show the usage of  some mgwt / gwt-phonegap components.

As some of you may know I posted a very popular blog post about a year ago about how to get Phonegap  and GWT RPC working together.

A few weeks ago John Gentillin brought the issue up again on the mgwt user group.

He rightly suggested that this could be fixed by just changing the client and without touching the server at all. So today I decided to revisit the issue and see if I can find a nice way to handle it on the client.

To fix this you need some basic knowledge of how GWT RPC works on the client.
The compiler generates some classes around the RPC interface which do the actual communication.

We need to do two things:
  • set the url for the entry point
  • set the url for the gwt module base

Both parameters are passed with our request and help the server code find the serialization policy. With gwt-phonegap 1.7 I decided to introcude a utility method that handles all those things directly on the client. You just pass in your service, your module url (where you GWT app is deployed) and the relative path to your service.

The code would look like this:

GreetingServiceAsync service = GWT.create(GreetingService.class);
  
PhonegapUtil.prepareService(service, "http://www.yourserver.com/", "greet");


If you want to see how this is implemented take a look here: PhonegapUtilImplDevice.java

There is also an article on RequestFactory & Phonegap. 

7 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi daniel

    i try to use ur solution, but i have some problems on the rpc server part.

    Type '*.ClientContext' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' and did not have a custom field serializer.For security purposes, this type will not be serialized.

    Am i missing something ? My bean has empty constructor, serial ID and implements Serializable.

    ReplyDelete
  3. Hi Yohan,
    lets put discussions on the mgwt user group: https://groups.google.com/group/mgwt (since we can discuss there in any length). Would you be so kind to repost there?

    ReplyDelete
  4. Hi Daniel,

    I use your solution and i have a statusexception 0

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. I am also getting statusexception 0 when I am trying on local server http://127.0.0.1:8888. After the RPC call in the onFailure I am displaying exception message and cause. It is showing exception message as 0 and exception cause as null. Daniel can you please help. Wilkin Dessin, were you able to fix your issue?

    ReplyDelete
  7. You will get StatusCodeException 0 when you are accessing your app's *.html file directly from the filesystem (not from the server; for example through URL file:///C:/AppFolder/war/index.html).
    Check bugs in your browser's dev console. If you have:

    "Uncaught SecurityError: Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match."

    or

    "XMLHttpRequest cannot load http://127.0.0.1:8888/appname/serviceName. Origin file:// is not allowed by Access-Control-Allow-Origin."

    disable browser's web security (only for testing period!) -> run Chrome with flag "--disable-web-security" (first make sure that you don't have any running instances of Chrome). Chrome will display yellow bar saying that it's not safe now.

    It is only a problem with Same Origin Policy (SOP) on desktop browser. WebView in PhoneGap allows this kind of request.

    If you're still getting StatusCodeException 0, check if your services have proper entry points set (ServiceDefTarget.setServiceEntryPoint()).

    I'm using m-gwt without gwt-phonegap, so I'm not using PhonegapUtil.prepareService(), but in the gwt-phonegap source code I can see that the implementation for the browser (PhonegapUtilImplBrowser.java) has empty prepareService() method (contrary to PhonegapUtilImplDevice.java). So the entry point will be wrong for the browser. Set it via ServiceDefTarget.setServiceEntryPoint().

    And on the server side in RemoteServiceServlet override doGetSerializationPolicy() and set there proper moduleBaseURL.

    ReplyDelete