Rhodes

Outline

Overview

Rhodes is a cross-platform mobile framework that is part of the mobile application suite RhoMobile. The RhoMobile suite includes many components aside from Rhodes, including a server-sync product called RhoConnect. RhoConnect is commonly used in conjunction with Rhodes applications to simplify data synchronization between device and server, and it also allows developers to send push notifications with relative ease.

But not all apps have a need for data synchronization, and thus not everyone may want to implement and maintain a RhoConnect application. This is where Urban Airship comes in. The integration between Rhodes and Urban Airship is not nearly as smooth as with RhoConnect, but it is entirely possible for your Rhodes application to leverage push notifications without RhoConnect.

This tutorial will show you how to configure your Rhodes application to receive and process non-RhoConnect push notifications. In this example, these pushes come from Urban Airship and we are developing specifically for Android, although developing for iOS would only require a few simple changes. Our complete project is for demonstration purposes only, called FinslapRhodes.

Registering the device for push (get token)

Once you configure your Rhodes application to handle push notifications, it automatically handles registration with the push notification service, and the push registration id is accessible by calling “System.get_property(‘device_id’)”.

Configure Application to Handle Push Notifications

There are only two steps to configure the application:

  1. Add entries to “build.yml” file. The sender entry should be the Google email account registered to your application.
    android:
      push:
        sender: yourGoogleAccount@gmail.com
    capabilities:
      - push
      - vibrate #if you want to enable vibrate in your push messages
    
  2. Register push callback method in application “initialize” event
    def initialize
      System.set_push_notification "app/YourController/your_push_callback", ""
      super
    end
    

Register Push Registration ID with Urban Airship

Once you have access to your device’s push registration id, you need to register it with Urban Airship (UA). Best practice is to do this every time the application opens in case the device’s push registration id changes for some reason; in our example we do this in the application “initialize” event. This is a complicated process, because this registration is meant to be handled by a .jar file that UA provides. But since our application doesn’t use native Java code, we must do this manually. The steps to register your push registration id with Urban Airship are as follows:

  1. An HTTP POST to UA linking a UUID (which will be your Urban Airship APID) to your Android package name. The Android package name will follow this naming convention – “com.<vendor entry in build.yml>.<name entry in build.yml file>”. You can also see this package name in the “app_info.txt” file that is located next to your application’s .apk file when you build your application for production (“rake device:android:production” from application’s root directory in the command prompt).
    ** This HTTP POST only needs to happen the first time you are registering this UUID with Urban Airship, but it doesn’t seem to hurt to do this every time **
    ** Because Rhodes does not have a gem for UUID generation built-in, our example uses the phone id as the APID. The phone id is a UUID that identifies the device, and it is retrieved by calling “System.get_property(‘phone_id’)”. The APID can be generated by other means as long as it complies with the RFC 4122 standard for UUIDs. **

    Rho::AsyncHttp.post(
        :url => "https://boxoffice.urbanairship.com/firstrun",
        :body => "package=#{package_name}&apid=#{apid}"
    )
    
  2. An HTTP PUT to UA linking the APID to your device’s push registration id.
    payload = { :c2dm_registration_id => registration_id }
    Rho::AsyncHttp.post(
        :url => "https://device-api.urbanairship.com/api/apids/#{apid}",
        :http_command => 'PUT',
        :authentication => {
            :type => :basic,
            :username => appKey,
            :password => appSecret
        },
        :headers => {"content-type" => "application/json"},
        :body => payload.to_json
    )
    

Sending the token to the application server

In our example, the Urban Airship APID is sent to our application server as part of the login procedure. This allows user logins to be associated with a push registration id so that the application can send pushes to all devices that a user is logged into. More detail can be found on this decision in the Application Server section of this site. You can choose how to send the APID in a way that is best for your application as long as your server receives and stores it in some meaningful way.

How to handle a push on the device

If you configured your device correctly, push notifications will be sent to the method you specified in the “System.set_push_notification” call in the application initialize event. From there you have access to all of the parameters in the push payload. This code will be executed whether the app is in the foreground, background, or not open at all.

Whether the Application is Open or Closed

Depending on the needs of your application, you may want to handle the push notification differently depending on the state of the app. No matter the stateIn our example, we want to handle the push differently depending on whether the app is in the foreground or if it is in the background or closed. If the app is in the foreground, we also want to handle the app differently depending on what page is open.

In order to track whether the app is in the foreground or background, we manipulate a global variable $appInForeground in the application “on_activate_app” and “on_deactivate_app” events.

  def on_activate_app
    $appInForeground = 1 #set global variable to indicate app is now in foreground
  end

  def on_deactivate_app
    $appInForeground = 0 #set global variable to indicate app is now in background
  end

If the application is in the foreground, this variable will be 1, and if it is in the background, this variable will be 0. If the application isn’t open at all, this variable will be nil, because the variable was destroyed when the application closed.

Current Page of the Application

If the application is open, the current page is accessible via the “WebView.current_page” method. A simple if statement on the result of this method call will allow you to perform different actions depending on which page is open.

