Convincing developers that Adobe Flex rocks on Android, iOS, and PlayBook

On April 11th, Adobe announced that Creative Suite 5.5 will ship within 30 days.  Among the long list of amazing new capabilities and features across all of the CS5.5 products is something that really stands out to us developers — Flash Builder 4.5.  This is a monumental release of Flash Builder because when this ships in early May, developers will be able to build Flex apps for mobile devices!  The initial ship will support Android devices, but just a few weeks later (June), we will update Flash Builder to also support iOS (iPhone, iPad) and BlackBerry PlayBooks!

Imagine a world…

Imagine a world where developers can build awesome apps for the web, desktop (Windows, Mac OS X, Linux) and a huge majority of the mobile device market.  Imagine tooling that supports building, testing, and deploying these apps to all of these platforms and devices.  Imagine being able to share and reuse code from platform to platform/device to device!

I’m coming dangerously close to sounding like a marketing guy so I’ll stop there…but you have to admit, the vision is exciting to imagine… but do you really believe it? Keep reading.

Yes, it’s real

Many of you have heard us talking about the above vision for a long time.  I’m thrilled to tell you that the vision is now real.  It’s not smoke and mirrors.  It’s not clever click-thru demos.  It’s the real deal and it’s done VERY well.

The “Wow” process

Our job as technical evangelists is to prove to you that this stuff works and strive to be experts before you ever get your hands on the technology so we can answer your questions.  This forces us to live on the bleeding edge of builds from our engineering teams.  During the past 3 months, I’ve probably installed at least 10 different builds of Flash Builder 4.5 (in addition to many other products I evangelize)!  About 5 weeks ago, we started getting builds that we felt were ready to take “on tour” so we hit the road and went to show it off to some key customers and a few user groups.  Developers are never truly convinced until they get their hands on the technology and try it for themselves, and based on the results so far, developers are starting to be convinced!

The biggest surprise to developers (including myself) is the performance of Flex apps on iOS devices.  During the past several meetings with customers and user groups, I’ve passed around my iPad, iPod Touch, and various Android devices and let people interact with the apps.  Here are some typical comments and some frequently asked questions (my answers are in parenthesis).  Every one of these is a near exact quote that I’ve heard in the past 5 weeks.

  • Wow – the performance shocks me!” (me too!)
  • I didn’t know you guys could build apps for iPhone/iPad” (Yep – and also Android and BlackBerry PlayBook and of course desktop and web!  There were some changes to the Apple developer rules in September, 2010 that allows developers to use non-Apple tools to build apps for iOS devices.  This allowed us to expand our mobile strategy to include iOS in our growing list of supported platforms.)
  • I thought Flash wasn’t allowed on iOS devices” (Apple still does not allow Flash Player to be installed on iOS devices for the web browser, but these are not browser apps… they are installable apps that have been cross-compiled to Objective-C bytecode. Your apps can be packaged into a standalone .ipa file, the file extension of all iOS apps.  No separate runtime is needed.)
  • What about mobile specific stuff like GPS, accelerometer, and multitouch?” – (The Flex 4.5 SDK adds many mobile-specific APIs including all of those plus support for cameras, microphone, gestures, and more. — then I demo these APIs using Tour de Mobile Flex and Adobe AIR Launchpad — links below)
  • I’m surprised at the level of detail in the UI behavior… scrollable lists have a subtle bounce at the end and movement is smooth and fluid.  It feels like how I expect a mobile app to feel.” (Yep – I was surprised too! I even blogged about my own skepticism here)
  • So, I can write the app once and deploy it on iOS, Android, and PlayBook? Really?” (Yes, almost. Different devices have different screen sizes, pixel densities, aspect ratios, etc. An app that looks great on an iPad might need some tweaks to also work well on an HTC Inspire phone. An app that works great on an iPhone may need some UI tweaks to better take advantage of a tablet screen like the Motorola Xoom or a BlackBerry PlayBook. The Flex 4.5 SDK provides APIs to query screen dimensions and density so you can dynamically make UI adjustments based on the device. Also, module loading is not supported on iOS nor is loading any external SWFs that contain ActionScript. This is due to Apple’s app restrictions on loading and interpreting external code.)
  • Is it easy to convert a non-mobile app built with Flex into a mobile app?” (It depends on the app. You probably don’t want to take a million line Flex project and try to deploy it to a mobile device that has a fraction of the CPU and memory of a desktop machine. However, some apps can be modified to work on mobile devices fairly easily after some UI tweaks and adjustments to take advantage of the touch-screen environment. Either way, it will be dramatically faster than writing the app from scratch using another technology.)
  • How does Flash Builder handle iOS application signing and provisioning?” (You will still need an Apple cert and provisioning profile for your app like any other iOS app. Flash Builder prompts you for the signing cert and the provisioning profile in the build configuration. Once you have these in place, Flash Builder will create the final .ipa for you.)
  • Can I create iOS apps using a Windows machine?” (Yes, it works the same as on Mac OS X.)
  • How do I handle application auto-updates?” (It’s no different than if you used the Android SDK or Apple SDK – updates are handled through the various marketplaces/app stores based on the version number assigned. No special code is required.)
  • Do apps built with Flex perform as well as apps built with the native SDK for each platform?” (It depends on the app.  For many apps, yes it will.  For apps with very complex animations such as with intense game graphics, you might want to turn to the native SDK.)

