XCode and Rhodes Upgrading for iOS5

Posted by Jonathan | Posted in Mobile Connection, rhomobile, XCode | Posted on 24-10-2011

0

So I recently updated my iPhone to iOS5.  Its a 3GS … so it was less than exciting to see the end result.  Yea, there are some GUI enhancements, but nothing really worth the trouble its causing now.  What trouble?  When you build an app using XCode, and you want to deploy it to your iPhone for testing purposes, the OS on your phone MUST match the SDK on your system.

So I’m plugging along building and testing 2 apps in the simulator, they’re working great.  I decided I’m to the point where I’d like to test them on my phone, so I fire up XCode (4.1 to something) and got a nice little message that said something like the Operating system on your device does not match the SDK version on this machine.  Click here to revert the device … WHAT?  Heck no.  So that mean I now have to go through the pain of updaing XCode.

This has happened multiple times to me as I’ve progressed up through OS versions on my phone, so this time I figured I’d document it – so next time its not so much guess work, and it might help someone else too.

  • Download XCode : Log into your developer account at http://developer.apple.com click downloads, and download the latest SDK version (4.2 includes iOS5 SDK)
  • Install XCode.  This can take a while, so grab a book or make a sandwich.  DON’T listen to music on iTunes, because that’ll have to be closed during this upgrade.

