Emulating PhoneGap/Cordova Apps in the Desktop Browser

Earlier this month the PhoneGap team held the first PhoneGap day.  This was in part to celebrate the release of PhoneGap 2.0, but more importantly to bring together members of the PhoneGap community to share and learn from each other.   There are great recaps of PhoneGap Day from RedMonk, as well as on the PhoneGap blog. One of the new services announced on PhoneGap Day was emulate.phonegap.com.  Emulate.phonegap.com enables an in-browser simulator for developing and debugging PhoneGap/Cordova applications, complete with Cordova API emulation.  It is built off of the Ripple Emulator, which itself is open source and may even be contributed to the Apache Cordova project.

Emulate.phonegap.com is built as a Google Chrome Extension, so it requires the Chrome browser.  It also uses the Ripple Operating Environment (another Chrome Extension).   Once you have the dependencies installed you can emulate any site as a PhoneGap/Cordova application by either going to emulate.phonegap.com and entering the target URL, by launching the emulator from a right-click -> Emulator -> Enable, or by clicking on the Ripple icon in the Chrome toobar, and selecting the “Enable” option.

Once launched, the URL that you want to simulate will be displayed within the Ripple operating environment view.

Note: This only works with assets that are on a live URL. You can use a local http server with references to localhost, however the emulator will fail if you try to access your application directly from the local file system using a file:// URI.

Update: You can enable access to local files by changing a few settings on the Ripple emulator.  See the first comment on this post for additional detail.


(click for full-size image)

The emulator environment gives you the ability to emulate PhoneGap events and API calls, without having to deploy to a device or run inside of the iOS, Android, Blackberry, or other emulator.  Not only can you simulate the PhoneGap/Cordova API, but you can also use Chrome’s debugging tools to test & debug your code – complete with breakpoints, memory inspection, and resource monitoring. This is a handy development configuration. It enables app development within a rich debugging environment that is familiar, fast & easy to use. This does not replace on-device debugging however… nothing will replace that.   On-device debugging is extremely important; this helps increase your productivity as a developer.

So how do you use this environment? The environment will handle Cordova API requests, and you can also simulate device events.

First, the “Devices” panel… In this panel you can select a device configuration – Everything from iOS, to Android, to BlackBerry.  Changing the device configuration will not only change the physical dimensions, but will also change Device/OS/user agent settings reported by the application.   Here you can also select the device orientation, which will change the visual area within the simulator.

Within the “Platforms” panel you can choose the platform you wish to emulate.  With respect to PhoneGap applications, you will want to choose “Apache Cordova”, and then select the API version that you are using.  By default, it uses “PhoneGap 1.0.0″, however you can chose “Apache Cordova 2.0.0″ to get the most recent version.   The Ripple emulator also simulates BlackBerry WebWorks and mobile web configurations as well.

The “Information” panel shows you information about your current simulator configuration.  It shows the platform, device, simulated OS, user agent etc…

The “Accelerometer” panel can be used to simulate device orientation/accelerometer events.  Just click and drag on the device icon (the gray and black boxes), and the icon will rotate in 3D.   As you drag, accelerometer events will be dispatched and handled within your application.  From here, you can even trigger a “shake” event.

The “Settings” panel lets you turn on/off the cross domain policy, adjust the UI color theme, and view additional data about the Ripple emulator.

The “Device & Network Settings” panel enables you to simulate and throttle the network connection type: “Ethernet”, “WIFI”, “CELL_3G”, etc…

The “Geolocation” panel enables you to simulate your geographic position within your PhoneGap/Cordova application.  You can specify a latitude, longitude, altitude, speed, etc…  You can even drag the map and use it to specify your geographic position. The position that you set within the geolocation panel will be reported when using navigator.geolocation.getCurrentLocation().

The “Config” panel is a graphical representation of your PhoneGap Build Config.xml file.   You can use this to easily view/analyze what’s in your application configuration.

The “Events” panel can be used to simulate PhoneGap specific events, including “deviceready”, “backbutton”, “menubutton”, “online”, and “offline” (among others).  Just select the event type, and click on the “Fire Event” button.

