Category Archives: Mobile Development

9 Chrome Plugins to help you debug your web apps and GSD

I’m personally obsessed with GSD (getting stuff done) and find the following (free) developer tools to be invaluable in this regard. Check ’em out, and if you have any other suggestions, please list them in the comments!

POSTMAN

Postman is a free Google Chrome App that enables you to easily test your REST API’s.

Image

Features include:

  • Ability to create requests quickly
  • Simulate HTTP requests with file upload support
  • Auto-Formatting of JSON and XML responses
  • Basic an OAuth Helpers
  • Share collections between developers
  • Create unit tests by adding “Jetpacks” ($9.95 US)

CLEAR CACHE

Clear Cache is a free Google Chrome App that enables you to reliably clear your browser cache at the click of a button.

Image

APACHE RIPPLE

Apache Ripple™ is a web based mobile environment simulator designed to enable rapid development of mobile web applications for various web application frameworks, such as Apache Cordova™ and BlackBerry® WebWorks™. It can be paired with current web based mobile development workflows to decrease time spent developing and testing on real devices and/or simulators.

Image

It is free software, licensed under the Apache License, Version 2.0.

Features include:

  • Disabling cross-domain security restrictions
  • Accelerometer simulation
  • Geolocation simulation

JSON EDITOR ONLINE

JSON Editor is a Chrome plugin for viewing, editing, and formatting JSON. It shows your data in an editable treeview and in a code editor.

JSONEditor

Features include:

  • View and edit JSON side by side in treeview and a code editor.
  • Edit, add, move, remove, and duplicate fields and values.
  • Change type of values.
  • Sort arrays and objects.
  • Colorized values, color depends of the value type.
  • Search & highlight text in the treeview.
  • Undo and redo all actions.
  • Load and save files and urls.
  • Format, compact, and inspect JSON in the code editor.

REGEXP TESTER

This free Chrome plugin enables you to quickly and easily verify the validity of your javascript regular expressions.

regexp

ICOMOON

Icomoon enables you to rapidly select and encode icons as a custom font. This is particularly useful  if you’re developing custom themes for Sencha Touch and Ext JS 4.21+ applications.

icomoon

SPEEDTRACER

Speed Tracer by Google is a tool to help you identify and fix performance problems in your web applications. It visualizes metrics that are taken from low level instrumentation points inside of the browser and analyzes them as your application runs.

speedtracer

If you’re obsessed with Javascript RIA application performance, check it out!

CHROMEVOX

If you want to verify that your Javascript-based RIA (Ext JS 4) is accessible for the vision impaired, check out this free Chrome plugin.

APP INSPECTOR FOR SENCHA

App Inspector for Sencha™ is an extension for Google Chrome DevTools which makes debugging Sencha Ext JS and Touch applications easier than ever before!

App Inspector for Sencha™ helps you to inspect your component tree, data stores, events, and layouts. It provides similar functionality to Illuminations for Developers.

appinspector

Create a game and win an all-expenses paid trip to SenchaCon!

bbz10Last month, Sencha and Blackberry sponsored a contest among the top 25 performing Sencha partners from which five would be selected to be demoed at SenchaCon. The goal of the contest was to develop/port apps to the Blackberry Z10 that highlighted the features and benefits of that new device. We were honored to be included in the contest and delighted to find that our entry was named as one of the winners.

Now, as many of my close friends can attest, I have a weakness for contests that dates all the way back to an unfortunate incident that occurred during my senior year of high school. And ever since then, any time a good contest comes along, it captures my full attention. It’s a bit of an unhealthy obsession, actually. This was as true for the first (and last) game of “quarters” that I played back in college as it is today when I’m competing in a hackathon or for a spot in the Inc. 500/5000. And don’t “double-dog dare” me…ever. You’ll end up licking Bourbon Street. But, I digress.

Victorious warriors win first and then go to war, while defeated warriors go to war first and then seek to win.

-Sun Tsu

So, the first step in competing was strategizing about what kind of app might make it to the “final five.” I wanted to do something that hadn’t really been attempted before. So, I made a list of key features:

  • It had to be “cool.”
  • It had demonstrate the superior performance of the Blackberry Z10.
  • It had to stretch the limits of what was possible with Sencha Touch and mobile platforms.
  • It had to make our brains hurt (something new that we hadn’t built before).
  • It had to contain at least one Mel Brooks or Monty Python reference.
  • It had to “suck up” to the judges (lesson learned in high school)

So I decided that we’d build a game. Not any game, mind you. THE GAME. The game that initially piqued my interest in computers, way back in 1980 – STAR RAIDERS, running on an Atari 400. Surely a game that had been built nearly 35 years ago to run within 8KB of RAM and perform well on a 4.77 Mhz CPU could be redeveloped to run as an HTML5 app on a mobile phone, right? What could possibly go wrong?!

Creating the Proof of Concept

With the plan in hand, we built out a proof-of-concept just to see if we could get the most basic UI elements to operate efficiently on the platform.  We had to get directional starfield working, as well as some of the visuals for basic game features like “raising the shields” and changing direction of the ship. We also wanted to see if we animate the firing of photon torpedoes to be reasonably performant. Fortunately, the overall HTML5 performance of the Blackberry Z10 was really great. This is a device that definitely merits your consideration the next time that you find yourself shopping for a smartphone.

My God, It’s Full of Stars

stars

As it turned out, the starfield was actually relatively easy to implement- largely because we could “cheat” and port this HTML 5 example over to a Sencha Touch view. One of the challenges, however, is that since the starfield was built for an HTML5 canvas, we had to ensure that Sencha’s Ext.draw.Component class would always generate a <canvas> tag, regardless of the device that the app was running on (currently Sencha Touch outputs <canvas> on iOS and SVG for everything else). The solution was fairly straightforward, albeit not particularly well documented. Sencha Touch enables you to explicitly set the drawing engine as illustrated by the following code snippet:

Ext.define('MyApp.view.StarCanvas', {
	extend: 'Ext.draw.Component',
	alias: 'widget.starcanvas',
	engine: 'Ext.draw.engine.Canvas'
});

The rest of the starfield was, more or less, a direct port. Of course, we had to fit it into the Sencha framework and made some minor mods to support an “aft view” as well as tweaked the code to randomize the star’s starting positions:

Ext.define('MyApp.view.ViewScreen', {
	extend: 'Ext.Container',
	alias: 'widget.viewscreen',
	requires: [
			'Ext.draw.Component',
			'MyApp.view.StarCanvas'
	],

	c_x: null,
	c_y: null,
	starTimer: null,

	config: {
		itemId: 'viewscreen',
		style: 'background-color: #000000',
		layout: {
			type: 'fit'
		},
		aftView: false
	},

	onViewscreenActivate: function() {
		this.onChangeOrientation();
		this.initializeStars();
		this.doAnimate();

		//console.log(Ext.ComponentQuery.query("#sndThrust")[0].getDuration());
		/*
        Ext.device.Orientation.on({
            orientationchange: {
                fn: this.onOrientationChange,
                scope: this
            }
        });
        */
	},

	updateAftView: function(nVal) {
		this.initializeStars();
		this.star_speed *= -1;
	},

	initialize: function() {
		this.n = 512;
		this.w = 0;
		this.h = 0;
		this.x = 0;
		this.y = 0;
		this.z = 0;
		this.star_color_ratio = 1;
		this.star_ratio = 256;
		this.star_speed = 1;
		this.star_speed_save = 0;
		this.star = new Array(this.n);
		this.fps = 0;
		this.cursor_x = 0;
		this.cursor_y = 0;
		this.canvas_x = 0;
		this.canvas_y = 0;
		this.setItems({
			xtype: 'starcanvas',
			itemId: 'viewscreenCanvas'
		});
		this.canvas = this.down('#viewscreenCanvas');
		this.domCanvas = Ext.get(this.canvas.getSurface().element.query('canvas')[0]);
		this.on({
			resize: this.onChangeOrientation,
			scope: this
		});
		Ext.Function.defer(this.onViewscreenActivate, 750, this);
		this.animateStarField = Ext.Function.bind(this.doAnimate, this);
		this.callParent(arguments);
	},

	onOrientationChange: function(e) {
		e = e[0];

		// var s = this.down('starcanvas');
		// console.log('g', e.gamma);
		// console.log('b', e.beta);

		this.cursor_x += e.gamma - this.c_x;
		this.c_x = e.gamma;
		this.cursor_y += e.beta - this.c_y;
		this.c_y = e.beta;
	},

	onChangeOrientation: function() {
		var el = Ext.get(this.element.select('canvas').elements[0]);
		this.w = el.getWidth();
		this.h = el.getHeight();

		this.x = Math.round(this.w / 2);
		this.y = Math.round(this.h / 2);
		this.z = (this.w + this.h) / 2;
		this.star_color_ratio = 1 / this.z;
		this.cursor_x = this.x;
		this.cursor_y = this.y;
	},

	doAnimate: function() {
		context = this.domCanvas.dom.getContext('2d');
		context.fillStyle = 'rgb(0,0,0)';
		context.strokeStyle = 'rgb(255,255,255)';
		mouse_x = this.cursor_x - this.x;
		mouse_y = this.cursor_y - this.y;
		// console.log(mouse_x, mouse_y);
		// var path = '';
		// this.canvas.removeAll(true);
		context.fillRect(0, 0, this.w, this.h);
		for (var i = 0; i < this.n; i++) {
			test = true;
			this.star_x_save = this.star[i][3];
			this.star_y_save = this.star[i][4];
			this.star[i][0] += mouse_x >> 4;
			if (this.star[i][0] > this.x << 1) {
				this.star[i][0] -= this.w << 1;
				test = false;
			}
			if (this.star[i][0] < -this.x << 1) {
				this.star[i][0] += this.w << 1;
				test = false;
			}
			this.star[i][1] += mouse_y >> 4;
			if (this.star[i][1] > this.y << 1) {
				this.star[i][1] -= this.h << 1;
				test = false;
			}
			if (this.star[i][1] < -this.y << 1) {
				this.star[i][1] += this.h << 1;
				test = false;
			}
			this.star[i][2] -= this.star_speed;
			if (this.star[i][2] > this.z) {
				this.star[i][2] -= this.z;
				test = false;
			}
			if (this.star[i][2] < 0) {
				this.star[i][2] += this.z;
				test = false;
			}
			if (!test) {
				// reset starting position and angle
				this.star[i][0] = Math.random() * this.w * 2 - this.x * 2;
				this.star[i][1] = Math.random() * this.h * 2 - this.y * 2;
				this.star[i][2] = Math.round(Math.random() * this.z);
			}
			this.star[i][3] = this.x + (this.star[i][0] / this.star[i][2]) * this.star_ratio;
			this.star[i][4] = this.y + (this.star[i][1] / this.star[i][2]) * this.star_ratio;
			if (this.star_x_save > 0 && this.star_x_save < this.w && this.star_y_save > 0 && this.star_y_save < this.h && test) {
				context.lineWidth = (1 - this.star_color_ratio * this.star[i][2]) * 2;
				context.beginPath();
				context.moveTo(this.star_x_save, this.star_y_save);
				context.lineTo(this.star[i][3], this.star[i][4]);
				context.stroke();
				context.closePath();
			}
		}
		// surface.renderFrame();
		// update playfield
		requestAnimationFrame(this.animateStarField);
	},

	initializeStars: function() {
		for (var i = 0; i < this.n; i++) {
			this.star[i] = new Array(5);
			this.star[i][0] = Math.random() * this.w * 2 - this.x * 2;
			this.star[i][1] = Math.random() * this.h * 2 - this.y * 2;
			this.star[i][2] = Math.round(Math.random() * this.z);
			this.star[i][3] = 0;
			this.star[i][4] = 0;
		}
	}
});

As you can see from the code snippet, we toyed around with using the device’s accelerometer to control ship/starfield movement but ultimately abandoned the idea as it was too difficult for my forty-four year old fingers to accurately control.

In Space, No One Can Hear the Developer Scream

Another somewhat unexpected challenge involved adding sound effects to the app. I had heard that HTML5 audio had some “issues” but was completely unprepared for the truly heinous support (or lack thereof) that is currently out there. This was 2013, after all, and I figured that a full five years after the introduction of the iPhone that surely browser support for MP3 playback must have been troubleshot. I could not have been more wrong.