If you’re developing with Rhodes (http://rhomobile.com) you might possibly have to upgrade this as well.  Since you have your sandwich and a drink, you might as well.

Rhodes Upgrade (optional)

From a terminal prompt

  • sudo gem update rhodes
  • rhodes-setup
  • set-rhodes-sdk (from your application’s root folder)
  • rake clean:iphone

If you get an error like this -

=== CLEAN NATIVE TARGET rhorubylib OF PROJECT rhorubylib WITH CONFIGURATION Distribution ===
Check dependencies
Unsupported compiler 'GCC 4.2' selected for architecture 'i386'

Welcome to the club.

It seems that XCode 4.2 removes the older 4.x simulators.  I found this out when I opened XCode trying to debug the message above, and there was only iPhone Simulator 5.0 listed.  So to fix the error above, you much edit your build.yml file and set these lines -

iphone:
  sdk: iphonesimulator5.0
  iphoneemulator: 5.0
Then you can run your rake commands and it’ll all work including rake run:iphone
XCode usage
To compile it in XCode run this from your project root

rake switch_app

Then from XCode you can choose your simulator and compile away for your simulator.

 

Code it right
theCodeDog
theCodeDog

PABUG (Pt3) – Mobile Connection 1.1

Posted by Jonathan | Posted in Mobile Connection, PABUG, rhomobile | Posted on 22-07-2011

0

<QUICKNOTE>
A coworker here has created a set of web forms, reports and database tables to collect all the conference information including presenters, sessions, tracks, attendance, exhibitors, vendors, etc.  I won’t go into any of that, other than to mention I now have at my disposal all the data I need to make an app, Yea !  Oh yea, and there’s some screenies way down below if you want to check out what I’ve done.  I’ve also made it further than this post as you can see in the screenie below, I’ll continue to work through posts to explain what I’m doing though so you can see the app mature over the next couple months.
</QUICKNOTE>

The Home Screen for the PABUG app

Sungard Higher Education released Mobile Connection 1.1 last week, which caused some great excitement in the developer world.  … ok, in my world it did.  I had obtained a pre-release version and started building out the PABUG app using that.  It was going well, but when the release version came out I decided to essentially start over due to some improved performance and bug fixes.  Enough had changed that it was worth doing.

So where do we start coding.  Firstly – we want to be able to list the conference sessions, tap on a session and view the session details.  Ideally, since this is a multi-day conference, I’d like to alternately be able to select a day and list only that days’ sessions.  To get even more granular – maybe list the tracks as well and list that tracks sessions.

So where to start.  Using Mobile Connection we need to create what is called an mApp … or MApp … or Mapp … not sure the proper spelling, but its pronounced – em-app <G>  Anyway an m-app (I’ll keep using creative ways to type it to keep your interest) – is essentially some functionality you pack up in a single directory in your apps code tree.  In our case, we create a directory called Session.  Rhodes (the underlying framework we’re using) uses the MVC architecture so we need a model (database – more on that soon), View – what the user sees, and the Controller – where all the magic happens.

When you’re at a conference, they typically have wireless throughout.  That said – this particular conference venue has partial wireless and the part that works is crap.  So we can assume you’ll be in sessions that have no connectivity.  Its an older building – so its also quite possible that you will not get a cell signal either (aka No Data).  You’re unplugged.  Not good for a mobile app.  So we need to plan accordingly.

Luckily – we can use the device to create a database for us, store the information we’ll need for later, we’ll call that caching – because its a much cooler term than storing.  So our app now needs a database, a model if you will.  We’ll need to grab the session list and all its data, presenters, tracks, level, etc and store it on the phone then render it to the user depending on what they tap on.

We create a session_controller.rb file and in the index method, check the Session model for data.  If the data count is <1 then we know its the first time the app has run, and we need to load ‘er up.

  def index     
    @sessions = Session.find(:all)
    if @sessions and @sessions.size<1
      sessions_result = fetch('Session Data',@@session_file_name, 'http://apps3.messiah.edu/mobile/pabug/session_load.php')
      insert_sessions  
    end
    @days = Session.find_by_sql("SELECT distinct(session_date) FROM Session ORDER BY session_date")
    render
  end

So we’ll go get the session list.  Hmmm, we’ll need to build a way to generate the session list.  Using PHP on a server here at Messiah, I quickly put together an SQL call to pull the session data I need from the database tables I mentioned above.  I concatenate that data in a format that my app will process when it creates the database on the device.  Below is an example of what that looks like -

"session_id"=>"321","session_title"=>"Testing a really long session title name.","session_date"=>"21-NOV-11","session_time"=>"10:10 AM - 11:10 AM","session_level"=>"Advanced","session_notes"=>"Session Notes","session_desc"=>"Session Description","session_room"=>"Regency","session_track"=>"--","primary_presenter"=>"Dorie Minich","other_presenters"=>""
"session_id"=>"113","session_title"=>"Mobile BOF","session_date"=>"24-NOV-11","session_time"=>"11:20 AM - 12:20 PM","session_level"=>"Beginner","session_notes"=>"","session_desc"=>"","session_room"=>"TBD","session_track"=>"Mobile |  Technical","primary_presenter"=>"Jonathan Wheat","other_presenters"=>""
"session_id"=>"114","session_title"=>"Imaging BOF","session_date"=>"24-NOV-11","session_time"=>"11:20 AM - 12:20 PM","session_level"=>"Beginner","session_notes"=>"","session_desc"=>"","session_room"=>"TBD","session_track"=>"Technical","primary_presenter"=>"Dorie Minich","other_presenters"=>""
"session_id"=>"141","session_title"=>"Mobile Connect : A Starting Point","session_date"=>"25-NOV-11","session_time"=>"1:30 PM - 2:30 PM","session_level"=>"Beginner","session_notes"=>"This is an intro to Mobile Connection and the framework.  Will allow users to get a feel for what you actually need to get started.","session_desc"=>"The Beginner&apos;s Guide to Mobile Connection and what you need to dig in","session_room"=>"TBD","session_track"=>"Mobile |  Technical","primary_presenter"=>"Jonathan Wheat","other_presenters"=>""
"session_id"=>"82","session_title"=>"BDMS Are the possibilities endless?","session_date"=>"24-NOV-11","session_time"=>"3:00 PM - 4:00 PM","session_level"=>"Intermediate","session_notes"=>"","session_desc"=>"Discussion of options available to load documents into imaging.","session_room"=>"Regency","session_track"=>"Technical","primary_presenter"=>"Dorie Minich","other_presenters"=>"Jonathan Wheat "
"session_id"=>"115","session_title"=>"Upgrade Planning","session_date"=>"25-NOV-11","session_time"=>"3:00 PM - 4:00 PM","session_level"=>"Intermediate","session_notes"=>"","session_desc"=>"","session_room"=>"TBD","session_track"=>"Accounts Receivable |  Accounts Receivable |  DBA |  Technical","primary_presenter"=>"Robert Getty","other_presenters"=>"Dorie Minich "

 

Since I now know what fields I’ll have in my device’s database, I need to set up the database in the app.  With Rhodes there are two types of database you can use.  PropertyBag, and Fixed Schema (more on those here).  Anyway, let me say, I’ve chosen Fixed Schema so I can perform real SQL on the table.  PropertyBag has a different type of syntax, and doesn’t allow for a distinct(x) ability, which I’ll need shortly.

With Fixed Schema, I have to specify the structure because, well, its fixed.  I do that in the session.rb file like this -

  property :session_id, :integer
  property :session_title, :string
  property :session_date, :date
  property :session_time, :string
  property :session_level, :string
  property :session_notes, :string
  property :session_desc, :string
  property :session_room, :string
  property :session_track, :string
  property :primary_presenter, :string
  property : other_presenters, :string

That just sets up the fields and types in the Session model.

Back in session_controller.rb I have a method I created called fetch, that pulls that data into the phone and stores the file on the device.  it looks like this -

  def fetch(desc,local_filename,remote_url)
    ## Use to pull down .JSON files for system loading
    if File.exists?(local_filename)
         File.delete(local_filename)
     end
     Rho::AsyncHttp.download_file(
       :url => remote_url,
       :filename => local_filename,
       :headers => {},
       :callback => {},
       :callback_param => "" )
  end

I use this method many times and in different apps I’ve worked on.  Sending it a URL and a temporary filename, the file is downloaded to the phone.  I can then process the file using my insert_session method like this to build my model -

  def insert_sessions
       Alert.show_popup :message=> 'Indexing Session Data',:title => 'One Moment Please'
       sleep 2
       Alert.hide_popup

      #READ FILE AND ASSEMBLE 'data'
         f = File.new(@@session_file_name)     
          f.each_line do |line|
             #take line and convert it into a hash
             h = {}
             line.split(',').each do |substr|
                ary = substr.strip.split('=>')
                h[ary.first.tr('"','')] = ary.last.tr('"','')
             end
             app_info "\n\n\n PROCESSING : " + line + "\n\n\n"

             @params['session'] = h
             @session = Session.new(@params['session'])
             @session.save
         end
    end

That builds a record for each session in the file I’ve pulled down (our model is complete and now loaded with data). Since this can take 3-5 seconds, I pop up an alert message to let the user know what’s going on and that the app didn’t lock up.  Once we have the sessions in a database on the phone, we can do just about anything with them.

I’ll create an array called @days and fill it with the distinct days from the database that sessions occur, and display that to the user so they can choose one day of sessions to look at.

@days = Session.find_by_sql("SELECT distinct(session_date) FROM Session ORDER BY session_date")

The find_by_sql method is NOT available with a Property Bag type database, thus the Fixed Schema decision.

On to the view, and I don’t mean that stupid talk show that bashes men all the time.  Our view (in this case index.erb) is rendered by the index method in our session_controler.rb file.  The overall function of view.erb is to render the data to the screen, this is where your HTML is used, along with some ruby code.  Below is my index.erb file, and you’ll notice there is some default Mobile Connection code still in there as well as necessary JQuery Mobile code.

<div id="session-page" data-role="page">

    <div data-role="header" data-position="fixed" data-theme="f" id='header'>
        <a href="<%= Mshell.show_url %>" data-direction="reverse"><img src="<%= Mshell.path %>/images/icon-back.png"/></a>
        <h1>&nbsp;</h1>
        <img src="<%= Mshell.path %>/images/icon-menu.png">
    </div><!-- /header -->

    <div data-role="content">
        <div><img src="<%= Mshell.path %>/images/icon-menu.png"></div>
        <div>    
            <ul>
                <% if Mshell.is_logged_in? %>
                    <li><a href="<%= url_for({ :controller => :Mshell, :action => :async_logout}) %>" data-transition="pop" data-direction="reverse"><%= Locale::Mshell[:label_logout] %></a></li>
                <% else %>
                    <li><a href="<%= url_for({ :controller => :Mshell, :action => :show_login}) %>" data-transition="pop"><%= Locale::Mshell[:label_login] %></a></li>
                <% end %>
                <li><a href="<%= Mshell.show_url %>" data-direction="reverse"><%= Locale::Mc[:label_home] %></a></li>
            </ul>
            <br/>
        </div>

        <ul data-role="listview">
            <div id='mappTitle'><%= Mshell.current_mapp.title %></div>
            <!-- ul style='margin-left:10px;margin-right:10px;'-->
            <li data-role="list-divider" role="heading">
                Full Session List
            </li>
            <li data-theme="c">
              <div>
                  <div>
                      <a href ="<%= url_for :action => :list_sessions %>">
                        List All Sessions
                    </a>    
                </div>
                <span></span>
              </div>
            </li>
        </ul>
        <br/><br/><br/>
        <ul data-role="listview">    
            <li data-role="list-divider" role="heading">
                Sessions By Day
            </li>
            <% @days.each do |session| %>
            <li data-theme="c">
              <div>
                  <div style='height:24px;'>
                      <% @session_date = session.session_date  %>
                      <a href ="<%= url_for :action => :list_sessions_byday, :query => {:session_date => session.session_date} %>">
                        <%= session.session_date %> <br/>
                    </a>    
                </div>
                <span></span>
              </div>
            </li>
            <% end %>        
        </ul>
    </div><!-- /content -->
</div><!-- /page -->

We’re using an unordered list to create this display.  JQuery Mobile has some fantastic theme-able elements and we’re exploiting them here.

The blue-ish code code is creating a list item with a link to list sessions

<a href ="<%= url_for :action => :list_sessions %>">

This is the Rhodes way of creating internal links to other methods.  Takes a little getting used to, but works great.  This method (list_sessions) will lists ALL of the sessions for the conference alphabetically.  We’ll add a way to filter those quickly using JQuery later.

The green bits of code are where we spin through the @days array, assign each element to an object called session and then we can access each one with dot (.) notation.  For example session.session_date displays 21NOV11 for us (only because I haven’t formatted the date yet). Each day then becomes a link off to our list_sessions_byday method that list all the sessions for one day.

<a href ="<%= url_for :action => :list_sessions_byday, :query => {:session_date => session.session_date} %>">

You’ll notice to pass a parameter in the querystring we’re using :query and setting up key/value pairs.  This equates to ?session_date=21NOV11. Our list_session_byday method pulls out the session_date parameter which we then use to query the Session model (database) to grab the sessions for that particular day

    def list_sessions_byday
      @session_date =  @params['session_date']
      @sessions = Session.find(:all,:conditions => {'session_date' => @session_date},:order => 'session_date')
      render
    end

Then we render the list_sessions_byday.erb view file, where we display all of the sessions for that particular day.  Be aware, the syntax for the find seems a bit goofy, since you’re telling it – find all of the records, and then applying the condition.  You’d think you would leave off the :all portion, and just say find records with this condition.

Without boring you with even more code, the list_sessions_byday.erb file spins through the sessions and lists the session.session_title and some other bits (See screenies below) and creates a link like this for each session -

<a href ="<%= url_for :action => :list_details, :query => {:session_id => session.session_id} %>">

This is passing the session_id off to list_details method

    def list_details
      @session_id = @params['session_id']
      @sessions = Session.find(:all,:conditions => {'session_id' => @session_id})
      render
    end

This again grabs that parameter from the query string, does a quick find against the Session model where session_id = @session_id and calls the view, which like the other views displays the session information, although this time we display everything we have about a session in a nice detail page.

Next up – I’ll either tackle the “By Track” functionality or Exhibitor information.  Only time will tell :)

