Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
324 lines (190 sloc) 23.5 KB
<h1>Building a Crossplatform Native Smartphone App with RhoHub</h1>
<p><a href="">Rhodes</a> allows you to create applications for multiple smartphone platforms. You write your application in Ruby with the UI in HTML and CSS with embedded Ruby code (.erb files) to create dynamic, data-driven elements. RhoHub allows you to quickly create and build applications, reducing the overhead of getting started and as well as streamlining ongoing development effort. The following tutorials will guide you through creating an application using RhoHub.</p>
<h1>Lesson 1: Simple Offline Application</h1>
<p>This lesson will show you how to create an application that does not connect to a server, but does allow users to retrieve and edit local data. You can look at a screencast of <a href="">building an application using RhoHub in one minute</a> for a quick preview of the steps to building this kind of application. The tutorial below shows you how to build a simple product inventory application.</p>
<h2>Create the application</h2>
<p>The name you use for your application is purely for your own reference, it need not appear to your end users, but it will appear in the URLs that you use for development.</p>
<p><img src="" alt="Create Application Screenshot" title="" /></p>
<h2>Create a model</h2>
<p>The application creation wizard lets you create one model which serves as a starting point for your application. Whatever you define in this step will be included with UI and actions to support listing objects, create, show, update and delete. When you enter information about your model, it will be used to generate server and client application code. In this lesson, we'll be making a client-only application. We will use the generated server code in lesson 2, but you could release a finished application with only the client-side code and functionality.</p>
<p>Note: Model attributes are always represented as strings.</p>
<p><img src="" alt="Create New Object Screenshot" title="" /></p>
<p>Note: after you complete the application wizard, you can create additional models for your app under Settings in the QuickLinks sidebar ("Create new object"), but for this app, we'll just use one.</p>
<h2>Application Generation Complete</h2>
<p>In the editor, you'll notice that both client &amp; server code was generated (as noted we'll ignore the server code). Under the client tab, all of your product code is in a single folder in the app directory called "Product."</p>
<h2>Set up the initial screen</h2>
<p>First we will edit the view code to set up the initial screen. By default, when a Rhodes application starts, it will present the UI defined in app/index.erb. You could edit that file to contain links to different screens in your application. However, for this application, we'll just point the start page to the products index page.</p>
<p>Edit "rhoconfig.txt" at root level of the client files and change:</p>
<pre><code>start_path = '/app'
<pre><code>start_path = '/app/Product'
<p>Save your change.</p>
<h2>Build the App</h2>
<p>Select the "Builds" tab. For this example, we'll first build for Android since there is an Android Simulator available for Mac, Windows and Linux. RhoHub also offers builds for BlackBerry and Windows Mobile, but you need Windows to run the simulators and install to a device; however, running the simulators in Windows virtual machines such as VMware or Parallels works fine.</p>
<p><img src="" alt="Builds Screenshot" title="" /></p>
<p>Select "Android" as the "Build Type" and then click "Create Build." (You can leave the version as is. This refers to the version of Rhodes that you want to build with.) It will take a minute or two for your app to build. While it is building, you will see feedback in the list below. You can use this time to download and install the Android SDK and simulator if you haven't already using the handy link on the right side of the table or under "Developer Tools" in the right sidebar.</p>
<p><img src="" alt="Build In Progress Screenshot" title="" /></p>
<p>When it is finished building, you should see "Success" in the status column:</p>
<p><img src="" alt="Build Complete Screenshot" title="" /></p>
<h2>Running the App on Android</h2>
<p>You need to install the Android SDK on your development machine (linked from the Developer Tools section on the right side of the builds section). It'll be the 1.5 SDK, but we'll be building for Android 1.1, which will allow your application to work on all Android devices. After installing the SDK, you'll need to set up and run the simulator before installing your application.</p>
<p>Type the following into your command line:</p>
<pre><code>android create avd --name rhoAndroid11 --target 1 --sdcard 32M --skin HVGA
<p>You will see the following output:</p>
<pre><code>Android 1.1 is a basic Android platform.
Do you wish to create a custom hardware profile [no]
<p>Press return (you don't need a custom hardware profile), and you should see:</p>
<pre><code>Created AVD 'rhoAndroid11' based on Android 1.1
<h3>Running the emulator</h3>
<p>Next you will run the emulator, by typing the following on the command line:</p>
<pre><code>emulator -avd rhoAndroid11
<p>The Android emulator will open in a window. The window will open quickly, but you will need to wait for the emulator to start up. When it does, it should look like this:</p>
<p><img src="" alt="Android Emulator" title="" /></p>
<h3>Install the app</h3>
<p>Download the build from RhoHub and unzip it.</p>
<p>From another terminal window, cd into the directory where you unzipped the build from RhoHub and install the app in the emulator with the Android adb command: 'adb install Rhodes.apk' Sample command line session:</p>
<pre><code>$ cd ~/Downloads/749ef187-0c9b-4e14-be34-50c97a598846
$ ls
Inventory.apk* log.txt*
$ adb install Inventory.apk
2099 KB/s (698543 bytes in 0.324s)
pkg: /data/local/tmp/Inventory.apk
<p>Note: your application will remain installed in the simulator even if you shut it down and launch it again. When you want to uninstall, use the following command:</p>
<pre><code>adb uninstall com.rhomobile.inventory
<h3>Open the app</h3>
<p>To see your app running in the simulator, click on the gray tab at the bottom of the screen:</p>
<p><img src="" alt="Open the App Screenshot" title="" /></p>
<p>The tab will slide up to reveal the built-in and installed applications. Your new app appears with the Rhodes logo by default, you can see it identified with the name "Inventory":</p>
<p><img src="" alt="Applications Tab Screenshot" title="" /></p>
<p>Click on the Inventory application icon and your application will open to the product page:</p>
<p><img src="" alt="Product Page on Android" title="" /></p>
<p>To create a new product, click the new button in the upper-right.</p>
<h3>Using the Inventory application</h3>
<p>Part of the auto-generated application is a page to enter data for new records which will then appear in a list on the main page. To create a new record, click the "new" button on the main page, and then you will see a screen like this:</p>
<p><img src="" alt="New Product Screen" title="" /></p>
<p>Enter information about a product. The following screenshots show data entered for the Acme Hovercraft. When you click create, you will be returned to the main product page and it will show one item in the list:</p>
<p><img src="" alt="Product List Screen" title="" /></p>
<p>By default the first attribute is displayed. In the next section, we'll modify the display. For now, let's take a quick look at the other auto-generated pages. If you click on the "Acme" item, you will see a page that displays all of the attributes for the product:</p>
<p><img src="" alt="Product Detail Screen" title="" /></p>
<p>If you click edit in the top-right, the application will display a page similar to the "new" page which lets you edit or delete the record:</p>
<p><img src="" alt="Product Edit Details Screen" title="" /></p>
<h2>Modify views</h2>
<p>Next we will learn how to modify one of the application screens. In your application, you may have noticed that by default, the attribute displayed in the list is the first one; however, for this example, we want to display the brand and name. We can change this by simply editing HTML.</p>
<p>Go back to RhoHub in your browser, and click on the "Editor" tab. </p>
<p>In app/Product/index.erb, change the list item to display the name along with the brand:</p>
&lt;li&gt;<%=link_to "#{x.brand} #{}", :action => :show, :id => x.object%>&lt;/li&gt;
<p>Save the file.</p>
<h3>Re-load the app</h3>
<p>Now that you have modifed your app on RhoHub. Create another Android build from the builds page, download the zip and extract the files, then cd into that directory, uninstall and install. Here are the specific steps on the command line:</p>
<pre><code>$ cd dd9f9c6e-dc0b-41ad-97e0-6d9e90c0eee2
$ adb uninstall com.rhomobile.inventory
$ adb install Inventory.apk
1626 KB/s (657878 bytes in 0.395s)
pkg: /data/local/tmp/Inventory.apk
<p>After reloading it (and adding another record for the "Ford Flitter", the main page should look like this:</p>
<p><img src="" alt="Modified Product List Screen" title="" /></p>
<p>You can build for other target platforms using RhoHub. To run other device builds, you will need to install the appropriate simulator and/or SDK from the platform vendor.</p>
<h2>iPhone Launcher</h2>
<p>If you are developing on a Mac and have installed the iPhone SDK, you can use the "iPhone Launcher" to easily download and run your app in the iPhone simulator. It also includes a handy reload button that will build your application, if needed, download from RhoHub and install in your local simulator.
<img src="" alt="IPhone New Product Screen" title="" /></p>
<p>Note: if you are running in the iPhone simulator and you want to look at the client log you can find it in a directory named like this (you will have to look for the correct GUID for your build -- it is easiest to find if you just reset the simulator and only test one app at a time):
/Library/Application Support/iPhone Simulator/User/Applications/364FFCAF-C71D-4543-B293-9058E31CFFEE/Documents</p>
<h2>Windows Desktop Client</h2>
<p>[[Testing with the Rhodes Desktop Client]] is an alternate workflow on Windows which reduces the number of steps to testing your application (and starts much faster than the device simulators); however, you will still want to test your final application on the specific target platform.</p>
<h1>Lesson 2: Connecting to Server Data Source</h1>
<p>Next we will connect the application that we built in Lesson 1 to a web service and sync local data with the remote data source.</p>
<p>Typically when developing a connected mobile application, there is significant complexity in having code running locally, code hosted on the server and code running on a device. With RhoHub's hosted IDE and hosted sync, your middle-tier "source adapter" is automatically deployed and you can build for multiple platforms without setting up a complete dev environment locally. In the diagram below you can see how your app, whether running in the simulator on your development machine or installed on a device connects to RhoHub where your source adapter is developed hosted.</p>
<p><img src="" alt="Diagram" title="" /></p>
<p>Note: if you want to, you can develop locally and upload the source code to RhoHub.</p>
<h2>Users and Logins</h2>
<p>It is important to understand how your rhodes client connects and logs in into rhohub (and rhosync). Your rhodes client will login and create a session with rhohub. It will use this session to issue create, read, update or delete instructions from the client to rhohub. Typically, these rhodes to rhohub sessions are good for 1 year, and so you only have to login from the client when you initially install. As needed, rhohub will in turn establish a connection and login to your server data source (aka backend) to create, read, update or delete records using code your write in your source adapter (see below). The user names and passwords for those systems can be the same or totally different, and rhohub may have to re-authenticate itself every time your source adapter runs. In some cases, a backend system may not require any login at all, example an application that reads publicly available RSS feeds. However, you always need to have a login between the rhodes client and rhohub.</p>
<p>There are two approaches available.</p>
<li><p>Create a user in rhohub. This is the simplest way to get started and what follows in the tutorial. Login from your rhodes client using that login and password. A disadvantage of this approach is that you have to create these users ahead of time in rhohub which makes it hard for for arbitrary new users to connect (see next section). Next, you have to subscribe the user you just created to your application because when a client connects with the user name and password you set up, rhohub will check if they have permission to sync with the given application and if not will reject your client's sync request. Lastly, you can add credentials to the subscription you created. Credentials are information like the real backend user name and password and URLs that are saved in the rhohub database and later passed to your source adapter when it executes. Credentials are optional.</p>
<p>Example, you create user a new user john with password mobile in rhohub. This login and password are only used between the rhodes client and rhohub. Subscribe him to your application. Now in johns subscription, you can set his credentials to be john.adams123 with password enterprise because that is what John uses to login to your enterprise system. John can login from his client using john and mobile, but rhohub will save, and your source adapter will have access to john.adams123 and enterprise when it runs and john's device is syncing.</p>
<p>Tip: if you do not care to limit access on a per user basis, you can hard code a shared login and password into your client application. This approach is generally not suitable if you need to display different data for different users however.</p></li>
<li><p>Because we usually don't know ahead of time which users will be accessing an application, and we don't want to keep a 2nd set of user names and passwords in rhohub, we created delegated authentication. Using delegated authentication your backend application is responsible for logins and passwords instead of rhohub. The rest of this tutorial doesn't use delegated authentication as it is a slightly more advanced topic. To read more about delegated authentication, please see</p></li>
<h2>Subscribe User</h2>
<p>In order for your application to connect to the server, you will need to subscribe a user. You can use the same user and credentials that you use to log in to RhoHub; however, it is advisable to create a test user so that you can publish your experimental application for others to use. To create a new user, click on "Dashboard" then select the "Users" tab, click "Add User" and create a user named "tester" with the password "tester" with your email address. </p>
<p>Then to go back to your application, click on "Dashboard" and choose "Inventory" from your list of applications. Then click on the "Settings" tab in RhoHub and scroll down to the Permissions panel at the bottom of the screen.</p>
<p><img src="" alt="Permission Screen" title="" /></p>
<p>Check the "tester" user and leave the other fields blank, then click "Save."</p>
<h2>Creating a Source Adapter: Query</h2>
<p>Go to RhoHub in your browser and click on the "Editor" tab in the Inventory project. Under the "Server" tab, select "product.rb" -- this is a template the was generated by the application creation wizard. </p>
<p><img src="" alt="Source Adapter Screen" title="" /></p>
<p>If this was an application that required us to login to see the products, we would implement login, but for now, just delete the implementation of the login method so it doesn't raise an exception. The example shop on heroku we are using does not require logins. We will modify the code to connect to a mock back end, which you can see at:</p>
<p>Next we will implement the query method to fetch the list of products so that we will be able to display them on the phone.</p>
<p>Query is called every time that the client syncs with the server.
We'll use an XML API to access a list of products. You can see the data we will fetch by looking at it in your browser: </p>
<p>In RhoHub, we're not in the Rails enviroment, so we need to require the libraries we'll be using. We'll use nokogiri for XML parsing and open-uri to access the URL over http. Put the following two lines at the top of product.rb:</p>
<pre><code>require 'nokogiri'
require 'open-uri'
<p>The code to implement the fetching of the data from the web service needs to be in the query method. We'll do the data transformation, right after fetching the data:</p>
<pre><code>def query
@result = {}
xml = nil
open("") do |f|
xml = Nokogiri::XML(
xml.xpath('./products/product').each do |product_node|
id = product_node.xpath("./sku/text()").to_s
attr_hash = {}
product_node.children.each do |attr_node|
attr_hash[] = attr_node.text
@result[id] = attr_hash
<p>The query method reads the XML data from the productshop web service, then iterate through each XML node and transform it into a Rhodes "generic result" which it stores in @result. The format of this generic result is a hash, where each key is a unique string with a value that is a hash of object attributes. For example, if there were two products, we would want to create a result like this:</p>
<pre><code>{"88"=&gt; {"brand"=&gt;"Ruby", "name"=&gt;"Rails", "price"=&gt;"$1000000000.00", "quantity"=&gt;"1", "sku"=&gt;"88"}
"900"=&gt;{"brand"=&gt;"Ford", "name"=&gt;"Hovercraft", "price"=&gt;"$30,000", "quantity"=&gt;"1", "sku"=&gt;"900"}}
<p>Click Save!</p>
<h2>Test your source adapter</h2>
<p>To test your source adapter, click "Show Records" at the top-right of the Editor panel. (Note: this will automatically reload the source adapter into the running sync server). Note that the "Show Records" button acts on the selected source adapter file. ("product.rb" is selected by default, so you don't need to do anything in this case.)</p>
<p>You should see a list of IDs, which you can open to see their contents. The screenshot below shows that the server had 4 records at the time of this writing. The record with id (sku) "100" has been open to reveal its attributes.</p>
<p><img src="" alt="Show Records Screen" title="" /></p>
<p>If your code had an error such that the query method raised an exception, the console will automatically open and display errors. However, if the format is correct and no exceptions were raised, the console will remain closed. If you are not seeing the data you expect, click on the arrow to see the console output. You can add "puts" statements to your code to analyze what is going on. You can also view the log by clicking the "View Logs" button (next to the "Show Records" button).</p>
<h2>Sync Remote Data to the Device</h2>
<p>With the implementation of the source adapter, which is automatically deployed on RhoHub, you can sync data from the device. Note: you don't need to update the application in the simulator since we only modified server code. </p>
<p>To sync, you will need to login using the following steps. (Note: later you can develop your own UI that will present a login screen or automatically log in for anonymous access.)</p>
<p>Clicking "menu" on the device chrome will bring up an array of six choices. Then choose the "more" option:</p>
<p><img src="ttp://" alt="Finding the Sync Button" title="" /></p>
<p>You will next see a menu. Select "Options"</p>
<p><img src="" alt="Options" title="" /></p>
<p>This takes you to the Rhodes Setttings page which was auto-generated and is part of your application. (You can see the source to this page under the Client tab on RhoHub: app/Settings/index.erb)</p>
<p><img src="" alt="Settings Screen" title="" /></p>
<p>Click the "Login" link which will take you to the login page (app/Settings/login.erb)</p>
<p><img src="" alt="Login Screen" title="" /></p>
<p>Now type login "tester" and password "tester" and click login. You will be directed to a wait screen and when login is complete, you will see the product page again. This will show you local data, since the start page is rendered immediately after login, but before sync is complete. If you refresh the screen you will see the remote data.</p>
<p>What happened to your local data? Well, we're not done yet. The local data is trying to sync to the server, but if you recall, we have not yet implemented the create method which will sync the local data to the remote web service.</p>
<h2>Sync Local Data to the Remote Web Service</h2>
<p>Implement a create method. Note that you will need to add the requires at the top of the file.</p>
<pre><code>require 'net/http'
require 'uri'
def create(name_value_list,blob=nil)
name_value_list.each { |nv| attrvals["product["+nv["name"]+"]"]=nv["value"]} # convert name-value list to hash
res = Net::HTTP.post_form(URI.parse(""),attrvals)
<p>You can test it, by clicking "Create Records" at the top of the source adaptor code editor panel. Fill in some attributes (including a unique sku) and click "create."
<img src="" alt="Create Object Screen" title="" /></p>
<p>This will call your source adapter's create method, which in turn calls the web service to save the data remotely. You should see a new record added to the list. Now in your application which is running in your local simulator, go to Options (or Settings) and select "Perform Sync" -- you should see your new record along with the remote data that was there before.</p>