Our initial “brute-force” implementation for adding sound was to simply add hidden Ext.Audio instances to a view class as illustrated below:

 items:[
  { xtype: 'audio',
   url  : 'resources/sounds/pewpew.mp3',
   itemId: 'sndFirePhoton',
   hidden: true
  },
  {
   xtype: 'audio',
   url  : 'resources/sounds/thrust.mp3',
   itemId: 'sndEngineThrust',
   loop: true,
   hidden: true
  }
 ]

We then selectively executed the Ext.audio.Play() method based on the type of operation that was being performed by the user. And this worked great…until we tested it on mobile devices where it failed in strange and magnificent ways! It turns out that iOS has some significant issues with playing back two audio streams simultaneously, and the Blackberry OS would randomly fail to load our MP3 files once a certain memory usage threshold was reached.

Pull-yourself-together! “What will you do?” Is this a question? You will show him you remember that he is Mr. Incredible, and you will remind him who *you* are. Well, you know where he is. Go, confront the problem. Fight! Win!

Edna Mode

Ultimately, our stop-gap solution was to produce a sound “sprite.” Essentially we merged all of the game’s sound effects into a single file (cudos to Adobe Audition) and then extended the Ext.Audio class to play segments on an as-needed basis:

Ext.define('MyApp.view.Sounds', {
    extend: 'Ext.Audio',
    xtype: 'sounds',

    audioSprite: null, // DOM reference
    audioQueue: [],
    canPlayThrough: false,

    config: {
        hidden: true,

        ambientTrack: 'sndThrust',
        playAmbient: false,

        tracks: {
            sndOn: {
                start: 0,
                length: 0.35
            },
            sndOff: {
                start: 1.38,
                length: 0.5
            },
            sndWarp: {
                start: 2.974,
                length: 6.456
            },
            sndWarpExit: {
                start: 9.43,
                length: 6.96
            },
            sndTorp: {
                start: 17.39,
                length: 1.32
            }
        },

        url: 'resources/sounds/audiosprite.mp3',
        itemId: 'sndSprite'
    },

    initialize: function() {
        this.callParent(arguments);
        this.audioSprite = Ext.get(this.element.select('audio').elements[0]);
        this.audioTimeUpdate = Ext.Function.bind(this.onTimeUpdate, this);
    },

    onTimeUpdate: function(e) {

        if (this.audioQueue.length > 0) {
            if (this.getCurrentTime() >= this.audioQueue[0].start + this.audioQueue[0].length) {
                this.pause();
                Ext.Array.erase(this.audioQueue, 0, 1);
                if (this.audioQueue.length > 0)
                    this.playQueue();
                else if (this.getAmbientTrack() != '' && this.getPlayAmbient()) {
                    this.playTrack(this.getAmbientTrack());
                }
            }
            requestAnimationFrame(this.audioTimeUpdate);
        }

    },

    updatePlayAmbient: function(bool) {
        if (bool) {
            this.playTrack(this.getAmbientTrack());
        }
    },

    playQueue: function(bNow, err) {

        try {
            this.setCurrentTime(this.audioQueue[0].start);
            this.play();
            requestAnimationFrame(this.audioTimeUpdate);
        } catch (e) {
            // overcome potential ios seeking issue
            this.play();
            this.pause();
        }

    },

    playTrack: function(name, bNow) {

        if (bNow) {
            this.audioQueue = [];
        }
        this.audioQueue.push(
            this.getTracks()[name]);

        this.playQueue(bNow);

    }
})

This effectively solved our file loading issue on Blackberry and iOS started playing back a bit more reliably, but is still a bit dodgy. It also had the side benefit of reducing the number of http requests to sound files, and anything that you can do to reduce the number of http transactions is helpful for performance. Ultimately, I’ll refactor this again to try and make it even more stable, but it’s borderline acceptable for a 1.0 release of a “demo app”

Always remember to bring the funny

For me, the best part of working on this project was finding interesting ways to inject geek humor into the proceedings

Like engaging the warp drive…

ludicrous

…and putting a ridiculous backstory into a “Star Wars” crawl  using CSS3…

crawl

…and making an oblique reference to the lead developer of Sencha Touch (Jacky Nguyen)…

instructions

… and simulating a “cracked” viewscreen when you get caught with your shields down…

cracked

…and designing a scenario where legions of  jQuery developers are out to assimilate you …

jq

Was it over when the Germans bombed Pearl Harbor?

I suppose that what I’ve learned over the years is that it takes just a little bit of insanity and no small amount of effort to win these contests. Reach for the stars, but be prepared when the universe responds by firing a photon in your general direction.

Work on the app continues…we’re still hacking away, posting new builds every few days, optimizing the codebase, and tweaking gameplay at http://webapps.figleaf.com/sr. Because, let me tell you, MATH IS HARD! We’ll have our initial 1.0 release out before SenchaCon on July 16th which will coincide with a full release of the sourcecode on GitHub for everyone’s mutual enjoyment.

Update:

Full sourcecode is available at:
https://github.com/sdruckerfig

 

How to Win Prizes at a Hackathon with Sencha Touch 2.2 Theming

A couple of weeks ago myself and one of my fellow Figs, Jason Perry, attended a MoDevUX Hackathon. Honestly, I had no idea what to expect – the last programming competition that I was in was when I led my high school team to a 12th place finish among all high schools in the area as we typed fast and furiously on an Apple IIE, programming in BASIC.

Obviously, the technology has improved just a little bit since then – as has the competition. After all, several of the hackathon contestants were just a glimmer in their parent’s eyes back in 1987 when going “mobile” meant lugging 20 lbs of equipment around with a handtruck. But I digress…

The goal of the hackathon was to produce a mobile app that had something to do with finance. (Capital One was the big sponsor). You got bonus points for developing apps for Microsoft Windows phones (Nokia was a sponsor), as well as using various APIs (Mashery.com) and/or adding VOIP/Voice/SMS communications to an app using the awesome Twilio API.

walletA third team member, whom we met at the Hackathon, came up with the idea to produce a mobile/social app that would enable people to exchange international currencies at the airport, without having to pay the ridiculous transaction fees charged by the on-site money exchanges.

My strategy was to cover as many bases as possible to ensure that we’d win *something* – I figured a first-time win for Team Fig would go a long way towards boosting company morale (and I wanted a Microsoft phone to complete our suite of  test devices). So, with the immortal words of Sean Connery ringing in my ear, we set off to design and build an app that would support the following features:

1) Look and feel like a native Windows Mobile phone (as well as be compatible across a broad range of other mobile devices)
2) Integrate voice/sms features from Twilio
3) Calculate currency conversion based on the current exchange rates via a third-party API
4) Link to a back-office database that would help facilitate matching compatible requests.
5) Translate requests and messages into different languages via the Google Translate API

And get functional prototype programmed and tested within a seven hour timeframe on a device (Nokia Windows Phone) that we had no prior development experience with. What could possibly go wrong?

Divide and Conquer

In order to make the deadline, we decided to use Sencha Touch 2.2 as our underlying development platform as they had just begun supporting Windows Mobile devices and had a Windows-Mobile compatible theme ready to go “out of the box.” I was responsible for developing the “front-end” Touch UI, while Jason was responsible for standing up a publicly accessible XAMPP stack and all the “back-end” API integration (PHP, figuring out how to use the Twilio API, etc).

Supporting Windows Mobile Devices

Supporting Windows Mobile 8 was the lynchpin of our strategy. I figured that since it was relatively new, most hackathon participants wouldn’t know how to develop for it. And even if they were familiar with it, they probably wouldn’t be able to throw an app together with Microsoft’s native tools as quickly as we could by using Sencha Touch.

Supporting Windows Mobile in Sencha Touch really comes down to linking to the “out of the box” Windows mobile stylesheet. In a Sencha Touch project, this can be accomplished by just typing a few lines out into the app.json file, which controls the loading of stylesheets based on device platform:

"css": [
 {
  "platform": ['ie10'],
  "theme": "Windows",
  "update": "delta",
  "path": "resources/css/ie.css"
 },
 {
  "path": "resources/css/bb.css",
  "platform": ['blackberry'],
  "theme": "Blackberry",
  "update": "delta"
 },
 {
   "path": "resources/css/default.css",
   "platform": ['chrome', 'safari', 'ios'],
   "theme": "Default",
   "update": "delta"
 }
]

The CSS file itself is generated by SASS/Compass, from a .SCSS file that resembled the following:

@import ‘sencha-touch/windows’;
@import ‘sencha-touch/windows/all’;

@include icon(‘upload’);
@include icon(‘left’);

So, with about 10 lines of code, we were able to leverage years of Sencha Touch development experience to produce an app for a device that we had never actually laid our hands on. We could also use Sencha Architect to rapidly prototype the UI, which was an added bonus!

Integrating Currency Conversion

Integrating currency conversion into an application is a pretty straightforward affair. We used a free currency rate service that supported a JSON-P interface that could be called directly from our Sencha Touch app:

Ext.define('MyApp.util.Currency', {
 statics: {
  conversionRate: function( from, to, callback, scope) {
   Ext.data.JsonP.request({
     url: 'http://rate-exchange.appspot.com/currency',
     params: {
      from: from,
      to: to
     },
     success: function(response) {
	callback.call(scope, response);
     }
   });
  }
 }
});

In this case, from and to represent currency codes (e.g. USD is US Dollars).

Using the Google Translate API

One of the features that we added to the app was the ability to send SMS and voice-synthesized phone messages (via Twilio), translated into the language of the recipient. Google Translate, while far from perfect, is quite easy to use – albeit not a free service. Integrating it into Sencha Touch was a snap:

Ext.define('MyApp.util.Translate', {
 statics: {
  key: 'AIza...',
  translate: function(text, source, target, callback, scope) {
   if (source == target) {
    callback.call(scope,text);
   } else {
    Ext.data.JsonP.request({
      url: 'https://www.googleapis.com/language/translate/v2',
      params: {
	key: MyApp.util.Translate.key,
	source: source,
	target: target,
	q: text
      },
      success: function(response) {
        callback.call(scope, response.data.translations[0].translatedText);
      }
    });
   }
  }
 }
});

Adding tel/sms services using Twilio

Twilio is a cloud-based service that enables you to create apps which send/receive/route phone calls, record audio, capture stats, send SMS messages, and more. They’ve even got an HTML5 SDK and series of REST services that you can invoke from Sencha Touch. We designed the app so that a user could message someone via SMS and voice-synthesized message (in language) who had a reciprocal currency exchange need at the designated airport, while keeping the user’s telephone numbers private.

In order to accomplish this, we defined a static class in our app that invoked a couple of custom webservices that we developed initially in PHP, and then later ported over to ColdFusion:

Ext.define('MyApp.util.Twilio', {
 statics: {
  sendText: function( transactionId, msg, callback, scope) {
    Ext.Ajax.request({
      url: 'http://webapps.figleaf.com/wallet/transaction.cfc?method=sendText',
      params: {
	id: transactionId,
	msg: msg
      },
      success: function(response) {
	callback.call(scope, response);
      }
    });
  },

  sendCall: function( transactionId, msg, callback, scope) {
    Ext.Ajax.request({
      url: 'http://webapps.figleaf.com/wallet/transaction.cfc?method=sendCall',
      params: {
	id: transactionId,
	msg: msg
      },
      success: function(response) {
	callback.call(scope, response);
      }
   });
  }
 }
});

On the server-side, we lookup transaction details and then invoke Twilio to send SMS messages and make the phone call. The way that Twilio scripted phone calls work is that you pass a callback URL that generates “TwiML” to their service. TwiML is quite powerful, but for our limited proof of concept, all we needed to do was tell it to “read” from a script that we translated into language using the Google Translate API.

<!--- send an sms text message --->
<cffunction name="sendText" access="remote" returntype="string" returnformat="plain">
 <cfargument name="id" type="numeric" required="yes">
 <cfargument name="msg" type="string" required="Yes">

 <cfset var q = "">
 <cfset var stSuccess={}>
 <cfquery name="q">
  select * from transaction where transactionid=<cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#">
 </cfquery>
 <cfhttp
   username="[twilio user id]"
   password="[twilio password]"
   url="https://api.twilio.com/2010-04-01/Accounts/[twilio account id]/SMS/Messages" method="post">
     <cfhttpparam name="From" value="[twilio phone num]" type="formfield">
     <cfhttpparam name="To" value="#q.phone#" type="formfield">
     <cfhttpparam name="Body" value="#arguments.msg#" type="formfield">
 </cfhttp>
 <cflog file="twilio" text="#cfhttp.FileContent#">
 <cfset stSuccess= {success: true}>
 <cfreturn serializeJson(stSuccess)>
</cffunction>

