I recently came across the Rhodes mobile framework which allows "building locally executing, device-optimized native mobile applications" in Ruby. There are a couple of nice things about Rhodes that I really like:
- Once you've written your application it can be built for a variety of mobile applications - iPhone, BlackBerry, Symbian, Android and Windows Mobile.
- Development is done in Ruby with a Rails-like structure - the mobile GUI is written in HTML but designed to retain the look and feel of each mobile devices native interface.
- It provides Rhosync - the back-end server component to help syncronise data between the data source and the local cache on the mobile device.
The Rhomobile wiki is a good place to start, with a fair bit of information on how to get started. The biggest thing that tripped me up was when generating the model in Rhodes - its not really clear, but the source_id parameter must match the id of the source on the rhosync backend.
The only work I really had to do on the Rhosync server was to create a source adapter for the Google Reader items with the following methods:
- query - this logs into Google Reader using the user's credentials (the Rhosync server allows users to register themselves, subscribe to various sources and provide their credentials for each), and retreives the most recent set of items from Google Reader which are stored in the @result instance variable
- sync - the sync method takes the @results from query and simply twists them into the object-value format the Rhosync uses (this is so that it can sync each attribute of each object individually)
- update - this is called by Rhosync when a mobile client has made a change to the data locally that now needs to be propogated to the backend. In my case the only property I cared about was the read state.
The actual Rhodes client was fairly simple to implement - it is mostly just editing HTML in ERb. Although, I did a couple of things to clean up the generic application:
- Edit /config.rb to set the page that the app starts on (by default it will start with a list of all your models).
- In the controller for the start page I added the following to redirect to the login page when required:
if SyncEngine::logged_in > 0
@items = Item.find(:all).sort {|a,b| b.timestamp <=> a.timestamp}
render
else
redirect :controller=>"Settings", :action=>"login"
end
- By default, the login view has the password field as type "text" meaning the password is visible as it is being typed, I changed it to "password".
After all this ... I have decided that I'm going to release the source for this, but I am not going to release it as an application. The reason is that I would need to host the Rhosync server, which is not a problem in itself - after a couple of quick changes it seems to work fine on Heroku (although I think I would need to make some changes to restrict users to just subscribing to apps, not creating them). However, the Rhosync server would need to store the Google Reader password for all of the users which is not something I want to deal with. Perhaps one day Google will deign to add OAuth to Google Reader which would mean that Rhosync just needs to store its OAuth token ... maybe at that time I'll revisit this. For now I'll probably just use this myself and release the source. (Note that Rhomobile have announced a hosted version of Rhosync called Rhohub which would make this a bit easier, but I still don't want to be responsible for people's Google password)
If you're interested the Rhosync and client source is hosted in my GitHub account: http://github.com/nonspeaking
Great stuff. By the way, we have a solution for your stored passwords issue coming in the 1.2 release (some time in July). Hope you consider fielding your great app in that timeframe.
ReplyDeleteCheers,
- A