After 20 minutes of Q&A, most developers start shifting their questions to “How do I get this so I can try it out?”.  Last week, I showed this stuff at two user group meetings – Tampa and Nashville.  Both meetings resulted in several ongoing email threads with developers who are excited to get their hands on this stuff.  Every customer visit that my team has made in the past few weeks has had similar results.

Check it out now!

Hopefully I’ve at least made you raise an eyebrow in this blog post.  Rather than rambling on and on about how others have reacted, take a look for yourself.  Below are some videos that Christophe Coenraets, James Ward, Michael Chaize, and Lee Brimelow have put together showing off Flex apps on mobile.  Each video demonstrates what I’ve been talking about.  They are short and to the point, so it’s worth going through them.

What works when

  • Shipping software availability:
    • Flash Builder 4.5 ships in a couple of weeks and includes Android support
    • An update to Flash Builder will ship in June that adds iOS and PlayBook support
  • Pre-release software availability:
    • If you join the pre-release program (see below), you can get 4.5 today with Android support
    • The pre-release site will be updated in a few days with a version that adds iOS and PlayBook support

What’s missing

Most things are ready to go now including APIs for geolocation, accelerometers, multitouch, gestures, microphone, overlaying HTML content, and more, but we are missing a few things that developers are asking for including support for notifications, APIs for compass and the ability to make native OS calls. We’ll have more details on these soon as work is progressing on multiple fronts.

How to see for yourself

If you would like to give this a try, I recommend the following steps:

  • Join the pre-release program for Flash Builder. A recent build is already available with Android support. A newer build with iOS support is coming very soon. There is also a version of Flash Builder on labs code-named “Burrito”, but it’s a bit old and missing some recent advancements. I recommend that you skip Burrito and get into the pre-release program so you can get the hot-off-the-press bits.
  • Download and install Adobe AIR Launchpad — this tool is one of the best learning resources you’ll find. It will help you create your first mobile project with well commented sample code. This is a pre-release of Launchpad 2.6 that supports the current Flash Builder pre-release
  • If you have an Android device, go install Tour de Mobile Flex on the device. It’s another great learning resource.
  • Go steal borrow every Android and iOS device you can find. Your mom can live without her iPad for a few days, right?
  • If you plan to try this on a real iOS device, you’ll need to join the Apple developer program ($99/yr) so you can get your cert and so you can provision apps.
  • If you build a cool app, contact me. I want to see it!

If you are new to Flex, here are a few additional resources:

It’s a great time to be a Flex developer and the excitement is spreading fast.  I hope this blog post inspires you to check it out!

Share

Introducing Mixing Loom – Runtime ActionScript Bytecode Modification

At this year’s 360|Flex conference in Denver, Mike Labriola and I unveiled a new project we’ve been working on called Mixing Loom. Our presentation was called “Planet of the AOPs” because Mixing Loom lays the foundation for true Aspect Oriented Programming (AOP) on the Flash Platform. Mixing Loom provides Flex and ActionScript applications the hooks they need to do bytecode modification either before runtime or at runtime. Through bytecode modification an application can apply a behavior across hierarchies of objects. There are a number of behaviors in a typical Flex application (such as logging, security, application configuration, accessibility, and styling) that could be represented as Aspects. Today these behaviors must either be included in every class that needs them or included way down the object hierarchy (i.e. UIComponent). With Mixing Loom a compiled SWF can be modified (applying necessary behaviors) after it’s been compiled or as it’s starting up.

If you are building Flex apps and want to take advantage of AOP then Mixing Loom is probably a bit lower level than what you need. Mixing Loom combined with AS3 Commons Bytecode provides the foundation for AOP systems to be built on top of. We hope that by providing developers the hooks to modify bytecode that frameworks will emerge that provide application developers higher level APIs based on AOP. As Mike says, “Mixing Loom kicks off the Summer of AOP.”