Till then -keep coding and enjow the screenies below.

 


 

Code it right
theCodeDog
theCodeDog

PABUG (Pt2): From Wireframes to Project Management

Posted by Jonathan | Posted in Mobile Connection, PABUG | Posted on 15-07-2011

0

If you know me, you know I get sidetracked .. a lot.  I’m not A.D.D, I’m just multi-interested and if I talk to a coworker down the hall about something and tell them I’ll do something when I get back to my office, by the time I get back to my office I’m off on something else completely unrelated.  Often times when leaving someone’s office, I’ll have an IM waiting to remind me about what I said I would do.

So what does that have to do with this project ?

I like to collaborate on ideas, bounce things off of people, have them bounce ideas off me, flesh them out, white board ‘em, sketch-in-code, all of that.  But when it comes down to actually coding, much like the situation above, I sometimes can’t remember a feature or action the app should have.  I’ve found this AMAZING project management application called Pivitol Tracker. It is a collaborative, story-based project management system that can easily help you organize your project’s features.  One view that is configurable with separate “silos” for stories including Done, Current, Backlog, Icebox gives you as a developer (or manager) a clean view of the overall project needs and time to completion.  Simple workflows step a story from Backlog (or icebox) through the silos and individual statuses such as not started yet, started, finished, delivered, accepted/rejected.  I currently have 7 projects configured and have one exposed to the public.  Below is a screenie of the main console with one story opened for editing in my Current panel. What is amazingly easy to use is the difficulty level assignment.  You can use the default 1-3 or set up your own difficulty levels.  Each story can be assigned a difficulty level and that helps plan your current story list, so you’re not slammed with 10 level 3 items one week and 10 level 1′s the next.  You can drag items back and forth, attach documents, set up task lists for a story, assign it to someone else.  For a full list of features check out their site – they just released an iPhone and iPad app that gives you access to your projects from a mobile device – which simply ROCKS.

