Vixiom Axioms

March 24, 2008

Adobe holding a series of online seminars this week

Filed under: AIR, ActionScript, Flash, Flex, RIA Alastair @ 7:00 am

Info here.

Some of the more interesting sessions:

Extending Web to the Desktop with AIR
Monday, March 24, 2008
9:00 AM - 10:00 AM US/Pacific

Getting Started with Flash Lite 3 and CS3
Monday, March 24, 2008
11:00 AM - 12:00 PM US/Pacific

Building Rich Internet Applications with Flex 3
Monday, March 24, 2008
4:00 PM - 5:00 PM US/Pacific

Introduction to Adobe Blaze DS
Tuesday, March 25, 2008
9:00 AM - 10:00 AM US/Pacific

Integrating Salesforce.com and Flex
Tuesday, March 25, 2008
11:00 AM - 12:00 PM US/Pacific

Building AIR Applications with Flash CS3
Tuesday, March 25, 2008
1:00 PM - 2:00 PM US/Pacific

Adobe AIR Local Data Storage Options With Emphasis on Using Embedded SQL Databases
Wednesday, March 26, 2008
9:00 AM - 10:00 AM US/Pacific

Flex and Java – Tying the Knot!
Wednesday, March 26, 2008
4:00 PM - 5:00 PM US/Pacific

Flex Data Services
Thursday, March 27, 2008
9:00 AM - 10:00 AM US/Pacific

Blood from a Stone: Flash Game Optimization on Low-end mobile devices
Thursday, March 27, 2008
1:00 PM - 2:00 PM US/Pacific

Flex Visual Data & Charting
Thursday, March 27, 2008
4:00 PM - 5:00 PM US/Pacific

AIR Native Drag and Drop
Friday, March 28, 2008
1:00 PM - 2:00 PM US/Pacific

Flex Architecture
Friday, March 28, 2008
4:00 PM - 5:00 PM US/Pacific

Digg! submit Adobe holding a series of online seminars this week to stumbleupon.com submit Adobe holding a series of online seminars this week to del.icio.us submit Adobe holding a series of online seminars this week to reddit.com Like this post? subscribe to the feed.

February 26, 2008

Run Ruby code in the Flash Player?

Filed under: AIR, ActionScript, Flash, Flex, RIA, Ruby, Silverlight Alastair @ 6:30 pm

Or even better write Flash/Flex Rich Internet Applications with Ruby? Ted Patrick says it may soon be possible.

When Microsoft released Silverlight the one feature that got a lot of people excited was that you could use the language you were most familiar with to build a RIA. Apparently Adobe has an internal project which allows any C or C++ code to run in the Flash Player or on AIR. This means that any language built on C/C++ will also run which means that Java, Python, and my beloved Ruby could also run. Schwing! :)

Ted is a Python guy so he talks about IronPython and JPython but of course Ruby has JRuby and IronRuby so I’m sure the behavior would be similar.

Like many organizations Adobe has lots of legacy C/C++ code ranging from PhotoShop filters, to PDF renderers, to readers and writers of every file format in existence, font libraries, to very complex vector renderers, and text layout code. Beyond Adobe there are many open source libraries that could be leveraged as components as well. The big thing for me is that these are not ports of these libraries, they run identical to the original source code down. For example the behavior of Python in Flash Player is identical to C-Python vs the ported behavior under the IronPython and Jython projects. The goal here is to bring lots of these legacy assets, code libraries, and languages into Flash Player and Adobe AIR perfectly so that any developer can leverage them cross-platform to build software. It would not shock me to see some of these components added into the Flash Player component cache so that they essentially are built into the player on first use.

InfoWorld has more.

Digg! submit Run Ruby code in the Flash Player? to stumbleupon.com submit Run Ruby code in the Flash Player? to del.icio.us submit Run Ruby code in the Flash Player? to reddit.com Like this post? subscribe to the feed.

January 10, 2008

Log into Facebook with Adobe AIR (without leaving the desktop)

Filed under: AIR, ActionScript, Facebook, Flex Alastair @ 9:40 am

I’ve been messing around with the Facebook API and one of the things I don’t like about the desktop version is that you still have to authorize an app through a browser. I know you only have to do this the first time but what’s the point of a desktop application if you have to open a browser? Here’s how to use AIR’s HTML control to login to Facebook without leaving the safe confines of your desktop. The example will log into facebook and grab the most recent noifications for the logged in user - that’d be you :)

If your making a Facebook app you’ll need the developer application added to your profile and have generated application keys. If this is all new to you see this page on how to get started. Once you have the developer application with a new app click on ‘My Applications’

And take note of your API Key, Secrect Key, and set your Callback URL (see note on Callback URL below).

On a regular facebook app the Callback URL would be the first page that shows up once you login but for our purposes it doesn’t really matter where it is or what it does, I have a simple PHP file that just outputs the returned auth_token variable.

<?php

$auth_token = $_GET[auth_token];
print_r($auth_token);

?>