If you are one of those developers who likes getting dirty with bytecode modification then you might want to check out the slides from the “Planet of the AOPs” session:

If you are still following along and looking for more details on how to use Mixing Loom, then keep reading. Flex applications are broken into at least two pieces. The first piece is the thing that displays the loading / progress bar. That is located on the first “frame” of an application’s SWF file. The rest of the application is on the second frame of the main SWF and possibly in other SWF files like Modules and/or Runtime Shared Libraries (RSLs). Mixing Loom provides two ways to modify the bytecode of a running application. First, using a custom preloader an application can modify its second frame and/or any Flex Modules before they are loaded into the VM. The second way is to use LoomApplication and a custom preloader, which allows an application to modify its second frame, modules, and/or RSLs (even the signed Flex Framework RSLs). Let’s walk through a simple example of an application that uses a custom preloader to modify a string that exists in its second frame.

Let’s take a simple object Foo that has a getBar method, which returns a string “a bar”:

package blah
{
public class Foo
{
  public function getBar():String
  {
      return "a bar";
  }
}
}

And here is a simple application that just displays the results of calling an instance of Foo’s getBar method:

<?xml version="1.0"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark">
 
  <fx:Script>
    import blah.Foo;
  </fx:Script>
 
  <s:applicationComplete>
     var foo:Foo = new Foo();
     l.text = foo.getBar();
  </s:applicationComplete>
 
  <s:Label id="l"/>
 
</s:Application>

If you were to run this application as is then the Label would display “a bar” – as expected. But to give you an idea of how to do runtime bytecode modification let’s change the “a bar” string to something else. (BTW: If you are following along then you will need to pull down the mixingloom-core code from github and compile it on your own because we haven’t published a SWC for Mixing Loom yet.) The thing in Mixing Loom that actually does the bytecode modification is called a “Patcher” so we will need to create one of those that searches the bytecode for a string and then replaces that string. Before we do that, let me explain how a SWF file is structured. Every SWF file is a series of “tags”. There are many different tag types but the types we are interested in for bytecode modification are the ones that actually contain the ActionScript ByteCode (ABC). This is the DoABC tag – type 82. For a full list of SWF tags and their structures check out the SWF Spec. One of the tag types indicates an executable boundary called a Frame. As a SWF file is being loaded by Flash Player it is parsing it. When Flash Player parses a “ShowFrame” tag it knows it can load and run the preceding tags. The code doing the bytecode modification will be running on the first frame, which means that all of the tags to do the modification and those to display the Flex preloader will have already been loaded. That means we can’t modify those tags using this method at runtime. But we can modify the tags on the second frame of the SWF, which will be passed to our Patcher before they have actually been loaded.

Here is the code for the StringModifierPatcher:

package org.mixingloom.patcher
{
import flash.utils.ByteArray;
 
import org.as3commons.bytecode.tags.DoABCTag;
import org.as3commons.bytecode.util.AbcSpec;
 
import org.mixingloom.SwfContext;
import org.mixingloom.SwfTag;
import org.mixingloom.invocation.InvocationType;
import org.mixingloom.utils.ByteArrayUtils;
 
public class StringModifierPatcher extends AbstractPatcher
{
    public var originalString:String;
    public var replacementString:String;
 
    public function StringModifierPatcher(originalString:String, replacementString:String)
    {
        this.originalString = originalString;
        this.replacementString = replacementString;
    }
 
    override public function apply( invocationType:InvocationType, swfContext:SwfContext ):void
    {
        var searchByteArray:ByteArray = new ByteArray();
        AbcSpec.writeStringInfo(originalString, searchByteArray);
 
        var replacementByteArray:ByteArray = new ByteArray();
        AbcSpec.writeStringInfo(replacementString, replacementByteArray);
 
        for each (var swfTag:SwfTag in swfContext.swfTags)
        {
            if (swfTag.type == DoABCTag.TAG_ID)
            {
                swfTag.tagBody = ByteArrayUtils.findAndReplaceFirstOccurrence(swfTag.tagBody, searchByteArray, replacementByteArray);
            }
        }
 
        invokeCallBack();
    }
 
}
}

The StringModifierPatcher extends the Mixing Loom AbstractPatcher and takes two parameters, the originalString and the replacementString. The StringModifierPatcher has an apply method, which will be called by Mixing Loom during application startup. In the apply method the StringModifierPatcher creates a search ByteArray and a replacement ByteArray from the provided strings. Then it loops through each tag from the second frame of the SWF being loaded (ignoring everything that is not a DoABC tag) and then uses Mixing Loom’s ByteArrayUtils.findAndReplaceFirstOccurrence utility to replace the first occurrence of the search ByteArray with replacement ByteArray. Finally it notifies Mixing Loom that it is all done by calling the invokeCallBack method. So that is the simple example of actually modifying the application, but we still need to set the hooks in the main application so that Mixing Loom can do its thing.