Pivotal Tracker does cost if you want private projects (which is worth it).  Pricing options are very reasonable if you’re a lone developer and want something to help keep you organized. If you want to open your project to the public, its free.

Now that I have some basic tasks in my tracker, I’m ready to start coding. This list will continue to expand as I add new features, I just added a few items in to get me started.  I’ll probably spend an hour or so brainstorming features for the app and add them all into Tracker. 

Code it right
theCodeDog
theCodeDog

Mobile App Adventures

Posted by Jonathan | Posted in Mobile Connection, PABUG, rhomobile | Posted on 12-07-2011

0

I’m currently working on a mobile application for a local user group’s annual conference.  The group is PABUG (Pennsylvania Banner User Group).  Each year we hold a conference with multiple tracks, dozens of sessions, and host between 350-500 attendees over the course of two days, not bad for a small user group :)

Sungard Higher Education has released a Mobile Connection (MC) framework that builds on Rhomobile‘s Rhodes framework.  MC gives you access to a nice GUI (Mshell) and the ability to add new functionality to your app (called mApps).  You can read all about MC and Rhomobile other places in my blog.

My wireframe for the conference app

PABUG Wireframe

Back to the app.  The Conference App was thought up one night at the conference when we talked about the changes to sessions and having to post notices all over.  Thinking it would be great to simply text attendees about changes, it continued to morph into a pretty well thought out app; listing sessions, a schedule builder, exhibit/sponsor information, presenters, social integration etc.