But that’s was really just for when I was testing before moving to AIR it could be a blank HTML file. The last Facebook setting to check is to set ‘Application Type’ to ‘Desktop’

With your API Key, Secret Key noted download the source files for this tutorial and create a new AIR project. The source files include two Adobe libraries the as3facebooklib and elements from the core library as3corelib (which has tons of other useful stuff). In the file ’src/com/desktopfb/model/Model.as’ change ‘api_key’ and ’secret_key’ to your values. The model is a Singleton with some hactackstic exposed public variables - I went to art school so I don’t know any better ;)

package com.desktopfb.model
{
    import com.adobe.webapis.facebook.FacebookService;
    import com.adobe.webapis.facebook.User;

    [Bindable]
    public class Model
    {
        private static var instance:Model;

        // state
        public var appState:String = undefined;

        // service
        public var service:FacebookService;

        public var api_key:String = “YOUR API KEY HERE”;
        public var secrect_key:String = “YOUR SECRET KEY HERE”;
        public var auth_token:String = “”;

        // main user uid
        public var loggedInUser_uid:String;

        // main user
        public var loggedInUser:User;

        //////////////////////////////////////////////////////////////////////
        //
        // instance
        //
        //////////////////////////////////////////////////////////////////////

        public static function getInstance():Model
        {
            if ( instance == null ) instance = new Model();
            return instance as Model;
        }
    }
}

With those two changes made you can run the application, but… I’ll explain what’s going on. The main application file ’src/DesktopFB.mxml’ is the WindowedApplication wrapper, it’s the entry to the app and really only handles state (which is bound to the model’s ‘appState’ var). There are only two states the login view and the home view.

<?xml version=1.0 encoding=utf-8?>
<mx:WindowedApplication
    xmlns:mx=http://www.adobe.com/2006/mxml
    xmlns:view=com.desktopfb.view.*
    layout=vertical width=1024 height=768
    currentState=“{model.appState}”>

    <mx:states>
        <mx:State name=loggedIn>
            <mx:RemoveChild target=“{loginView}”/>
            <mx:AddChild>
                <view:HomeView />
            </mx:AddChild>
        </mx:State>
    </mx:states>

    <mx:Style source=css/app.css />

    <mx:Script>
        <![CDATA[
            import com.desktopfb.model.Model;

            [Bindable]
            private var model:Model = Model.getInstance();

        ]]>
    </mx:Script>

    <view:LoginView id=loginView />

</mx:WindowedApplication>

