Nice. Adobe has apparently been working closely with Facebook and Jason Crist (original API dev.) to get a nice, solid API for Facebook apps ready for the Flash Platform. As a Flash Platform developer and Facebook user, this is nothing but good news. Very timely, too – as my department is looking to expand into the social media space. I look forward to integrating this into my day-to-day work and our overall codebase!
Tag Archives: ActionScript
Quick Tip: Display Application Version in your AIR App.
Just a quick tip for those looking to somehow display the AIR application version from the descriptor file. I’ve found it very helpful in troubleshooting is users can say EXACTLY what version of the app they are running.

private function getAppVersion():String {
var appXml:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = appXml.namespace();
var appVersion:String = appXml.ns::version[0];
return appVersion;
}
Using FlexEvent.IDLE to Determine Inactivity
A FlexEvent.IDLE event will dispatch every 100 milliseconds when there has been no keyboard or mouse activity for 1 second. So, if you want to have some other method fire off after the user is inactive for 5 minutes (for example), you would set it up as detailed below.
Be sure to import the following classes. IDLE needs to be bound to a SystemManager instance and we will need to reference the mx_internal namespace later on:
1 2 3 | import mx.managers.SystemManager; import mx.events.FlexEvent; import mx.core.mx_internal; |
You’ll need to tell Flex that you want to use mx_internal as a namespace to access those properties within the SystemManager class. SytemManager has an “idleCounter” property which is super useful to access- but it is scoped to mx_internal and is not normally accessible. Trying to access it without these steps will throw an error:
1 | use namespace mx_internal; |
SystemManager is automatically instantiated as a part of every Flex app, so we do not need to do this manually. We will, however, need to add an event listener for FlexEvent.IDLE:
1 | this.systemManager.addEventListener(FlexEvent.IDLE, userIdle); |
Construct the callback method. Five minutes is equal to 300000 milliseconds… divided by 100 ticks and the number we need to check against is 3000. Of course, you’ll probably want something a little shorter in duration for testing:
1 2 3 4 5 | private function userIdle(e:FlexEvent):void { if(e.currentTarget.mx_internal::idleCounter == 3000){ //do something! } } |
Note that we prefix the idleClounter property with the mx_internal namespace.
That’s it! Now we have a sweet little activity monitor in our app. When activity is detected, idleCounter will automatically reset as well.
Creating a Splash Screen in AIR
A lot of desktop apps have a splash screen that brands the application while it is loading or performing other processes in the background. Adobe AIR does not have a direct mechanism for this- but the feature can be easily achieved with some nice windowing action.
There are a number of steps to take when preparing your app for this sort of thing. This example was adapted from a much larger application and there may also be some imports and properties that are not necessary for our narrow purpose here. I’m sure my method is not the only one and I’m not saying it’s perfect either! Taking the following steps should produce a similar result though:
1) Edit your application descriptor file to set the initial main application window x and y positions off screen.
<!-- The window's initial x position. Optional. --> -1000 <!-- The window's initial y position. Optional. --> -1000
2) I have also set an applicationComplete event within the WindowedApplication node.
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:custom="components.*" layout="absolute" horizontalScrollPolicy="off" verticalScrollPolicy="off" showFlexChrome="true" applicationComplete="{init()}" currentState="SplashState"></mx:WindowedApplication>3) The init function reads as follow:
private function init():void { mainWindow = this.stage.nativeWindow; var splashWindowinitOptions:NativeWindowInitOptions = new NativeWindowInitOptions(); splashWindowinitOptions.transparent = true; splashWindowinitOptions.systemChrome = NativeWindowSystemChrome.NONE; splashWindowinitOptions.type = NativeWindowType.UTILITY; splashWindow = new NativeWindow(splashWindowinitOptions); splashWindow.title = "Splash Example"; appSplash = new SplashScreen(); hiddenCanvas.addChild(appSplash); hiddenCanvas.removeChild(appSplash); splashWindow.stage.scaleMode = 'noScale'; splashWindow.stage.align = 'topLeft'; splashWindow.stage.addChild(appSplash); splashWindow.x = Screen.mainScreen.visibleBounds.width/2 - 300; splashWindow.y = Screen.mainScreen.visibleBounds.height/2 - 200; splashWindow.width = 600; splashWindow.height = 400; splashWindow.activate(); mainWindow.visible = false; splashTimer = new Timer(1000, 2); splashTimer.addEventListener(TimerEvent.TIMER_COMPLETE, removeSplash); splashTimer.start(); this.removeEventListener(FlexEvent.APPLICATION_COMPLETE, init); }
The NativeWindowInitOptions are hugely important as they will render the window chromeless and transparent.
“SplashScreen” is a custom component which simply holds material for display- such as an image or text or whatever you want users to see as a visible splash screen.
Since I am using the ActionScript NativeWindow class here and not the Flex Window component, we must add the display object first to a hidden element in our Flex application. It’s weird but is something you must do if you want your splash screen to be visible when doing it this way.
We then activate our splash window and make the main app window invisible. In the case of this example, I have a timer that runs to determine when to remove the splash screen and bring up the main app window. In most cases, this would instead be reliant on some background process such as a data load.
4) Next comes the function that fires when we want to remove the splash screen and start using our app.
private function removeSplash(e:TimerEvent):void { mainWindow.x = Screen.mainScreen.visibleBounds.width/2 - mainWindow.width/2; mainWindow.y = Screen.mainScreen.visibleBounds.height/2 - mainWindow.height/2; mainWindow.visible = true; mainWindow.activate(); splashWindow.stage.removeChild(appSplash); splashWindow.close(); splashWindow = null; currentState = "LoadedState"; splashTimer.stop(); splashTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, removeSplash); splashTimer = null; }
So, we reset reposition the main window onto the screen, render it visible again, and activate it. This will cause it to spring to life and now the app is running for our user. We then perform some cleanup routines on the splash screen and timer objects so they will not linger in memory any longer.
There we have it! I’ve made the source available as a Flex Project Archive.
Client.videoSampleAccess False-Negative
In past versions of FMS, developers were barred from accessing raw audio and video data over RTMP and had to resort to a number of hacks and proxies to get around the restriction. As time went by and new versions of the Flash Player were released, a lot of these loopholes were blocked as well.
With FMS3, there is Client.videoSampleAccess: a property of the Flash Media Server 3 that allows direct access to raw stream data for video use (“audioSampleAccess” for audio). This can be used for things like producing visual audio spectrums or grabbing a still from a video stream. It is applied within the onConnect method of the Application server class as demonstrated here:
1 2 | appClient.audioSampleAccess = "/"; appClient.videoSampleAccess = "/"; |
In the above example, the “/” signifies that any streams within the application directory are allowed to be sampled in this way. You can also specify a semicolon-delimited list of folder names instead if you need to be picky.
Something I came across today and the whole point of this post: even when you have Client.videoSampleAccess set up properly on Flash Media Server, you will still receive a security sandbox violation error #2123 if the stream data is not available. This can easily happen if you have a timer invoking BitmapData.draw every few milliseconds on loading content.
One way to get around this is using NetStatusEvent.NET_STATUS making sure it reports “NetStream.Buffer.Full” before attempting to access the stream data. Depending on what you are doing, you can oftentimes check the object recieving the stream data to be sure it is accessible first. this all seems really obvious now, but threw me for a bit of a loop, initially.