Since this example only modifies frame 2 tags (no RSLs), we can just use a custom preloader to set up the Mixing Loom hooks. Here is the StringModifierPatcherPreloader:

package preloader {
import org.mixingloom.managers.IPatchManager;
import org.mixingloom.patcher.StringModifierPatcher;
import org.mixingloom.preloader.AbstractPreloader;
 
public class StringModifierPatcherPreloader extends AbstractPreloader {
    override protected function setupPatchers(manager:IPatchManager):void {
        super.setupPatchers(manager);
        manager.registerPatcher( new StringModifierPatcher("a bar", "not really a bar") );
    }
}
}

The StringModifierPatcherPreloader extends Mixing Loom’s AbstractPreloader and uses the setupPatchers method to register a new patcher. In this case the only patcher is an instance of the StringModifierPatcher that will search for the default “a bar” string and replace it with the “not really a bar” string.

The last thing to make this all work is to tell the main application to use the new preloader:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               preloader="preloader.StringModifierPatcherPreloader">

Here is the result:

Exciting! Our application code just modified itself at startup! Now this is obviously a very trivial example but I hope it provides a basic understanding of how to use Mixing Loom as the foundation for AOP. Let’s walk through some other examples that are more exciting (and complex).

For the next example let’s do something a little more AOP-ish. There will be an XML configuration file that is loaded on startup that will specify some classes and methods to apply interceptors to. An interceptor is simply a method call injected into the body of a method. First, here is the FooInterceptor class:

package
{
import mx.core.FlexGlobals;
 
public class FooInterceptor
{
    public static function interceptAll():void
    {
        FlexGlobals.topLevelApplication.setStyle("backgroundColor", Math.random() * 0xffffff);
    }
}
}

For demo purposes this interceptor is very simple – it just changes the application’s background color. Here is the XML configuration file that the application will load on startup to determine where to apply the interceptor:

<interceptors>
    <interceptor>
        <swfTag>blah/Foo</swfTag>
        <methodEntryInvoker>
            <className>FooInterceptor</className>
            <methodName>interceptAll</methodName>
        </methodEntryInvoker>
    </interceptor>
</interceptors>

In this case it is saying to only apply the interceptor to the SWF tag with the name “blah/Foo”. In a debug version of the application the Foo class from above will be in its own SWF tag named “blah/Foo”. The reason that the SWF tag is specified in this case is because by doing this the application won’t need to deserialize and reserialize every class. The downside to doing things this way is that it won’t work if we create an optimized SWF where all of the frame 2 classes are contained in one SWF tag. With some more work in AS3 Commons Bytecode we could optimize things for this kind of use case. Volunteers? :) The methodEntryInvoker simply specifies the class and method name to call on method entry. This interceptor will be added to every method, on every class in the SWF tag with the name “blah/Foo”.

Now for the fun part… Here is the patcher that loads the XML config file, parses it, and then applies the interceptor:

