Updating to AIR 2.0 Barriers

Now that Adobe 2.0 is released it’s time to update some older apps to use the new APIs.
The process to update seems kind of complicated and definitely worth a blog post. In my special case I am upgrading from an self signed 1.5.2 app to a self signed 2.0 app.

Since 1.5.3 the publisherID works differently so you have to add the publisherID to the XML descriptor like also described here. If you are not using EncryptedLocalStore you might be fine by now but otherwise you get this error when you debug the application: EncryptedLocalStore may not use publisher IDs passed in from ADL

A quick search lead me to add the publisherID to the debug configuration but then you get the error that the publisherID can’t be passed anymore by ADL since 1.5.3, damn.

More research brought me to this forum thread. So it looks like this bug is in the AIR 2.0 final so the only solution is to remove the publisherID from the descriptor while debugging the application. Before packaging the app you then have to add it to not break the update for your users who still have the older version of your app.

Ok, I removed the publisherID and finally could run my app with AIR 2.0, not! My next runtime exception is TypeError: Error #1034: Type Coercion failed: cannot convert flashx.textLayout.formats::TextLayoutFormat@184eb041 to flashx.textLayout.formats.TextLayoutFormatValueHolder.

Solution is to change TextLayoutFormat to TextLayoutFormatValueHolder like here:

var cfg : Configuration = TextFlow.defaultConfiguration;
var normalTLF : TextLayoutFormat = new TextLayoutFormat( cfg.defaultLinkNormalFormat );
cfg.defaultLinkNormalFormat = normalTLF;

to

var normalTLF : TextLayoutFormatValueHolder = new TextLayoutFormatValueHolder( cfg.defaultLinkNormalFormat );

Now I can finally run the app with AIR 2.0 without any runtime exceptions or other errors, uhh!
The TextArea default height seems to have changed though but that’s for another time.

Swiz Yahoo Finance Metadata Processor

Swiz 1.0 alpha introduced a very cool new feature which lets you extend Swiz be creating custom metadata processors.
This means that if you want to add a metadata like [MyCustomMetadata] you can now do so and Swiz offers you a very easy way to implement it.
For the Swiz 360 Flex demo app I have build a proof of concept YahooFinance metadata processor. The idea was to have something like this:

[YahooFinance(tickerSymbol="ADBE", days="60")]
public var adobeStocks:IList;

When you annotate the list variable with that metadata the YahooFinanceProcessor gets notified to process it and for the case above fetches the Adobe stock data for the last 60 days. The result is a list of objects which contain a date and a price. You can then bind this list to a chart é voilá, your chart shows live fetched data without writing any code (ok, except declaring the variable).

Here the full source of the view component:

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx">
 
	<fx:Script>
		<![CDATA[
			import mx.collections.IList;
 
			[Bindable]
			[YahooFinance(tickerSymbol="ADBE", days="60")]
			public var adobeStocks:IList;
 
			[Bindable]
			[YahooFinance(tickerSymbol="MSFT", days="60")]
			public var microsoftStocks:IList;
		]]>
	</fx:Script>
 
	<s:layout>
		<s:VerticalLayout/>
	</s:layout>
 
	<s:Label text="Stock Prices last 60 days" />
	<mx:LineChart id="chart" width="100%" height="100%" showDataTips="true" dataProvider="{adobeStocks}">
		<mx:horizontalAxis>
			<mx:CategoryAxis categoryField="date" title="Time" />
		</mx:horizontalAxis>
		<mx:verticalAxis>
			<mx:LinearAxis title="Price" baseAtZero="false" />
		</mx:verticalAxis>
 
		<mx:series>
			<mx:LineSeries dataProvider="{microsoftStocks}" displayName="Microsoft" xField="date" yField="price" />
			<mx:LineSeries dataProvider="{adobeStocks}" displayName="Adobe" xField="date" yField="price" />
		</mx:series>
	</mx:LineChart>
	<mx:Legend dataProvider="{chart}" />
 
</s:Group>

The result looks like this:

When you have a look at the source of the YahooFinaceProcessor you see how easy it is to build.

The example also shows how to use the MediateSignalProcessor build by Sam Ahn.
There are also a bunch of other custom metadata processors on the way like the ResourceProcessor also by Sam.
Note that I had to add -keep-as3-metadata+=YahooFinance which you have to do for any new metadata you introduce.

Running Project Sprouts

A few weeks ago I attended the SanFlashCisco usergroup meeting which was really great. After the meeting we moved to the Mars bar where I got to know Luke Bayes who founded Project Sprouts. Project Sprouts is a Ruby based open-source, cross-platform project generation and configuration tool for ActionScript 2, ActionScript 3, Adobe AIR and Flex projects. Also be sure to check the the GitHub repository.

The following works on a Mac with Ruby and RubyGems installed but should be similar under Windows. Open the Terminal, switch to your working directory where you want to create your new project and:

# installs project sprouts
sudo gem install sprout
# creates a new Flex 4 project named SproutsExample
sprout -n flex4 SproutsExample
# switch directory
cd SproutsExample
# build the project
rake