As I mentioned earlier, this won’t replace on-device debugging.  It also won’t handle execution of native code for PhoneGap native plugins, however you can test/develop against the JavaScript interfaces for those native plugins.  Emulate.phonegap.com will definitely help with development of PhoneGap applications in many scenarios, and is a nice complement to the Chrome Developer Tools.

PhoneGap 2.0 Released

PhoneGap 2.0 has just been released!  This is a great step forward for PhoneGap, with a much improved developer experience.

New and improved features in PhoneGap 2.0 include:

  • Cordova WebView
  • Command Line Tooling
  • Enhanced documentation
  • Web Inspector Remote (Weinre) ported to nodejs
  • Cordovajs (Support for unified Javascript across platforms)
  • Transition to Apache Cordova and nearing graduation from incubation
  • Windows Phone support
  • Improvement to iOS app creation

Read all about PhoneGap 2.0 on the PhoneGap blog, and check out the changelog for detailed changes in this release.   Or, just go download it and get started today!

Using Adobe Edge Animations As Components

You’ve probably heard of Adobe Edge, a timeline-based tool for creating interactive and animated HTML content. Edge enables you to easily create interactive experiences that rely only on HTML, CSS, and JavaScript. If you’ve used other Adobe Creative Suite tools, such as Flash Professional, Premiere, or After Effects, then Edge will probably look quite familiar. You have a timeline and controls to edit your content.

Currently, the “normal” use case for Edge is creating interactive experiences that are loaded when the page loads.  You can chain animation compositions in sequence, but they have to be in the same wrapper HTML file.  This works great for a number of use cases, but one thing I wanted to do is create an Edge animation and use that as a component that is arbitrarily added to the HTML DOM at any point in time. My findings: It can be done, although with a few gotchas.

Using Edge animations as components inside of a larger HTML experience isn’t the primary use case which Edge was designed for. However this use case is being evaluated and may end up in Edge at a later date. If that happens, this process will become much easier.

If you’re wondering “What was I thinking?”, I’ll try to explain… while discussing the process of building HTML-based apps, I had the thought:

Wouldn’t it be cool to have a really elaborate loading animation while loading data from the server? We could use Edge to build the animation!

As a proof of concept, I created a very basic application that loads two separate Edge animations on demand. Before I go into too much detail on what I built, let’s take a look at the running example. This example has two buttons, one shows a car animation, one shows an airplane animation. It’s pretty basic and straightforward:

The first thing that I did was create two simple Edge animations which you can view here:

All images used in these animations were obtained from thenounproject.com.

Once the animations were complete, I started looking at the generated HTML output, and figuring out how I can add it to the HTML DOM of an existing HTML page. I then started putting together the sample application using Mustache.js as a templating engine to abstract HTML views away from application logic. Note: I also have a simple utility that enables me to include Mustache.js templates in separate HTML files, so that I can keep everything separate.

First, I created the basic shell for the application. It is more or less an empty HTML structure, where all content is added at runtime:


Inside of the “contentHost” div, all UI is added to the HTML DOM upon request. Basically, when the user clicks a button, the Edge animation is added to the DOM, and then the animation begins.