if $appInForeground == 1 #app is in the foreground
  ##FIND CURRENT PAGE LOCATION
  currentPage = WebView.current_location

  ##REACT DIFFERENTLY DEPENDING ON WHAT PAGE THE USER IS ON
  if currentPage.include? "/app/SomeController/SomeAction" #user last hit this URL
    #do something
  elsif currentPage.include? "/app/SomeOtherController/SomeOtherAction" #user last hit this other URL
    #do something else
  else #user last hit any other URL in the application
    #do something else
  end
elsif $appInForegroud == 0 #app is in background
  #do something else
elsif $appInForeground == nil #app is not open
  #do something else
end

Status Bar Notifications

You can also implement status bar notifications when a push notification is received. There are some limitations to this functionality in Rhodes, so we used a native Java extension that builds the notification and sends it to the operating system for display. You should be able to drop this in your project without any modification, but if you need to change it for whatever reason, be aware that any changes/additions in methods or signatures in the Java code will require changes to other files within the extensions folder. See the Rhodes documentation for Native Extensions for more detail if you need to make modifications.

Follow these steps to add status bar notification functionality to your Rhodes project:

  1. Drop the “StatusNotificationHandler” folder into the extensions folder of your Rhodes project.
  2. Add the StatusNotificationHandler extension entry to the Android section of your “build.yml” file.
    android:
      extensions:
        - StatusNotificationHandler
    
  3. Call “StatusNotificationHandler.show_status(title, message, data)” whenever you want to display the status bar notification.
  • title is a string that will show as the title text on the phone’s notification center.
  • message is a string that will show as the message text on the phone’s notification center. This will also be what flashes at the top/bottom of the screen when the notification is received.
  • data is a string representation of any data you want to be able to access when the notification is clicked on. This string is added as an extra to the Java intent that is passed to the notification.

The data parameter is accessible when the notification is clicked by calling “System.get_start_params” in your Ruby code. This method will return the all extras added to the intent (in our case the data parameter from the show_status call) in query string format, i.e. “?data=Data parameter passed to the show_status method call”. For some reason, while the startup params are available immediately when the application goes from background to the foreground, but they are not immediately available on startup of the application. We accounted for this by using Rho::Timer to wait a few milliseconds before calling “System.get_start_params” when the app is first starting up. Once you get the start params, you can use parse them and react appropriately.

In our example, we pass a string representation of the push parameters to the show_status method, and parse them when the user clicks on the notification. This allows us to know what page to open to when the user clicks on a notification; if the user clicks on a notification that says they received a message, we are able to open the application to the page that contains that message.

There are two components to this functionality:

  1. Call the “check_start_params” method in the application “on_activate_app” event. If the application is first starting up, you will need to wait a few milliseconds (some devices take longer than others) before making this call to ensure that “System.get_start_params” will return its true value. If the application is coming from the background, the start params will be immediately available so we don’t have to wait.
    def on_activate_app
      if $appInForeground.nil? #app is first starting up
        Rho::Timer.start(500, "app/Echo/check_start_params", "") #need to wait for start params to be available
      else #app is coming from background
        WebView.navigate("app/Echo/check_start_params") #start params are immediately available
      end
    
      $appInForeground = 1 #set global variable to indicate app is now in foreground
    end
    
  2. Define the desired action based on the data in the “check_start_params” method of the “echo_controller.rb” class.
      def check_start_params
        start_params = System.get_start_params.to_s
        if start_params.include? "?data=" #ensure the start_params are in the right format
          hash = eval(start_params.gsub("?data=","")) #if data is a hash in string form, eval() turns it back to a hash
          #define actions based on the data
        end
      end
    

Code Starter

The “Echo” folder is reusable code than can be dropped into any Android project, and it can be easily modified to work with iOS devices. These files contain the code that registers the device’s push registration id with Urban Airship and the push callback method. The code requires the following in order to work out of the box with your project:

  • The Echo folder must be located in the “app” folder of your project.
  • The following entries must be present in the “rhoconfig.txt” file
    ua_application_key='' #Your Urban Airship application key goes here
    ua_application_secret='' #Your Urban Airship application secret goes here
    android_package_name='' #Your Android package name goes here
     
  • “System.set_push_notification” must be set to “app/Echo/receive_push” in the application “initialize” event
            System.set_push_notification "app/Echo/receive_push", ""
            
  • The $appInForeground global variable must be set to “1” in the application “on_activate_app” event and set to “0” in the application “on_deactivate_app” event, as shown in the “Whether the Application is Open or Closed” section.

While Echo is designed to be as flexible as possible, the code is easily modifiable if any of the above conditions cannot be met, or if you need to change its inner workings for any reason. All code samples are included in the project “EchoTemplate”; you can either use this project as a starting point or copy the files you need over to your own project. We are also including a copy of our sample app, FinslapRhodes, which is a chat application that implements the push notification functionality discussed on this page. FinslapRhodes is not a complete application and is for demonstration purposes only.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s