<!--- generate TwiMl --->
<cffunction name="playMsg" access="remote" returntype="xml" returnformat="plain">
  <cfargument name="id" type="numeric" required="yes">
  <cfargument name="msg" type="string" required="yes">
  <cfset var q = "">
  <cfset var out = "">
  <cfset var lang="">

  <cfquery name="q">
    select *
    from transaction
    where transactionid=<cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#">
  </cfquery>
  <cfset lang = q.nativeLanguage>
  <cfif listfind("en,es,fr,it,de",lang) is 0>
    <cfset lang="en-gb">
  </cfif>
  <cfxml variable="twiml">
    <cfoutput>
     <Response>
       <Say loop="0" voice="woman" language="#lang#">
          #xmlFormat(arguments.msg)#
       </Say>
     </Response>
    </cfoutput>
 </cfxml>
 <cfreturn twiml>
</cffunction>
<!--- call the user and read from a TwiML generated script --->
<cffunction name="sendCall" access="remote" returntype="string" returnformat="plain">
   <cfargument name="id" type="numeric" required="yes">
   <cfargument name="msg" type="string" required="Yes">
   <cfset var q = "">
   <cfset var stSuccess={}>

   <cfquery name="q">
     select *
     from transaction
     where transactionid=<cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#">
   </cfquery>

    <cfhttp
      username="[twilio user id]"
      password="[twilio password]"
      url="https://api.twilio.com/2010-04-01/Accounts/[twilio account id]/Calls" method="post">
       <cfhttpparam name="From" value="+15045951048" type="formfield">
       <cfhttpparam name="To" value="#q.phone#" type="formfield">
       <cfhttpparam name="Url" value="http://webapps.figleaf.com/wallet/transaction.cfc?method=playMsg&id=#arguments.id#&msg=#urlencodedformat(arguments.msg)#" type="formfield">
    </cfhttp>
    <cflog file="twilio" text="#cfhttp.FileContent#">
    <cfset stSuccess= {success: true}>
    <cfreturn serializeJson(stSuccess)>
 </cffunction>

To the Victor goes the Spoils

shinySo we got the app produced and debugged to the point where we could demonstrate all of the core functionality within a frenetic 6 hour period. After our allotted two minute (!) presentation that seemingly went by in about two seconds, we sat down and waited for the results. The folks from Nokia were kind enough to award us a new phone and nice tote bag for our efforts. I was happy to add a Microsoft device to Fig Leaf’s burgeoning collection of mobile test devices.

And then I went home and passed out for four hours from exhaustion.

You can try out the app at http://webapps.figleaf.com/wallet on your mobile device or by using Google Chrome on your PC (note that the Twilio features are disabled as we’re using a test account). Not too bad for 6 hours of frantic coding!

Making Sencha Touch + PhoneGap iOS Apps Available to Beta Testers

This is part 4 of a 4 part series.

After you’ve successfully compiled your app in XCode, you’ll want to make it available to beta testers. There are three methods that you can use to accomplish this.

1) Use an Ad-Hoc Distribution Method
2) Use an Ad-Hoc Distribution Method in combination with the TestFlight service to facilitate “over-the-air” (OTA) installs
3) Register for Apple’s iOS Enterprise Developer Program and distribute your app “over-the-air”

Using the Ad-Hoc Distribution Method

The Ad-Hoc distribution method enables testers to install your app on up to 100 devices.  You’ll need to use this technique if you aren’t a member of the iOS Enterprise Developer Program ($299 annual fee). Users will need to email you their device’s UDID so that you can enter them into the provisioning portal.

Using this distribution method involves completing the following steps:

  1. Acquire the UDID of the beta-tester’s device
  2. Registering devices with the Provisioning Portal
  3. Create a distribution certificate, if none exists
  4. Create an Ad-Hoc Distribution Provisioning Profile
  5. Build an App Archive
  6. Code-sign the app using the Ad-Hoc Provisioning Profile
  7. Post the app to a webserver for download.

Acquiring a Test Device’s UDID

The steps that a user must perform to retrieve a device’s UDID are as follows:

  1. Tether the device to their laptop/desktop computer. iTunes should automatically launch.
  2. Click on the Devices button in iTunes (illustrated by Step 1, below)
  3. Click on the tethered device (illustrated by Step 2, below)
  4. Click on the Serial Number (step 3) – note that this is actually an invisible button. And no, I’m not making this up. The serial number will magically transform into the device’s UDID.
  5. Right-click on the UDID and select Copy Identifier (UDID). This will place the UDID onto the user’s clipboard.
  6. Paste the UDID into an email and send to the app developer.

itunes

Registering a Device with the Provisioning Portal

Once you, as the developer, have the beta-tester’s device’s ID, you should perform the following steps:

  1. Log into the provisioning portal
  2. Click on the Certificates, Identifiers & Profiles link
  3. Click on the Devices link
  4. Click on the [+] to register a test device. Enter the a description of your tester’s device, and paste the UDID that they sent to you in an email.

a3

Creating a Distribution Certificate

If you haven’t already done so, you’ll need to create a distribution certificate  as described by the following steps:

  1. Click on Certificates > Distribution
  2. Click the [+] to add a new certificate
  3. Select Distribution > App Store and Ad Hoc
  4. Click Continue
  5. Follow the steps to create a certificate signing request (CSR). Click Continue.
  6. Select your CSR and click Generate
  7. Click the Download button to download your certificate
  8. Double-click on your downloaded certificate to install it into KeyChain Access.

Creating an Ad-Hoc Provisioning Profile

  1. Return to the provisioning portal
  2. Click on Provisioning Profiles > All
  3. Click the [+] button
  4. Click on Distribution > Ad Hoc as illustrated below:Adhoc
  5. Click Continue
  6. Select your App ID and click Continue
  7. Choose your iOS Distribution certificate and click Continue.
  8. Choose the devices that you want to use for testing your app as illustrated below:devices
  9. Click Continue
  10. Name the profile as illustrated below and click Generate.adhoctest
  11. Download the resulting .mobileprovision file and then double-click to install it into XCode Organizer

Building an App Archive