In order to get this working, I had to change a few things in the generated Edge output:

  1. in the *_edge.js file, I changed the DOM Ready event handler to use an arbitrary event that I can control. By default, Edge uses the jQuery $(window).ready() event to start the animation. Since I am adding this to an existing HTML DOM, the $(window).ready() event is not applicable.  Instead, I changed this to use a custom “animationReady” event:
    $(window).bind( "animationReady", function() {
       Edge.launchComposition(compId);
    });
  2. In the *_edgePreload.js file, I added a reference to the onDocLoaded function so that I can manually invoke it later, once the Edge animation has been added to the DOM, since again, this won’t rely on the “load” event.
    //added this so it can be invoked later
    window.onDocLoaded = onDocLoaded;

    I also changed the aLoader object to reference the appropriate JavaScript files, since I changed their location in the directory structure:

      aLoader = [
      { load: "templates/animation_planes/edge_includes/jquery-1.7.1.min.js"},
      { load: "templates/animation_planes/edge_includes/jquery.easing.1.3.js"},
      { load: "templates/animation_planes/edge_includes/edge.0.1.6.min.js"},
        {test: !hasJSON, yep:"templates/animation_planes/edge_includes/json2_min.js"},
         { load: "templates/animation_planes/planes_animation_edge.js"},
         { load: "templates/animation_planes/planes_animation_edgeActions.js"}];
  3. Finally, I created the Mustache.js template, which will be used to generate the HTML DOM elements that will be appended to the existing DOM.   In this there is a wrapper DIV, some HTML content including a button and some text (the animation number is dynamic for the templating), the styles, a “Stage” div, and Edge preload JavaScript files necessary for the animation.
    </pre>
    <div id="animationContainer">
     <button id="removeAnimation">Restore Default View</button>
    
     Animation {{animationCount}}
    
    <script charset="utf-8" type="text/javascript" src="templates/animation_planes/planes_animation_edgePreload.js"></script></div>
    <pre>
    
  4. Next, let’s look at how this is actually injected into the DOM.  I created a setupAnimationView() function to inject the animations into the DOM.  This function is used by both animations. The first thing that it does is remove any existing DOM content and dereference the AdobeEdge variables in memory. Since Edge wasn’t originally designed for asynchronously loading animations, I found it to be easiest to just wipe-out Edge and reload it for every animation.   The unfortunate side effect is that you can only have one Edge animation on screen at any given point in time.  Next, the setupAnimationView() function generates the HTML DOM elements and event listeners and adds them to the DOM. Finally, I created an edgeDetectionFunction, which checks to see if Edge is loaded.  If not, it loads the Edge runtime. The edgeDetectionFunction() then checks if the Edge animation is sufficiently loaded. If the animation definition is not loaded, it just waits and tries again.  If the animation definition is loaded, it dispatches the “animationReady” event (discussed in step 1) to invoke the actual animation.
    function setupAnimationView( template ) {
      $("#contentHost").empty();
      window.AdobeEdge = undefined;
      AdobeEdge = undefined;
      animationCount++;
      var viewModel = {animationCount:animationCount};
    
      var html = Mustache.to_html(template, viewModel)
      $("#contentHost").append( html );
      $("#removeAnimation").click( setupDefaultView );
    
      //detect if edge is loaded yet
      var edgeDetectionFunction = function() {
    
        if ( AdobeEdge && AdobeEdge.compositions != undefined) {
    
          var hasComposition = false;
    
          if ( AdobeEdge.compositions ) {
            //loop to see if the composition is actually loaded
            for ( var key in AdobeEdge.compositionDefns ) {
              hasComposition = true;
              break;
            }
          }
    
          if ( hasComposition ) {
            setTimeout( function(){ $(window).trigger( "animationReady" ); }, 100 );
            return;
          }
        }
        else if ( AdobeEdge ) {
          window.onDocLoaded();
        }
        setTimeout( edgeDetectionFunction, 100 );
      }
      edgeDetectionFunction();
    }
    

Since I am using Edge in a manner for which it was not initially designed, there are a few “gotchas” that I ran into:

  • You can’t have multiple instances of the same Edge animation in a single HTML DOM – at least, not easily.   Each Edge animation is assigned a unique ID.  This ID is referenced in the HTML structure and the *_edge.js, *_edgeActions.js, and *_edgePreload.js files.   You would need to assign a unique ID to each instance, and make sure everything is referenced consistently.
  • It will be very tricky asynchronously add more than one Edge animation at the same time.   The shortcut that I used to get these to render was to wipe away the Edge variables in JS and reload them – this would cause some issues with more than one animation.

If the capability to have Edge animations as components gets built into Edge (which I hope it does!), then you will not have to go through all of these steps, and it will be much easier.   I’ll be sure to share more if this feature develops.

This Example

More on Edge

If you haven’t yet seen what Edge can do, you really should take a look at some of these examples built with Adobe Edge:

Enjoy!