package patcher {
import flash.events.Event;
import flash.events.TimerEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.utils.ByteArray;
 
import org.as3commons.bytecode.abc.AbcFile;
import org.as3commons.bytecode.abc.InstanceInfo;
import org.as3commons.bytecode.abc.LNamespace;
import org.as3commons.bytecode.abc.MethodInfo;
import org.as3commons.bytecode.abc.Op;
import org.as3commons.bytecode.abc.QualifiedName;
import org.as3commons.bytecode.abc.enum.Opcode;
import org.as3commons.bytecode.io.AbcSerializer;
 
import org.mixingloom.SwfContext;
import org.mixingloom.SwfTag;
import org.mixingloom.invocation.InvocationType;
import org.mixingloom.patcher.AbstractPatcher;
 
import org.as3commons.bytecode.io.AbcDeserializer;
 
public class SampleXMLPatcher extends AbstractPatcher {
 
    public var url:String;
 
    private var swfContext:SwfContext;
 
    public function SampleXMLPatcher(url:String) {
        this.url = url;
    }
 
    override public function apply( invocationType:InvocationType, swfContext:SwfContext ):void {
        if (invocationType.type == InvocationType.FRAME2) {
 
            this.swfContext = swfContext;
 
            var urlLoader:URLLoader = new URLLoader();
            urlLoader.dataFormat = URLLoaderDataFormat.TEXT;
            urlLoader.addEventListener(Event.COMPLETE, handleXMLLoad);
            urlLoader.load(new URLRequest(url));
        }
        else {
            invokeCallBack();
        }
    }
 
    private function handleXMLLoad(event:Event):void {
        var xmlData:XML = new XML((event.currentTarget as URLLoader).data as String);
 
        var swfTagName:String = xmlData.interceptor.swfTag;
        var methodEntryInvokerClassName:String = xmlData.interceptor.methodEntryInvoker.className;
        var methodEntryInvokerMethodName:String = xmlData.interceptor.methodEntryInvoker.methodName;
 
        var methodEntryInvokerClassQName:QualifiedName = new QualifiedName(methodEntryInvokerClassName, LNamespace.PUBLIC);
        var methodEntryInvokerMethodQName:QualifiedName = new QualifiedName(methodEntryInvokerMethodName, LNamespace.PUBLIC);
 
        for each (var swfTag:SwfTag in swfContext.swfTags) {
            if (swfTag.name == swfTagName) {
 
                // skip the flags
                swfTag.tagBody.position = 4;
 
                var abcStartLocation:uint = 4;
                while (swfTag.tagBody.readByte() != 0) {
                    abcStartLocation++;
                }
                abcStartLocation++; // skip the string byte terminator
 
                swfTag.tagBody.position = 0;
 
                var abcDeserializer:AbcDeserializer = new AbcDeserializer(swfTag.tagBody);
 
                var abcFile:AbcFile = abcDeserializer.deserialize(abcStartLocation);
 
                for each (var instanceInfo:InstanceInfo in abcFile.instanceInfo) {
 
                    for each (var methodInfo:MethodInfo in instanceInfo.methodInfo) {
                        var startIndex:uint = 0;
                        for each (var op:Op in methodInfo.methodBody.opcodes) {
                            startIndex++;
                            if (op.opcode === Opcode.pushscope) {
                                break;
                            }
                        }
 
                        var findOp:Op = new Op(Opcode.findpropstrict, [methodEntryInvokerClassQName]);
                        var getOp:Op = new Op(Opcode.getproperty, [methodEntryInvokerClassQName]);
                        var callOp:Op = new Op(Opcode.callproperty, [methodEntryInvokerMethodQName, 0]);
 
                        methodInfo.methodBody.opcodes.splice(startIndex, 0, findOp, getOp, callOp, new Op(Opcode.pop));
                    }
                }
 
                var abcSerializer:AbcSerializer = new AbcSerializer();
                var modifiedBytes:ByteArray = new ByteArray();
                modifiedBytes.writeBytes(swfTag.tagBody, 0, abcStartLocation);
                modifiedBytes.writeBytes(abcSerializer.serializeAbcFile(abcFile));
 
                swfTag.tagBody = modifiedBytes;
            }
        }
 
        invokeCallBack();
    }
}
}

The constructor for this patcher takes a URL, which is used to specify the XML config file. Then in the apply method, if the invocation type is “FRAME2″ (meaning the patcher is being applied to the SWF tags on the second frame of the loading SWF) then it uses URLLoader to load the XML config file. Notice that URLLoader is used, not HTTPService. That is because anything that goes into a patcher is put on the first frame of the SWF and if HTTPService was used here, then there would be a ton of additional classes (dependencies) that would need to also be moved to the first frame. While technically this would work, it’s not a good practice because the more that is on the first frame, the longer the user has to wait before the preloader shows up (remember: all of the frame must be transferred across the network before the frame is loaded into the VM). If the invocation type is not “FRAME2″ then the invokeCallBack method is called to tell Mixing Loom that this patcher is done with the current invocation. Side note: patchers can block for as long as they want. Nothing moves forward in Mixing Loom until a patcher calls the invokeCallBack method.

When the data for the XML file arrives it is parsed using the E4X library. Then new QualifiedName instances are created based on the interceptor’s class and method names. Now the SWF tag with the name specified in the XML file is processed. First it is deserialized by AS3 Commons Bytecode. This provides an object representation of the underlying ABC code contained in the SWF tag. Then for every class and method the interceptor is applied at the beginning of the method. Kinda. There are a few operations that must happen at the very beginning of the method. For each method being intercepted we need to move past the “pushscope” opcode before we can insert new opcodes. Then four new opcodes are spliced into the array of opcodes for the method: findpropstrict, getproperty, callproperty, and pop. Those four opcodes are the ABC equivalent of calling the static method on the specified interceptor class. In this case the rest of the opcodes in the method will be left alone. Finally the ABC is recreated using AS3 Commons Bytecode and the original SWF tag is overwritten and the invokeCallBack method is called.