You must now compile your app into a .ipa file by completing the following steps:

  1. Open your project in XCode
  2. On the Project Summary tab, illustrated below, enter a version number for your app (typically 1.0)a4
  3. Click on the Build Settings tab
  4. As illustrated below, verify that your Code Signing Identity for app Release is set to the distribution certificate contained in your Ad Hoc Testing provisioning file.a5
  5. Choose Product > Archive from the XCode menu. After you are prompted to code sign, your archived app should appear in Organizer as illustrated below. Note: If you get a build error “Command /usr/sbin/chown failed with exit code 1”, this indicates that you have a permissions issue with your xcode project directory. You can fix this by issuing the following command:
    sudo chown -R [your osx account] [xcode project foldername]

    e.g.

    sudo chown -R stevedrucker notifications

    a6

Distributing the App

  1. In Organizer, click on the Distribute button
  2. Click Save for Enterprise or Ad-Hoc Deployment
  3. Click Next
  4. Select your Ad-Hoc Testing Code Signing Identity and click Next. Your application will be codesigned.
  5. As illustrated below, click on the Save for Enterprise Distribution checkbox and fill in the URL of where you intend to post the app.a7
  6. Click Save.
  7. This will generate a .ipa file and a .plist file.
  8. Upload the .ipa file and .plist file to your web server.
  9. Configure your web server to support the following mime types:
    .ipa   application/octet-stream
    .plist application/xml
  10. Create an HTML page that contains a link that the user can click on in order to install the app. The hyperlink should be similar to the following:
    <a href="itms-services://?action=download-manifest&url=http://training.figleaf.com/FigLeafNotifications.plist">Click here to download app</a>
    

Using a Third-Party Distribution Service

If you don’t have a webserver from which to distribute your app to testers, you can use a third-party service, such as TestFlight. TestFlight enables you to upload your ad-hoc provisioned app and generates a URL from which your testers can download and install the app. It also provides reporting metrics on who has installed the app, as well as notifies your testers whenever an update is available. It also enables you to revoke access to builds. By integrating the TestFlight API into your app, you can also quickly add customer feedback and review metrics on usage activity and crashes.

a9

In order to use TestFlight, your testers must download and install the TestFlight app. While the installation process is quite smooth, you should send a note to your testers informing them of this requirement.

Distributing to an Internal Enterprise

Clearly, the major sticking point with the aforementioned procedures is Apple’s requirement that you register the UDID of each test device. You can bypass this requirement by applying to Apple’s iOS Enterprise Developer Program. Membership in this program enables you to generate an “in-house” provisioning file that does *not* require registration of test devices.

a10

Once you have generated an In House provisioning file and installed it into XCode, you can complete the steps described previously under the heading “Distribute your App”, but use your in-house credential instead of an ad-hoc credential to code-sign the app.

Now that wasn’t too complicated, was it?

If you need help with your project or would like to be trained in the fine art of app development, please contact us at info@figleaf.com

Fire the Photons! Animating Sprites in Sencha Touch 2.2

boldlygo

Sencha Touch 2.2 contains a cross-device compatible canvas/svg drawing package that enables you to easily produce some really nice sprite-based animations.

Instantiating a Draw Component

Instantiate a draw component (xtype: ‘draw’) as illustrated below. Note that while the Ext.draw.Component class inherits from Ext.Container, docking components in a draw component directly exposes an animation bug that I reported to Sencha this morning.

Draw components are transparent by default, so you’ll probably want to set a background color on the parent container as illustrated below.

Ext.define('SpriteTest.view.Main', {
 extend: 'Ext.Container',
 xtype: 'main',
 requires: [
  'Ext.TitleBar',
  'Ext.Toolbar',
  'Ext.draw.Component',
  'SpriteTest.view.Photon' // torpedo to be added later
 ],

 config: {
  style: 'background-color: black',
  layout: 'fit'
 },

 photonTube: 0,

 initialize: function() {
  this.setItems(
   [{
     xtype: 'titlebar',
     title: 'Boldly Go...',
     docked: 'top'
    }, {
     xtype: 'draw',
     itemId: 'space'
    }, {
     xtype: 'toolbar',
     docked: 'bottom',
     layout: { pack: 'center' },
     items: [{
              xtype: 'button',
              text: 'Fire!'
            }]
     }
   ])
 }
});

Extending a Sprite Class

Sencha Touch supports the following types of sprites:

  • Arc
  • Circle
  • Composite
  • Ellipse
  • EllipticalArc
  • Image
  • Instancing
  • Path
  • Rect
  • Sector
  • Text

Sprites use a slightly different class system than the rest of Sencha Touch. You configure default values and custom properties using the syntax described in the following example:

Ext.define('SpriteTest.view.Photon', {
 extend: 'Ext.draw.sprite.Image',
 alias: 'sprite.photontorpedo',

 inheritableStatics: {
  def: {
   processors: { // define custom properties
    photonTube: 'string'
   },
   defaults: {  // configure default properties
     src: 'resources/images/photon.png',
     width: 150,
     height: 150,
     photonTube: '0'
   }
  }
 },

 constructor: function() {
   this.callParent(arguments);
   /* call custom code here */
 }
});

While other classes in Sencha Touch wrap configurable properties in a config block, sprites define their configs and defaults using very different syntax. Also, getters and setters are *not* automatically created in this construct.

Adding Sprites to a Draw Component

Technically, you don’t really add Sprites to a draw component. You actually add sprites to the “surface” that is instantiated by the draw component. The draw component’s surface is either an abstraction of an HTML5 canvas (on iOS platforms) or SVG (non-iOS platforms).

The following code snippet builds out the SpriteTest.view.Main class “Fire!” button described above.

{
 xtype: 'button',
 text: 'Fire!',
 scope: this,
 handler: function(b, e) {

  var surface = this.down('#space').getSurface();

  surface.add({
   type: 'photontorpedo',
   surface: surface,
   photonTube: this.photonTube
  });

  if (this.photonTube == 0)
   this.photonTube = 1;
  else
   this.photonTube = 0;
 }
}

Animating Sprites

You can change the appearance of a sprite in a single frame by modifying its attributes via the sprite.setAttributes() method and then subsequently calling the surface.renderFrame() method as illustrated below:

var component = new Ext.draw.Component();
Ext.Viewport.setLayout('fit');
Ext.Viewport.add(component);
var mySprite = component.getSurface().add({
    type: 'text',
    x: 50,
    y: 50,
    text: 'Fig Leaf Software Rulez',
    fontSize: 18,
    fillStyle: 'blue'
});
mySprite.setAttributes({
    x: 100,
    y: 100
});
component.getSurface().renderFrame(); // apply all changes