Upcoming Conferences & Presentations

I’ll be speaking at a few conferences in the next few months on PhoneGap and web standards-based development.  Here are just a few, with some more pending.  Be sure to come check one out (or all of them)!


RIACON

www.riacon.com
WHERE: Washington, DC
WHEN: Aug 6-7, 2012

Where architects and developers of all levels come to gather, share and learn about creating the next generation of web based applications.  RIAcon’s goal is to help you network with fellow industry professionals and expose you to the best content.

I’ll be speaking on the following topics at RIACON:

  • Introduction to PhoneGap
    Interested in developing applications for mobile devices, on multiple platforms? Interested in leveraging your existing web development skills to build natively installed applications? Just looking to expand your skill set? Come join Adobe Technical Evangelist, Andrew Trice, to learn about cross platform mobile development and PhoneGap. In this session, you will get an introduction to PhoneGap (Apache Cordova), be able to see example PhoneGap applications, and walk through the process of building your first PhoneGap application.

  • PhoneGap Native Plugins
    PhoneGap enables developers to build natively installed applications using traditional web-based development tools (HTML & JavaScript), but what if you want to make your application do more? In this session, learn how to write native plugins for PhoneGap that enable you to extend the API to tap into native device functionality.

  • Data Visualization with Web Standards
    Do you have the requirement to create rich visual data dashboard applications, but also have the requirement to use web-standard technologies, and don’t know what to do next? Well, you’re in luck! Come to this session to learn about data visualization strategies and frameworks powered entirely with HTML and JavaScript.


360|iDev

360idev.com/
WHERE: Denver, CO
WHEN: Sept 18-21, 2012

360|iDev is the first and still the best iPhone developer conference in the world. We’re not a publishing company pushing books, or a media company selling subscriptions. We’re a conference company, focused on community. Our goal is to bring the best and brightest in the developer community together for 3 days of incredible sessions, awesome parties, good times, and learning. If you don’t leave Wednesday night, with more ideas than you know what to do with, we’re not doing our jobs!

I’ll be speaking on the following topics at 360|iDev:

  • Kick A$$ iOS Apps with PhoneGap
    Apps don’t have to be written in native Objective-C to be awesome.   Get ready for a crash course in PhoneGap, a tool that enables you to build natively installed iOS apps using 100% HTML & JavaScript, complete with access to local APIs.  We’ll cover everything from “what is phonegap” to strategies for building highly performant & interactive applications.

  • Enterprise iOS Apps with PhoneGap
    Did you know that you can easily build awesome natively installed iOS apps using web technologies with PhoneGap? In this session, we’ll cover strategies for enterprise application development – everything from data visualization, MVC & distributed development, UI frameworks, performance considerations, and dev/debug workflows in PhoneGap apps built entirely with HTML, CSS & JavaScript.


Dreamforce

www.salesforce.com/dreamforce/DF12/
WHERE: San Francisco, CA
WHEN: Sept 18-21, 2012
Dreamforce is the annual conference by Salesforce.com. In their own words:

Every year Dreamforce features stories and presentations from some of the brightest minds in technology, business and beyond. This year’s Dreamforce promises to be even more informative and dynamic, with our most exciting keynote speaker lineup yet. The cloud computing event of the year is also the Social Enterprise event of the year. This is where you’ll learn everything you need to know—from the industry leaders who are paving the way—about how the Social Enterprise revolution is changing the way we do business.

I’ll be speaking on the following topics at Dreamforce:

  • Data Visualization with Web Standards
    Do you have the requirement to create rich visual data-centric applications, but also have the requirement to use web-standard technologies, and don’t know what to do next? Well, you’re in luck! Come to this session to learn about data visualization strategies and frameworks powered entirely with HTML, CSS, and JavaScript.

  • Native-like Apps with PhoneGap
    Native applications built using web technologies can suffer from the “uncanny valley” effect – where they don’t feel quite right as a native application. In this session we’ll focus on strategies to make your apps feel like native apps, including considerations for a native-feeling UI, platform consistency, and user experience.

I hope to see you at one of these events!