Mobile

Mobile in Minutes with Sinatra

Sinatra is described as a DSL for quickly creating web applications in Ruby with minimal effort. Sinatra makes it extremely easy to host a web application and expose RESTful services. Here we’ll show how this allows you to get mobile applications up and running in minutes with Sinatra.

Quick Introduction to Sinatra

The following ruby file is a valid RESTful service with Sinatra:

require 'sinatra'
require 'json/pure'

get '/hello/:name.json' do
  content_type :json
  {
    "message" => "Hello #{params[:name]}!"
  }.to_json
end

Here we are telling Sinatra to respond to any GET requests to the URI pattern /hello/.json. The inserted name is passed to the method as a parameter through the params hash. We set the returned content_type to JSON to ensure correct handling from the client and our hash is converted to a JSON response using json_pure.

To run this example, save the above code snippet to file named hello.rb. Then install and run your new application with Sinatra:

$ gem install json_pure
$ gem install sinatra
ruby -rubygems hello.rb

Now navigate to the URL http://localhost:4567/Jacob (feel free to use your own name) and you will be presented with:

{"message":"Hello Jacob!"}

Now we can easily consume that service with a jQuery script and host the script with Sinatra:

<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script>
      $.getJSON('/hello/Jacob.json', function(data) {
        alert(data.message);
      });
    </script>
  </head>
  <body>
  </body>
</html>

Here we use jQuery’s getJSON method to retrieve the JSON data from our service. The message from the JSON result is then alerted to the user.

To run the example, create a folder named public in the same directory where you created your hello.rb file. Inside that folder copy the above code snippet into a file named hello.html. Now navigate to the following page in your browser http://localhost:4567/hello.html. You will be alerted with the message “Hello Jacob!”

Creating a Mobile App with Sinatra

That was easy enough, but let’s see how we can apply this to a mobile setting. For this example, let’s create and consume a Sinatra service using jQuery Mobile.

Downloading and Running the Example

The example can be downloaded in its entirety here. To run the example, unzip the downloaded file to a known directory and execute the following commands:

$ cd /unzipped/folder/directory
$ gem install json_pure
$ gem install sinatra
$ ruby -rubygems cameras.rb

Now navigate to the following page in your browser http://localhost:4567/cameras.html. You will see the list of cameras for selection.

Exposing the RESTful Service

Let’s first create our RESTful service which will provide a top 10 list of popular DSLR cameras:

require 'sinatra'
require 'json/pure'

get '/cameras/top10.json' do
  content_type :json
  [
    {
      'id' => 1,
      'title' => 'Canon Rebel T3 DSLR',
      'description' => '...',
      'price' => '499.99
    },
    {
      'id' => 2,
      'title' => 'Canon Rebel EOS DSLR',
      'description' => '...',
      'price' => '349.99'
    }
    # ... ...
  ].to_json
end

In this case we are just constructing a hash that we then return back to the client in the same manner as our previous example. We could also retrieve the list of cameras from a database call, through an aggregation service, etc.

Setting up jQuery Mobile

Now we can consume the service with jQuery Mobile and host our mobile application with Sinatra. There will be two parts to our jQuery Mobile application, the HTML page which performs the setup for jQuery Mobile and a script which consumes our service. Let’s first take a look at the HTML page:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Top 10 Cameras</title>
  <link rel="stylesheet"
    href="//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="cameras.js"></script>
  <script src="//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js">
  </script>
</head>
<body id="page_body">
  <div id="cameraListPage" data-role="page">
    <div data-role="header">
      <h1>Camera List</h1>
    </div>
    <div data-role="content">
      <ul id="cameraList"></ul>
    </div>
  </div>
  <div id="cameraDetailPage" data-role="page">
    <div data-role="header">
      <h1>Camera Detail</h1>
    </div>
    <div id="cameraDetailContent" data-role="content">
    </div>
  </div>
</body>
</html>

The logic above is really just standard jQuery Mobile. We specify two pages, a #cameraListPage and a #cameraDetailPage. The #cameraListPage has an empty <ul> element which we intend to dynamically fill with cameras from our service. Similarly, the details page has no content which will be dynamically determined by selecting a camera from the list.

Rendering the Camera List

Now let’s have a look at the script that populates this logic. You can view the script in its entirety by downloading the example. The render method populates our <ul> by invoking our newly created camera service:

function render() {
  $.getJSON('/cameras/top10.json', function(data) {
    this.cameraData = data;
		
    var cameraListHtml = '';

    $.each(this.cameraData, function(i, camera) {
      cameraListHtml += '<li><a data-index="' + i + 
        '">' + camera.title + '</a></li>';
    });
		
    var $cameraList = $('#cameraList').append(cameraListHtml).listview();

    $cameraList.find('a').click(function() {
      displayCameraDetailPage(this, data);
    });
  });
}

Notice that the service data is retrieved in the same manner as our example above. The key difference is that we dynamically construct list items for each camera with a link that holds the index of the camera it refers to. The list items are then appended to the #cameraList which is rendered as a jQuery Mobile listview.

Showing the Camera Details

The final step is displaying the camera details. The displayCameraDetailPage method is bound to each camera link that was generated. The method is passed the <a> element and the camera data we retrieved from the service.

function displayCameraDetailPage(element, cameraData) {
  var camera = cameraData[$(element).data('index')];

  var detailsHtml = 
    '<div data-role="content"><h2>' + camera.title + '</h2>' + 
    '<p><strong>Price:</strong> ' + camera.price + '</p>' +
    '<p>' + camera.description + '</p>' +
    '</div></div>';
	
  $('#cameraDetailContent').html(detailsHtml);

  $.mobile.changePage('#cameraDetailPage');
}

Here we make use of the jQuery data method to retrieve the index of the camera that was selected. A markup representation of the details of the camera is generated and the #cameraDetailPage content is updated. Once the update is complete, the jQuery Mobile changePage method is used to show the #cameraDetailPage.

Sinatra makes it easy to develop web applications quickly. Try it and your sure to get your next mobile application up and running in minutes.

Re-imagining the App Store in the Cloud

The app formerly known as PhoneGap (now Apache Cordova) started out with a very telling name. PhoneGap/Cordova bridges the gap between a native application’s and a browser’s access to device APIs, thereby allowing you to develop apps in pure HTML5, CSS3, and JavaScript. In addition, you can wrap up and deploy your web-standards-based application to an app store.

But a native OS could provide the same API through the browser. The major drawback to this approach is the loss of revenue generated by the app store through app purchases and in-app purchases. This gives little incentive for OS manufacturers to implement these APIs through the browser. But let’s re-imagine the app store in the cloud for a moment and see how browser support for native APIs could enable this.

Mobile Devices as a Portal

A recent article on Technorati described Google’s new hardware offering which essentially provides a “portal into Google-land.” Chrome essentially becomes the OS for the device and Google Drive becomes the hard-drive. Expanding this idea into the mobile realm is not difficult to imagine, but what value does this provide other than giving us a common place to store documents and photos?

Right now the focus of the cloud in terms of consumers has seemed to revolve around storage. How can I get all of my “stuff” in one place where I can access it from anywhere? Think DropBox, Google Drive, etc. This is an interesting problem, but only the beginning. The next step is taking our Apps and making them accessible from anywhere. After buying a new App for my phone, it would be great if I had immediate access to this same App from my other devices, my tablet, my laptop, etc. and vice versa without the need to download anything on those devices.

App Store in the Cloud

Chrome recently released the ability to login, making your tabs and bookmarks accessible across all devices that are running Chrome. This is a novel concept and could be further applied to the App Store. The starting point in your browser could be a layout of all of the Apps that you have purchased and would look very similar to the native OS representation of your App icons. In addition, one of those Apps could guide you to the App Store which allows you to purchase these Apps. Each App then runs directly in your browser and stores all its data on an external server.

This may appear to have little value initially, but now I could login to my tablet and immediately have access to the same App that I just purchased through its browser. All of my data would be accessible and there is no requirement to find and download anything further. By implementing Apps using web standards (HTML5, CSS3, and JavaScript), the adjustment between devices could all be handled through styling differences. This allows the OS manufacturers to continue to reap revenue from App store purchases, while giving the consumer the advantage of ubiquitous access to their Apps. You could even imagine a pricing model that differs based on which devices you want to enable access from.

The Future is Here… Almost

Firefox OS takes exactly this approach. From the introduction:

The idea is essentially to have all user-accessible software running on the phone be a Web app that uses advanced HTML5 techniques and device APIs to access the phone’s hardware directly via JavaScript. For Web developers, the most important part to understand is that the entire user interface is a Web app, one that is capable of displaying and launching other Web apps. Any modifications you make to the user interface and any applications you create to run on Firefox OS are Web pages, albeit with enhanced access to the mobile device’s hardware and services.