Just like before we need a custom preloader to register the patchers:

package preloader {
import org.mixingloom.managers.IPatchManager;
import org.mixingloom.preloader.AbstractPreloader;
 
import patcher.SampleXMLPatcher;
 
public class SampleXMLPatcherPreloader extends AbstractPreloader {
 
		override protected function setupPatchers(manager:IPatchManager):void {
			super.setupPatchers(manager);
			manager.registerPatcher( new SampleXMLPatcher("interceptors.xml"));
		}
	}
}

Notice that a new instance of the SampleXMLPatcher is created and given the URL to the interceptor XML file. Here is a little test application containing a button that calls Foo’s getBar method every time it’s clicked:

<?xml version="1.0"?>
<?xml version="1.0"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               preloader="preloader.SampleXMLPatcherPreloader">
 
    <fx:Script>
        import blah.Foo;
        import FooInterceptor; FooInterceptor;
    </fx:Script>
 
 
    <s:Button label="call foo.getBar()" fontSize="32" top="20" horizontalCenter="0">
        <s:click>
                var foo:Foo = new Foo();
                foo.getBar();
        </s:click>
    </s:Button>
 
</s:Application>

Notice that since there wasn’t a reference anywhere else to the FooInterceptor we had to include one manually otherwise it will not exist in the compiled SWF. Here is a demo of that application:

Well, that was fun! And I hope you can see how Mixing Loom can be the foundation for doing AOP in Flex / ActionScript! But before I let you go I want to show you one more crazy thing we can do with Mixing Loom. Patchers can do just about anything they want since Mixing Loom provides hooks to modify the second frame, RSLs, and Modules. For instance, say there is a private method or property in the Flex framework that you need access to. One option is to use Monkey Patching to replace that class with one that you maintain. This is not a very maintainable way to get access to something that is private. Using Mixing Loom you can simply patch the class at runtime. Here is a simple (but impractical) example… The spark.components.Application class has a private method called “debugTickler” on it. Using the RevealPrivatesPatcher from Mixing Loom we can make that method public at runtime. First extend the base RevealPrivatesPatcher class and tell it only to apply the patcher on the “spark_” RSL:

package {
import org.mixingloom.SwfContext;
import org.mixingloom.invocation.InvocationType;
import org.mixingloom.patcher.RevealPrivatesPatcher;
 
public class MyRevealPrivatesPatcher extends RevealPrivatesPatcher {
 
    override public function apply( invocationType:InvocationType, swfContext:SwfContext ):void {
        if ((invocationType.type == InvocationType.RSL) && (invocationType.url.indexOf("spark_") >= 0)) {
            super.apply(invocationType, swfContext);
        }
        else {
            invokeCallBack();
        }
    }
}
}

Then create a custom preloader that registers a new instance of MyRevealPrivatesPatcher and tells it to reveal the “spark.components:Application” class and the “debugTickler” method:

package preloader {
import org.mixingloom.managers.IPatchManager;
import org.mixingloom.preloader.AbstractPreloader;
 
	public class RevealPrivatesPatcherPreloader extends AbstractPreloader {
 
		override protected function setupPatchers( manager:IPatchManager ):void {
			super.setupPatchers( manager );
			manager.registerPatcher( new MyRevealPrivatesPatcher("spark.components:Application", "debugTickler") );
		}
 
	}
}

Finally, use the LoomApplication and the custom preloader in order to have the hooks to patch RSLs:

<?xml version="1.0"?>
<ml:LoomApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                    xmlns:ml="library://ns.mixingloom.org/flex/spark"
                    xmlns:s="library://ns.adobe.com/flex/spark"
                    preloader="preloader.RevealPrivatesPatcherPreloader">
 
    <ml:applicationComplete>
            try {
                this['debugTickler']();
                l.text = "Yeah.  We just modified an RSL at runtime.";
            } catch (e:Error) {
                l.text = "booo";
            }
    </ml:applicationComplete>
 
    <s:Label id="l" text="nothing happened."/>
 
</ml:LoomApplication>

Notice that we can’t use the dot syntax “this.debugTickler()” to call the method since the compiler won’t let us do that. Instead we have to use the object key syntax “this['debugTickler']()” in order to make the method call. Now watch as Mixing Loom’s magic wand modifies a signed Flex Framework RSL right before your very eyes:

Fun stuff!!! And there is more to come! We are working on ways to also modify the first frame of the SWF and to modify a SWF pre-runtime. But now it’s your turn! All of the code for everything you’ve seen here, as well as some other demos, and goodies is all on github. We’d love to see the community create some interesting and useful patchers! So fork away and have fun! Let me know if you have any questions.