Now you see all dependencies like SDK and Flash Player being downloaded. So you can run this on a machine without Flex SDK and Flash Player installed because Sprouts handles all dependencies. However, I got this error:

/Library/Ruby/Gems/1.8/gems/sprout-flashplayer-bundle-10.22.7/lib/clix_wrapper.rb:20:  (RuntimeError)
[ERROR] You must install the rb-appscript gem to use the desktop debug Flash Player, you do this by running: sudo gem install rb-appscript

As being told I tried to run: sudo gem install rb-appscript which ended up in this error:

ERROR:  Error installing rb-appscript:
ERROR: Failed to build gem native extension.
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb
mkmf.rb can't find header files for ruby at /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/ruby.h

After a little web search I found out that I need to install the latest XCode since I am on Snow Leopard.

Having XCode installed I tried again sudo gem install rb-appscript and it works!

So another try with rake and horray, the project gets compiled and the standalone flash player comes up showing the compiled default project!

So far so good. Now let’s try to create a class and a unit test for it.
Due to a little bug in the flex 4 gem edit scripts/generate and replace

 begin
      Sprout::Sprout.generate('flex4', ARGV.shift, ARGV, File.dirname(File.dirname(__FILE__)))
    rescue RubiGen::GeneratorError =&gt; e
      Sprout::Sprout.generate('as3', ARGV.shift, ARGV, File.dirname(File.dirname(__FILE__)))
    end

with

Sprout::Sprout.generate('as3', ARGV.shift, ARGV, File.dirname(File.dirname(__FILE__)))

btw: when the fix for this is in place update with

sudo gem update sprout-flex4-bundle

So, now you are ready to create a class including test classes:

# creates the class com.soenkerohde.util.MathUtil and test classes
script/generate com.soenkerohde.util.MathUtil

You see the output

create  src/com/soenkerohde/util
create  src/com/soenkerohde/util/MathUtil.as
create  test/com/soenkerohde/util
create  test/com/soenkerohde/util/MathUtilTest.as
force  test/AllTests.as
# Run the tests
rake test

Now you see your tests compiling and they fail for now to remind you that you haven’t implemented the actual test code yet.

Pretty impressed by Sprouts so far but enough for now. In my next post I will try to go a little bit deeper and check what else Sprouts can do for me to not waste time on what can be automated.

360 Flex Swiz Birds of a Feather

Thanks to all who joined the Swiz BOF session at 360 Flex in San Jose today.

John Yanarella and I got the opportunity to show Swiz and some examples. We even had Chris around via Skype and I hope you guys enjoyed it!

Here the links to the slides and code:

Many thanks to John Wilker for organizing this great conference and inviting us to talk. 360 Flex is a great event so if you missed it make sure to attend next time when it’s around!

Powerful Cancelable Events

When you dispatch events I bet that most Flash/Flex devs don’t take advantage of the fact that dispatchEvent returns a Boolean value indicating wether or not the event has been canceled. Normally your code looks similar to this:

var event:MyEvent = new MyEvent(MyEvent.FOO);
dispatchEvent(event)

If you want to let something only happen if the event wasn’t canceled it should look like this:

// The second "true" sets the event cancelable, first one sets bubbles
var event:MyEvent = new MyEvent(MyEvent.FOO, true, true);
if(dispatchEvent(event)){
   // do the actual task
}

With the code above the event listener can control if the actual task gets executed or not:

dispatchingInstance.addEventListener(MyEvent.FOO, fooHandler);
function fooHandler(event:MyEvent):void{
   // depending on what you want to achieve you can cancel the event by calling preventDefault
   event.preventDefault();
   // this will cause dispatchEvent to return false so the actual task doesn't get executed
}

A real life usecase for UI related events could be dispatching an event before closing a popup window:

function closeButtonHandler(event:Event):void{
   if(dispatchEvent(new MyWindowEvent(MyWindowEvent.CLOSE, true, true)){
      PopUpManager.closePopup(this);
   }
}

Cancelable events are also very interesting when you develop APIs because it offers powerful and easy to use hooks for the API user.
I am making heavy use of cancelable events in my swizdesktop lib. Catching the different update phase events you get hooks to stop the update process by calling preventDefault on the listened event.

Connecting Pivotal Tracker with GitHub

GitHub with Pivotal Tracker is the killer agile combination.
With the just release Tracker v3 API update it is now easy to connect them.

You only have to configure GitHub Post-Receive Hooks so you can automatically deliver stories/bugs by providing the Tracker ID in the commit statement like: Fixes #TrackerId

How to set it up:

  1. Create a Pivotal Tracker API token: Login to PT -> My Profile -> Create New Token
  2. GitHub -> Project -> Admin -> Service Hooks -> Post-Receive URLs
  3. Paste https://www.pivotaltracker.com/services/v3/github_commits?token=YOUR_TOKEN_FROM_STEP_1

Now that was easy!