To publish a web application as a Firefox OS App, you simply have to add an app manifest, “a JSON file that describes your app, including its name, its icons, and a human-readable description.” The Marketplace then uses the information provided by the manifest to publish your web application to Firefox OS users.

Firefox OS will likely spurn competition between the OS manufacturers and it appears that Google is already making inroads into the approach with their recent releases. At the moment, the following issues remain although several will likely be solved in the next few years:

  • Native APIs – the Android and iOS browsers just don’t have access to them… yet. Apache Cordova has been a well-recognized stop-gap approach, but as browsers continue to adapt, will no longer be necessary in the future.
  • Performance – Facebook CEO Mark Zuckerberg recently discussed the issues with browser performance on mobile devices after choosing HTML5 as their strategic approach. This will only improve as time goes on and devices become more capable.
  • Connectivity – ubiquitous connectivity just doesn’t exist yet. In the basement of the parking garage, on a remote island… still having access to certain applications is beneficial in these scenarios.
  • Games – as with desktop computing, games require an extensive amount of native API access and have performance requirements that put general Apps to shame. Unless there are breakthroughs in SVG support that make gaming a snap in the browser, games will likely remain native.

Being a believer in web standards and seeing the exciting possibilities of HTML5, Firefox OS truly presents a breath of fresh air. Let’s hope that the other OS manufacturers take notice.

Software Consulting, there are Apps for that!

Since starting a consulting firm, I’m always looking for ways to automate the day to day tasks I find less than appealing. A colleague of mine was interested in the mobile applications that are part of my business application suite. So I’ve compiled a list of the iPhone applications, beyond the basics of course, that I use on a day-to-day basis.

Scanner Pro

Scanner Pro has been my favorite addition to my business application suite. You simply take a photo of a document, receipt, or whatever you choose and the application creates a “scan” representation. “Scans” can be saved as a PDF to your favorite online storage source (e.g. Evernote, Dropbox, Google Docs). Multiple “scans” can be combined into a single PDF which is particularly useful for business expense receipts.

Keeping up with receipts for business expenses (e.g. lunches, coffee, a new monitor) was something I never did well. They would remain in my wallet for weeks and if I didn’t lose them, were barely legible by the time they made it to my files. Now I simply take a picture and toss the receipt. This is also a lifesaver for sending documents when you don’t have a scanner immediately handy (e.g. you sign a contract over coffee and the client wants a copy).

Price: $6.99

Benefits:

  • Scan documents from anywhere
  • Stop carrying around expense receipts
  • If you like it enough, throw away your scanner!

Timesheeter

Timesheeter has been the best time tracking application I have found for my phone. Due to the consistency of my schedule, the ability to set defaults for my time entry generally makes tracking my time as simple as selecting “New Entry”, “Save”. While it doesn’t integrate with my invoicing software, it does provide at a glance views that make it easy to determine time worked for invoicing clients.

My favorite feature of Timesheeter is that it generates a customizable PDF report that can be exported to e-mail, Dropbox, or iTunes. This makes it simple to provide timesheets to clients or simply store a backup of your time tracking.

Price: $2.99

Benefits:

  • Very convenient for tracking time
  • Preferences make it quick for adding entries
  • Easily send timesheets to clients
  • Customizable timesheet reports

QuickBooks Mobile

I use QuickBooks online for invoicing. There are quite a few options available, but QuickBooks has served my needs for 6 years now and I find it hard to justify a change. The QuickBooks iPhone application is somewhat lacking in terms of features, but it provides the ability to create and send invoices which is really what I’m looking for from a mobile perspective.

Once you’ve customized your invoices through the general QuickBooks online browser application, creating invoices through the iPhone application is simple. Once created, they can be immediately e-mailed from your device to the client. This makes it simple to send invoices even if you don’t have immediate access to a wifi hotspot (e.g. standing in line at the DMV).

Price: FREE (but, you must subscribe to QuickBooks online)

Benefits:

  • Send invoices from anywhere
  • Convenient for quickly reviewing outstanding invoices

CardMunch

CardMunch was recommended to me by a colleague and I find it extremely useful. As a LinkedIn application, it connects to your LinkedIn account (if you don’t have a LinkedIn account by now, I suggest you get one).

When someone hands you a business card, rather than simply sticking it in your pocket and letting it run through washing machine, never to be seen again, snap a photo of it with CardMunch. The photo is sent off to LinkedIn employees who, within a brief period of time, transcribe the contact into a LinkedIn profile that you can then choose to connect with. CardMunch helps to ensure you don’t lose that valuable connection.