Invoking OpenX api from Flex

For the last several months I was playing with OpenX, an open source ad server written in PHP.  You can interact with OpenX in two ways: first by using the admin graphical interface, second by using API calls – most of the UI functionality can be programmatically reproduced.

OpenX is exposing its API through XML-RPC and they have a couple of examples on their website how to invoke the API from PHP, Java and Ruby. In my case I was trying to display some statistics without going through a middleware, so I started to investigate how can I do it from Flex. It turned out to be quite easy – one can use the AS3 RPC written by Akeem Philbert, with a small modification. The following steps should be done:

a) download the source code of the library from this location (http://code.google.com/p/as3-rpclib/)

b) you have to fix a small issue in the class com.ak33m.rpc.xmlrpc. XMLRPCObject  (compatibility issue between SDK’s). The overloaded methods setCredentials and setRemoteCredentials should receive another parameter, called charset.

c)create the objects mapping the OpenX structures (advertiser, campaign, zone etc) and invoke the exposed methods

I did these steps and I created this Flash Builder project – you can import it into your workspace and change the file ServerConfig.as accordingly.

In my example I have just a couple of operations like login, displaying and creating advertisers. It can easily be extended in order to support the whole OpenX api.

Next post on OpenX will be about displaying the ads on your website, from Flash and HTML.

Flash Camp San Francisco – April 30th

I am really excited to announce that this weekend we’re going to have a free, all day FlashCamp in San Francisco to celebrate the launch of Flex 4.5 and Flash Builder 4.5 starting at 9:00 AM, on April 30th. This will be a little bit different from some of our past Flash Camps that we have held, because it is during the day. However, this allows us to do some more hands on sessions as well as holding a coding session and contest for Flex 4.5 mobile application development

In the morning we’re going to have sessions covering all aspects of the mobile workflow. We’ve got a keynote from VP of Developer Tools, Ed Rowe, then Deepa Subramaniam, Flex Product Manager and Andrew Shorten, Group Product manager for Flex, are going to be doing an overview of the new mobile-specific features in Flex 4.5. We’ll also have 3 separate tracks to help you dive a little deeper:

  • Flash Builder for PHP
  • iOS and PlayBook development
  • UX design for mobile devices

In the afternoon we’ll bring out the tables and let you guys get to work building mobile apps. The Flex and Flash Builder teams will be on hand to help answer questions and help provide feedback.

The beer is being provided by City Beer Store, and I’m still nailing down the list, but we should have some fantastic craft beer at the event as well as pizza provided by Amici’s to help fuel the end of the day coding before we start giving away prizes and showing off mobile applications.

The Contest

One of the unique things about this Flash Camp is that after the hands-on session we’ll be giving away some prizes for people who have built a mobile application that afternoon. We’ll have a bunch of categories including most interesting use of Flex, most useful application, and most-well designed application. And you can win software, devices, an Xbox Kinect, and more, so there’s a ton of potential loot for you to take away.

You can also feel free to form teams, so if you are a designer-type, bring along your developer friends to fill out the team and you can show off the application as a team at the end of the day.

It’s going to be a lot of fun and I can’t wait to see what you guys put together. So register and come learn about mobile development with Flash and Flex, drink some great beer, and win prizes.

Register for Flash Camp 2011!

We are very excited to be hosting at Adobe, San Francisco a Flash Camp event on April 30th. This is going to be a rad event! This time around, the Flash Camp is a bit different. For starters, its on a Saturday – this means the fun will run all-day and include keynotes and sessions by Adobe Flex/Flash Builder team members as well as hands-on coding camps and labs. Of course, the usual beer and goodies will be provided and plenty of members from the engineering and product management teams will be in attendance!

The main focus of the camp is around mobile development. To that end, we’ll help you build a mobile application during the course of the camp and we’ll be giving away awesome prizes at the end for the best apps! So, come to Flash Camp to learn how to build a mobile application from scratch, or bring an application you’re already working on and polish it up during the event. Regardless of what you do, this is a not-to-miss event where you can learn hands-on from the experts about how to use Flex & Flash Builder to build performant standalone mobile applications on Android, Apple iOS and Blackberry Tablet OS!

Hope to see many of you there – register here!

Scrollable and Touch-Friendly Flex Charts

After I posted Flex Charts on the iPad, a few people asked me how to enable some specific gestures on these charts to make them small screen-friendly. One specific question was: “How can we make a chart scrollable to show a lot of data on a smaller screen while making sure the vertical axis is always visible?”. Here is a very simple implementation. You can customize and polish it in many different ways. For example, you could use AnimateProperty on the Axis minimum and maximum properties to animate the scrolling.