What is not generally understood, however, is that you can animate a sprite by modifying a sprite’s fx property, which functions as a pointer to an instance of the Ext.draw.modifier.Animation class. Here you can set a time duration (in ms) over which changes to sprite attributes will be gradually applied. You can also define an event listener that is fired once the animation has completed executing.

This technique is illustrated by the fire() method of the photon torpedo class, listed below:


Ext.define('SpriteTest.view.Photon', {
 extend: 'Ext.draw.sprite.Image',
 alias: 'sprite.photontorpedo',

 inheritableStatics: {
  def: {
   processors: {
    photonTube: 'string'
   },

   defaults: {
    src: 'resources/images/photon.png',
    width: 150,
    height: 150,
    photonTube: '0'
   }
  }
 },

 constructor: function() {
  this.callParent(arguments);
  this.fire();
 },

 fire: function() {
  var surface = this.config.surface;
  var stageWidth = surface.element.getWidth(true);
  var stageHeight = surface.element.getHeight(true);

  var centerX = stageWidth / 2;
  var centerY = stageHeight / 2;

  // start from left or right of the draw component view?
  switch (this.config.photonTube) {
   case 0:
    this.setAttributes({
     x: -150,
     y: stageHeight
    });
    break;

    case 1:
     this.setAttributes({
      x: stageWidth,
      y: stageHeight
     });
     break;
  }
  
  // set animation time to complete (1.5 seconds)
  this.fx.setDuration(1500);

  // set animation transition
  this.fx.setEasing('easeOut');

  // set animation callback
  this.fx.on('animationend',this.onAnimationEnd, this);

  // apply changes to sprite, over 1.5 seconds

  this.setAttributes({
    x: centerX - 20,
    y: centerY - 20,
    rotationRads: 3,
    width: 40,
    height: 40
  });
 },

 onAnimationEnd: function(animation) {
  this.destroy();
 }
});

What are you waiting for? Go get your ‘pew-pew’ on!

And don’t forget to contact Fig Leaf Software for all of your Sencha-related consulting and training needs!

Building a Notification App for iOS with Sencha Touch and PhoneGap – Part 1 of 4

Push it….Push it real good!

At Fig Leaf Software, we’re seeing increased demand to add push notifications to our customer’s mobile apps. Push notifications are a great way to notify your customer base about important events.

While Sencha Touch 2.x directly supports push notifications through its Ext.device.Push class,  as of this writing, its support is limited to iOS. We therefore opted to use a PhoneGap-based solution, described below, that supports both iOS and Android in order to support a broader audience.

(click here if you didn’t get the salt & pepa reference above)

  • Part I of this tutorial focuses on using Apple’s developer portal to generate the required certificates necessary for app compilation and testing. It also describes how to prepare a PhoneGap project to support push notifications.
  • Part II of this tutorial focuses on using PHP on a test server for sending push notifications to Apple. (coming soon!)
  • Part III of this tutorial describes how to integrate the PhoneGap Push Notifications plugin with your Sencha Touch application. (coming soon!)
  • Part IV of this tutorial describes how to make your application available to beta testers

Prerequisites

This tutorial assumes that you have procured an iOS developer account ($99 USD) and that you’re working with Sencha Touch 2.2+ and Sencha Cmd 3. You’ll also need a physical iOS device (I used an iPod Touch) and tethering cable, since notifications are not supported by the iOS simulator. No prior experience with compiling a Sencha Touch app is necessary to complete this tutorial.

PART I: Download the required software

  1. Download and install XCode
  2. Download PhoneGap 2.50
    Note: Sencha Touch seems to have some difficulties with Phonegap > 2.50
  3. Download the Cordova PushNotification Plugin
  4. Download the Cordova openUDID plugin
    Note: This is used by the Cordova PushNotification plugin
  5. PHP for OS/X, which you can enable by following these instructions.

Part II: Generate a Development Cert for your App

  1. Log into the iOS provisioning portal
  2. Click the link for Certificates, Identifiers, and Profiles
  3. In the iOS Developer Portal, click on Certificates
  4. Click on the [+] button
  5. Select iOS App Development and click Continue
  6. Follow the on-screen instructions to create a CSR file and click Continue.
  7. Click Choose File and select the CSR file that you created in the previous step.
  8. Click the Generate button.
  9. Click the Download button
  10. Double-click on the .cer file to install it into Keychain Access
  11. Return to the iOS Developer portal and click the Add Another button.

PART III: Register your App with the iOS Provisioning Portal

  1. Log into the iOS provisioning portal
  2. Click the link for Certificates, Identifiers, and Profiles
  3. Click on Certificates
  4. Click on App Ids
  5. Click on the [+] to define a new App ID
  6. Fill out the form:
    1. Enter an App ID Description, e.g. ‘Fig Leaf Software Notifications’
    2. Under the App Services heading, check the box labeled “Push Notifications”
    3. Enter a bundle id  in reverse domain style, e.g. ‘com.figleaf.notifications’
  7. Click the Continue Button
  8. Click the Submit Button. Your App’s definition should resemble the following:
    Registering an App

Part IV: Create a Push Notification Development Certificate

This is used by your server to communicate with Apple’s Push service. Each app will have its own development and production push notification SSL certificate.

  1. Click back on App IDs and  select your app. Note that the items labeled Push Notifications are marked as “Configurable” as illustrated below:flsnotifications
  2. Click the Settings button. At the bottom of the screen, under the Push Notifications heading, you should see output similar to the following:a1
  3. Click on the Create Certificate button under the Development SSL Certificate.
  4. Go through the process to generate the certificate.
  5. Click on App IDs
  6. Click on your application
  7. Click on the Settings button
  8. Click on the Download button to download the Development SSL Certificate for Push Notifications
  9. Double-click on the certificate that you downloaded in the prior step in order to install it into KeyChain Access.

Part V: Registering Test Devices and Defining a Provisioning Profile

  1. Open XCode
  2. Tether your iOS device to your computer.
  3. Select Window > Organizer
  4. Click on the Devices tab.
  5. In the Devices column, click on your device. Organizer should appear similar to the following:organizer
  6. Copy the device’s identifier to your clipboard
  7. Return to the iOS Provisioning portal in your browser.
  8. Click on Devices.
  9. Click on the [+] to register your device.
  10. Register your device as illustrated below:
    AddIOSDevice
  11. Click Continue
  12. Click on the Provisioning Profiles link
  13. Click the [+] to add a new Provisioning Profile
  14. Click the Radio button labeled iOS App Development
  15. Click Continue
  16. Select your App from the select list and click Continue.
  17. Choose your iOS Development Certificate and click Continue.
  18. Choose your device and click Continue
  19. Enter a name for your profile, e.g. Notification App Testing
  20. Click the Generate button.
  21. Click the Download button.
  22. Double-click on the downloaded mobileprovision file to install it into KeyChain access.