Price: FREE (but, you must have a LinkedIn account)

Benefits:

  • Avoid losing contacts
  • Finds connections for you
  • Save paper by leeting people keep their cards!

If you are a software consultant, and have any applications that you find useful, please feel free to leave them in the comments.

Keep your layouts DRY with Rails and jQuery Mobile

jQuery Mobile presents a bit of a challenge when trying to keep your layouts DRY. In a general HTML document layout you have the head content, a header, a footer, and the page specific content. In other words, an HTML document is a single “page”. With jQuery Mobile you sometimes have several “pages” in a single HTML document for simplicity and/or performance reasons. Since each “page” often needs to follow the same layout, we need an approach to keep our UI code DRY.

Using the general Rails layout

Rails layouts assume the general HTML document structure. This works fine for an HTML document with a single jQuery Mobile “page”:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <%= stylesheet_link_tag 'jquery-mobile-min', :media => 'screen' %>
    <%= javascript_include_tag 'jquery' %>
    <%= javascript_include_tag 'jquery.mobile.min' %>
  </head>
  <body>
    <div id="<%= page_id %>" data-role="page">
      <div data-role="header" class="main-header">
        <%= image_tag 'solutionsfit-logo.png' %>
      </div>

      <div data-role="header" data-position="inline">
        <%= yield :header %>
      </div>

      <% flash.each do |key, value| %>
        <%= content_tag(:div, value, :class => "flash #{key}") %>
      <% end %>

      <div data-role="content">
        <%= yield %>
      </div>

      <div data-role="footer">
        <h4>© <%= Date.today.year %> solutionsfit</h4>
      </div>
    </div>
  </body>
</html>

This works fine as long as you only have a single jQuery Mobile “page” in your HTML. Unfortunately, this is often not the case. When you want to include multiple jQuery Mobile “pages” in a single HTML document while keeping your layout DRY, you have to be a little more creative.

Using the CaptureHelper for multiple “pages”

Fortunately there is a solution using the CaptureHelper. From the Rails documentation:

CaptureHelper exposes methods to let you extract generated markup which can be used in other parts of a template or layout file.

This allows us to create a partial that describes our general “page” structure, shared/_page.html.erb:

<div id="<%= page_id %>" data-role="page">
  <div data-role="header" class="main-header">
    <%= image_tag 'solutionsfit-logo.png' %>
  </div>

  <div data-role="header" data-position="inline">
    <%= header %>
  </div>

  <% flash.each do |key, value| %>
    <%= content_tag(:div, value, :class => "flash #{key}") %>
  <% end %>

  <div data-role="content">
    <%= content %>
  </div>

  <div data-role="footer">
    <h4>© <%= Date.today.year %> solutionsfit</h4>
  </div>
</div>

As you can see we define variables for header and content. To use the partial we simply use the capture method from the CaptureHelper:

<% @home_header = capture do %>
  <h2>solutionsfit</h2>
<% end %>

<% @home_content = capture do %>
  <p>Welcome to solutionsfit!</p>

  <ul data-role="listview" data-inset="true">
    <li><a href="#postings">Blog Postings</li>
  </ul>
<% end %>

<%= render 'shared/page', :page_id => "home_page", 
  :header => @home_header, :content => @home_content %>

<% @blog_header = capture do %>
  <h2>Blog Postings</h2>
<% end %>

<% @blog_content = capture do %>
  <!-- Logic to list postings here -->
<% end %>

<%= render 'shared/page', :page_id => "postings", 
  :header => @blog_header, :content => @blog_content %>

Refactoring the general layout

Now that we have our partial defined, we can refactor our general layout to include just the basic HTML document structure:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <%= stylesheet_link_tag 'jquery-mobile-min', :media => 'screen' %>
    <%= javascript_include_tag 'jquery' %>
    <%= javascript_include_tag 'jquery.mobile.min' %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

While it’s not as pretty as a general template, it allows us to DRY up our jQuery Mobile views. Another option is using a partial layout, but this has the disadvantage of requiring you to make both your header and content partials themselves. This tradeoff wasn’t worth the additional files in my case.

Mobile Grails at Dallas Techfest

Thanks to all who attended my presentation on Saturday at Dallas Techfest. As promised you can find the slides and source code at the links below:

Presentation Slides
Source Code