Next up the login view ’src/com/desktopfb/view/LoginView.mxml’. It guides us through the fairly complicated task of authorizing a Facebook user. Stepping throught the methods

  1. onCreationComplete(): fires right away and checks for a sharedObject (an ActionScript session/cookie), if it finds one it sets the appState var to ‘loggedIn’ and since it’s bound to the app’s current state will automatically take the suer to the home view. If it doesn’t find a sharedObject it starts the login sequence.
  2. startLoginSequence(): takes your keys packages them up in a service (including md5′ing them behind the scenes) and listens for a response ‘service.addEventListener( FacebookResultEvent.AUTH_CREATE_TOKEN, createTokenResponse )‘. If you’re new to web services in Flex/AIR that’s the routine; create a service, then map a method to the service via an event listener.
  3. createTokenResponse(): Sends the HTML control to the facebook login page with your API key appended (http://www.facebook.com/login.php?api_key=YOUR_KEY&v=1.0)
  4. the HTML control is set up to listen for location change events (locationChange = "onLocationChange()"), and once a user logs into your app in Facebook it redirects your to the CallbackURL, as the HTML has redirected the ‘locationChange’ event fires and because the URL is appended with ‘auth_token’ the ‘location.search(pattern)’ will match, the auth_token is saved to the model and then we go to the final set of authorizing a Facebook user getting a session key (logging into Facebook is not for the faint of heart!)
  5. getSession(): takes your auth_token and sends it to Facebook so they really really really know it’s you, it’s listener is ‘getSessionResponse
  6. getSessionResponse(): finally done! we have a session_key - it’s worth more than it’s weight in gold - save it to a shared object so we never have to go through this again. The app’s current state is set to ‘loggedIn’ and you switch to the home view.
<?xml version=1.0 encoding=utf-8?>
<mx:VBox xmlns:mx=http://www.adobe.com/2006/mxml
    width=100% height=100% horizontalAlign=center verticalAlign=top
    creationComplete=onCreationComplete()>

    <mx:Script>
        <![CDATA[
            import com.adobe.webapis.facebook.*;
            import com.adobe.webapis.facebook.events.FacebookResultEvent;

            import mx.managers.CursorManager;
            import mx.core.UIComponent;
            import com.desktopfb.model.Model;
            import flash.display.Sprite;
            import flash.html.HTMLLoader;
            import flash.net.URLRequest;

            private var service:FacebookService;
            private var model:Model = Model.getInstance();
            private var sharedObject:SharedObject;

            /**
             * onCreationComplete
             *
             * check sharedObject for a saved session key
             *
             */

            private function onCreationComplete():void
            {
                trace(“login view”);
                var facebookCookie:SharedObject = SharedObject.getLocal( “FacebookServiceTest” );

                // check ‘cookie’

                delete facebookCookie.data.session_key; // uncomment to clear cookie and force login

                if ( facebookCookie.data.session_key )
                {
                    trace(“Found stored auth token…”);

                    // Assign the token and permission to the service
                    service = new FacebookService( facebookCookie.data.api_key );
                    model.service = service;
                    service.session_key = facebookCookie.data.session_key;
                    service.secret = facebookCookie.data.secret;

                    // set app state as home
                    model.appState = “loggedIn”;
                }
                else
                {
                    startLoginSequence();
                }
            }

            /**
             * startLoginSequence
             *
             * send api and secret to Facebook to get auth_token
             *
             */

            public function startLoginSequence():void
            {
                service = new FacebookService( model.api_key );
                model.service = service;

                service.secret = model.secrect_key;

                service.addEventListener( FacebookResultEvent.AUTH_CREATE_TOKEN, createTokenResponse );
                service.auth.createToken();
            }

            /**
             * Create token response
             *
             * load auth_url in htmlWindow
             *
             */

            private function createTokenResponse( event:FacebookResultEvent ):void
            {
                trace(“createTokenResponse: success = “ + event.success);

                if ( event.success )
                {
                    // Have the service construct a login url
                    var auth_token:String = String( event.data );
                    var auth_url:String = service.getLoginURL( auth_token );

                    trace(auth_url);

                    // Open a htmlControl window to authenticate the user
                    htmlWindow.location = auth_url;
                    htmlWindow.reload();
                }
                else
                {
                    // error
                    traceError( FacebookError( event.data ) );
                }
            }

            /**
             * getSession
             *
             * After auth is returned get session
             *
             */
            private function getSession():void {

                // Get their authentication token, and call getTokenResponse
                service.addEventListener( FacebookResultEvent.AUTH_GET_SESSION, getSessionResponse );
                service.auth.getSession( model.auth_token );
            }

            /**
             * getSessionResponse
             *
             * last step of user authorization, save the facebook cookie
             *
             */

            private function getSessionResponse( event:FacebookResultEvent ):void
            {
                if ( event.success )
                {
                    var authSession:AuthSession = AuthSession( event.data );

                    // Assign the token and permission to the service for future calls
                    service.session_key = authSession.session_key;
                    service.secret = authSession.secret;

                    // Save the token in a shared object for future logins
                    var facebookCookie:SharedObject = SharedObject.getLocal( “FacebookServiceTest” );
                    facebookCookie.data.api_key = service.api_key;
                    facebookCookie.data.session_key = service.session_key;
                    facebookCookie.data.secret = service.secret;
                    facebookCookie.flush();

                    // set app state as home
                    model.appState = “loggedIn”;
                    model.loggedInUser_uid = authSession.uid;

                    // spit out authSession data
                    trace(“uid: “ + authSession.uid);
                    trace(“expires: “ + authSession.expires);
                    trace(“secret: “ + authSession.secret);
                    trace(“session_key: “ + authSession.session_key);
                }
                else
                {
                    // error
                    traceError( FacebookError( event.data ) );
                }
            }

            /**
             * onLocationChange
             *
             * watch and react to location changes
             *
             */

            private function onLocationChange():void
            {
                trace(“change”);
                var location:String = htmlWindow.location;
                trace(location);
                var pattern:RegExp = /auth_token/i;

                if (location.search(pattern) != -1)
                {
                    var locationArray:Array = location.split(“=”);

                    // save auth_token in model
                    model.auth_token = locationArray[1];
                    trace(model.auth_token);
                    getSession();
                }
            }

            /**
             * onComplete
             *
             * hide busy cursor when html finishes rendering
             *
             */

            private function onComplete():void
            {
                CursorManager.removeBusyCursor();
            }

            /**
             * domIni
             *
             * show busy cursor on html call
             *
             */

            private function domIni():void
            {
                CursorManager.setBusyCursor();
            }

            /**
             * traceError
             *
             * trace any errors to the console
             *
             */

            private function traceError( e:FacebookError ):void
            {
                trace(“error code: “ + e.errorCode);
                trace(“error message: “ + e.errorMessage);
            }

        ]]>
    </mx:Script>

    <mx:HTML id=htmlWindow width=800 height=400
    horizontalScrollPolicy=off verticalScrollPolicy=off
    locationChange=onLocationChange() complete=onComplete() htmlDOMInitialize=domIni()/>

</mx:VBox>

The home view. This is far less complicated than the login view, hopefully the comments let you know what’s going on, it’s just call and response (this one’s for you Tomo) for the user’s info and their notifications (which are outputted to a text area).

<?xml version=1.0 encoding=utf-8?>
<mx:HBox xmlns:mx=http://www.adobe.com/2006/mxml width=100% height=100%