I’ll be posting my progress as I go through this building out new functionality explaining how I did it with Mobile Connection.

 

I started out with a pencil drawing – planning out what we wanted – menu options, making notes, etc.  Then I did some wireframes in my favorite package – Balsamiq.  The purpose of wireframes for me is to get ideas out in a format that simulates what I’m aiming for.  For me, since I’m not doing this for a client, per se, I needed something to run by others to help get my ideas across.  This did it, as did the pencil scribblings I did.

I pulled together a couple others here @ Messiah and we talked about the backend data collection and how it’ll all come together technically.  Dorie created the database schema with all the tables and wrote a set of web screens in Grails to allow us (and others) to enter data.  Bob is going to build out the session evaluation functionality.  This will allow attendees to evaluate a session quickly and easily from within the app itself. No paper forms, no need to have them remember to do it on their computer when they get home, no need for Kiosks every 10 feet (although I think a few scattered around would be a good idea)

Simply the fastest and easiest way to get external data from one place into a mobile app is to use JSON formatted text.  So that’s what we’ll do.  I have a PHP server here that will query the data, and render it in a format the mobile app can consume, parse and render for the user.  This will speed up the screen renderings and make it a simple clean system of delivering content.  The issue becomes then – what happens when you loose your signal.  The Holiday Inn where we have the conference is notorious for bad wireless and terrible cell service, so the app will _have to_ behave if no signal is present.  What does that mean exactly ?  I think that means that I might not have the absolute latest data on my phone, but I can still tick through the data I pulled last time.  Yes, offline functionality.  Meaning the app will have to cache the files it pulls and use those to render the screens if signal is lost.  Sounds like fun.

Stay tuned as this goes from pencil and paper to downloadable app.

Code it right
theCodeDog
theCodeDog