Use the mouse to scroll the chart columns left and right. On a touch screen, you can do the same thing using gestures.

Here is the code (I’ll have to do something about the pink!):

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   creationComplete="completeHandler()">

	<fx:Script>
		<![CDATA[
			protected var lastX:Number = 0;

			[Bindable] protected var viewportMax:Number = 10;

			protected function completeHandler():void
			{
				// Simulate values
				var results:Array = [];
				for (var i:int=0; i<50; i++)
				{
					results[i] = Math.random() * 100;
				}
				chart.dataProvider = results;
			}

			protected function mouseDownHandler(event:MouseEvent):void
			{
				lastX = event.stageX;
				systemManager.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
				systemManager.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			}

			protected function mouseMoveHandler(event:MouseEvent):void
			{
				var delta:Number = (lastX - event.stageX) / chart.width * viewportMax;
				if (hAxis.minimum + delta < 0)
				{
					hAxis.minimum = 0;
					hAxis.maximum = viewportMax;
				}
				else if (hAxis.maximum + delta  > chart.dataProvider.length - 1)
				{
					hAxis.maximum = chart.dataProvider.length - 1;
					hAxis.minimum = hAxis.maximum - viewportMax;
				}
				else
				{
					hAxis.minimum += delta;
					hAxis.maximum += delta;
				}
				lastX = event.stageX;
			}

			protected function mouseUpHandler(event:MouseEvent):void
			{
				systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
				systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, mouseUpHandler);
			}

		]]>
	</fx:Script>

	<mx:ColumnChart id="chart" top="10" left="10" right="10" bottom="10"
					mouseDown="mouseDownHandler(event)">
		<mx:series>
			<mx:ColumnSeries />
		</mx:series>

		<mx:horizontalAxis>
			<mx:LinearAxis id="hAxis" minimum="0" maximum="{viewportMax}"/>
		</mx:horizontalAxis>

	</mx:ColumnChart>

</s:Application>

AIR on iOS Games From Terry Paton (video)

I have to say that I had basically given up on AIR for iOS a few months ago. Then out of nowhere the team had a breakthrough and it is now a technology that I truly believe in. It’s not perfect yet but the performance increases that have come tell me that this technology has a bright future. And don’t even get me started about Flex Mobile running really good on iOS now. I never would have thought that would happen either. I am eating a big slice of humble pie at the moment.

Game developer extraordinaire Terry Paton has started porting his great AIR for Android games to the iPad and the performance is nothing short of amazing. He let me record this sneak peek showing off a couple of them. Enjoy!

A Couple of PlayBook-Related Videos on AdobeTV

The PlayBook is on sale today and it really is a beautiful device, especially for Flash developers. Having been able to play with one for a while now I am incredibly impressed with the QNX operating system and the general form factor of the tablet.

I did a couple of videos on the PlayBook for AdobeTV. The first one is on using OAuth with the PlayBook. It should be a good primer for PlayBook developers who want to leverage services like Twitter or Facebook Connect. The second one was a video of one of Renaun’s tips on how to use ImageCache in a QNX list to help improve performance. Both are embedded below.

Slides and Code from 360Flex Denver

360Flex Denver360|Flex Denver was an absolutely fantastic event. I was at the first 360 and have watched the event grow and mature over the years. It’s always been the best Flex conference out there, but there was something about those first few 360′s that had so much energy and got the community excited. This event felt like that. I’d rank it as one of the best 360′s I’ve ever been to. The attendees were enthusiastic and great to talk to, the keynotes were awesome and inspiring, and John and Nicole were at the top of their game as far as hosting went. It might have been all of the mobile stuff, it might have been the announcement on day 2 of Project Spoon, but this 360Flex was just all around great.

So of course, I made a bit of a misstep with my talk. At what was one of the greatest Flex conferences of the past 5 years, I go and give an HTML5/jQuery talk. But hopefully it was still fun. And to be honest, as I dove into HTML5 and jQuery for this talk, I learned that we have it very, very good as Flex developers. There are a lot of great things about HTML5 and especially jQuery, but if you’re building complex RIAs and applications, Flex has solved a ton of problems that the HTML5/JS world hasn’t yet. I definitely think they will, and the community around JS and jQuery is great, but as a Flex developer, you’ve got the best of both worlds and you’re going to be able to jump over to jQuery/HTML5 projects and bring some very valuable knowledge about building complex apps.

Thanks to everyone who attended the talk. My slides can be found here (and embedded below) and you can grab the demos from my GitHub repository here.