Part VI: Create a Phonegap Project

  1. Unzip PhoneGap to a temporary directory
  2. Create a folder in your webroot named Cordova
  3. Copy PhoneGap’s lib/ios folder to webroot/Cordova. This should give you a /webroot/Cordova/ios folder.
  4. Open a command prompt to /webroot/Cordova/ios/bin
  5. Type the following command to generate an Xcode project:
    sudo .create [path to project folder] [application bundle id] [application name]
    

    e.g.:

    sudo .create ../../notifications com.figleaf.notifications FigLeafNotifications
    
  6. Using Finder, set read/write permissions on the generated project folder and all of its files.
  7. Verify that your project folder resembles the following:notificationprojfolder

copying

Part VII: Install the PhoneGap Notification Extension into your XCode Project

  1. Double-click on your .xcodeproj file to launch Xcode.
  2. Unzip the Cordova Push Notification Plugin that you downloaded in Part I/Step 3 into a temporary folder.
  3. Rename the Cordova Push Notification Plugin’s src/ios folder to ‘PushNotification’
  4. Drag and drop the ‘PushNotification’ folder from finder into your project’s ‘Plugins’ folder in XCode. When prompted, select ‘Create groups for any added folders’
  5. Copy the Cordova Push Notification Plugin’s www/PushNotification.js file into your Xcode project’s www folder.
  6. In XCode, open your project’s config.xml file.
  7. Add the following entry to the file’s plugins section:
    <plugin name="PushNotification" value="PushNotification" />
  8. In XCode, open classes/AppDelegate.h
  9. Append the following line just below the other imports:
    #import "PushNotification.h"
    
  10. In XCode, open classes/AppDelegate.m
  11. Append the following code just before the @end statement located at the end of the file:
     #pragma - PushNotification delegation
    
        - (void)application:(UIApplication*)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
        {
            PushNotification* pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
            [pushHandler didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
        }
    
        - (void)application:(UIApplication*)app didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
        {
            PushNotification* pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
            [pushHandler didFailToRegisterForRemoteNotificationsWithError:error];
        }
    
        - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
        {
            PushNotification* pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
            NSMutableDictionary* mutableUserInfo = [userInfo mutableCopy];
    
            // Get application state for iOS4.x+ devices, otherwise assume active
            UIApplicationState appState = UIApplicationStateActive;
            if ([application respondsToSelector:@selector(applicationState)]) {
                appState = application.applicationState;
            }
    
            [mutableUserInfo setValue:@"0" forKey:@"applicationLaunchNotification"];
            if (appState == UIApplicationStateActive) {
                [mutableUserInfo setValue:@"1" forKey:@"applicationStateActive"];
                [pushHandler didReceiveRemoteNotification:mutableUserInfo];
            } else {
                [mutableUserInfo setValue:@"0" forKey:@"applicationStateActive"];
                [mutableUserInfo setValue:[NSNumber numberWithDouble: [[NSDate date] timeIntervalSince1970]] forKey:@"timestamp"];
                [pushHandler.pendingNotifications addObject:mutableUserInfo];
            }
        }
    
    
  12. Add the following block inside the ‘- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions’ function,  just before the return YES.
       // PushNotification - Handle launch from a push notification
        NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
        if(userInfo) {
            PushNotification *pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
            NSMutableDictionary* mutableUserInfo = [userInfo mutableCopy];
            [mutableUserInfo setValue:@"1" forKey:@"applicationLaunchNotification"];
            [mutableUserInfo setValue:@"0" forKey:@"applicationStateActive"];
            [pushHandler.pendingNotifications addObject:mutableUserInfo];
        }
    
  13. Unzip the Cordova openUDID plugin that you had previously downloaded into a temporary folder.
  14. Drag and drop the OpenUDID.h and OpenUDID.m files into your XCode project’s Classes folder.
  15. In XCode, open www/index.html and add the following <script> tag after the <script> tag that loads cordova-2.5.0.js:
    <script type="text/javascript" src="PushNotification.js"></script>
    
  16. Select your device from the list of test devices as illustrated below:xcode
  17. Click the Run button. The app should compile successfully and install to your device.

— End —

Tips for Running Microsoft’s Windows Phone 8 Emulator in VMWare

Now that Sencha Touch supports Windows Phone 8, I thought that I’d give one of my new apps a whirl in Microsoft’s Simulator to see how well it worked.

Of course, as is frequently the case with products from Mr. Softie, things are never as easy as they seem – particularly when running their products on a mac.

First and foremost, you’ll need to purchase Windows 8 Professional 64-bit…and a machine with at least 8 GB of RAM (I’m running a 13″ Macbook Air)

Install Windows 8 into a new VM with the following settings:

  • Disk space: 30 GB (~20 GB will be used by the OS and Microsoft Vis Studio)
  • Memory: 3.5GB
  • CPU: 2 Cores (minimum)

After completing the installation process for Win 8, shut it down, go into your VM settings and select the following:

  • Settings > CPU and Memory > Advanced > Enable hypervisor applications (checked)
  • Settings > Advanced > Preferred virtualization engine: Intel VT-x with EPT
  • General > OS > Hyper-V (unsupported)

Next, launch Windows and install the Microsoft Windows Phone SDK from the following URL:

http://dev.windowsphone.com/en-us/downloadsdk

Once the SDK (which includes Visual Studio Express) has been installed and licensed, you can launch the emulator by running Visual Studio Express 2012 for Windows Phone, creating a new Windows Phone 8 project, and then clicking on the Emulator WVGA 512MB button. 

By default, your hardware keyboard is disabled in the emulator. Enable the hardware keyboard by selecting VMware Fusion > Virtual Machine > Send Key > Pause Key.

Conversely, you can disable keyboard support in the emulator by repeating the enablement steps.

From the emulator, you can browse your web server in OSX via your OS/X IP Address (System Preferences > Network)

Happy testing!!!