Archive for the ‘FlashBuilder’ Category

Accessing HTML5 Geolocation via ActionScript

Read on to learn how to access the HTML5 Geolocation API using ActionScript in a web app. Using the patterns below you can get access to a visitor’s approximate location in applications that run in a desktop or laptop browser. Mobile ActionScript/Flex/AIR apps have convenient, built-in access to location via the flash.sensors.Geolocation Class. However, with a web app you have to cobble together your own code using¬†ExternalInterface.

The key to all this is using ExternalInterface’s addCallback(). ¬†This method lets you access ActionScript from JavaScript code in the wrapper HTML file, which if you didn’t know is the .html file that is used to launch Flash Player.

There are two steps to take that make it work:

Step 1. In addCallback() set the first parameter to the name of the function you will invoke in JavaScript to send data to your ActionScript method. Set the second parameter to the name of the actual ActionScript method. ActionScript will then recognize when the method specified in the second parameter is called. Essentially this sets up a listener in ActionScript.

Step 2. Set the¬†call() method so that it invokes a public JavaScript function. When it’s done running, then you fire off the JavaScript function specified in the first parameter of addCallback().

If that doesn’t make any sense, check out the code below to see how it all fits together. Note, you can either hard code your JavaScript in the wrapper HTML file, or you can do what I do below and inject it into the DOM at runtime using the document.insertScript pattern so you know it’s always there.

public function findLocation():void
{
	if (!Geolocation.isSupported)
	{
		const  VERIFY_GEOLOCATION:String =
			"document.insertScript = function(){" +
				"verify_geolocation = function(){"+
					"var geoEnabled = false;" +
					"if(navigator && navigator.geolocation)" +
					"{" +
					"    return geoEnabled = true;" +
					"}" +
					"else{" +
					"    return geoEnabled = false;" +
					"}"+
				"}"+
			"}";

		const  GET_GEOLOCATION:String =
			"document.insertScript = function(){" +
				"get_geolocation = function(){"+
					"var mySWF = document.getElementById('YourApplicationName');"+
					"navigator.geolocation.getCurrentPosition(function(position){"+
					"     mySWF.sendGeolocationToActionScript(position);"+
					"});"+
				"}"+
			"}";

		if(ExternalInterface.available)
		{
			//load the script into DOM
			ExternalInterface.call(VERIFY_GEOLOCATION);

			//call the JS function
			var geoEnabled:Boolean = ExternalInterface.call("verify_geolocation");

			if(geoEnabled == true){
				//Load the script into DOM
				ExternalInterface.call(GET_GEOLOCATION);

				//Step 1: set the ActionScript callback
				ExternalInterface.addCallback("sendGeolocationToActionScript",geolocationResultHandler);

				//Step 2: call the JS Function
				ExternalInterface.call("get_geolocation");
			}
		}
	}
}

//Access this Handler from JavaScript
public function geolocationResultHandler(obj:Object):void
{
	//Access the HTML5 Geolocation object properties just like you would in JavaScript
	Alert.show("Latitude: " + obj.coords.latitude + ", "Longitude: " + obj.coords.longitude );
}

Test Notes:

I compiled this code using FlashBuilder 4.6 using Apache Flex 4.6. The functionality was tested on Internet Explorer 9, Chrome 21 and Firefox 14.

References:

Adobe ActionScript Reference – ExternalInterface
Adobe Help – Accessing Flex from JavaScript

Tags: , , ,
Posted in ActionScript, FlashBuilder, HTML5 | No Comments »

How to upgrade your AIR SDK in FlashBuilder 4.6

This post walks through the steps for upgrading your AIR SDK. ¬†There are just a few tricks and I spell them out here since this isn’t a one-click, plug-in-play operation.¬†As of this writing, AIR 3.3 is the latest version, whereas FlashBuilder 4.6 came with v3.1 installed.

Why upgrade? In my case I had two reasons. First, I’d heard from a co-worker that AIR v3.3 compiled significantly faster. And, second I ran into a few flaky bugs and I wanted to test my builds using the latest SDK version.

1. Make a copy of the Flex SDK directory and place it in the same default sdk directory. On windows this is C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.6\sdks. Rename the new directory you just created to something like “4.6A3.3″.

2. Download latest AIR SDK (zip) file from Adobe. Yep, even though Adobe open sourced Flex, they still produce AIR and the FlashPlayer runtime: http://www.adobe.com/devnet/air/air-sdk-download.html.

3. Merge the contents from the AIR SDK zip file into the new copy of the Flex SDK directory. There will be some files that you have to overwrite in order to get the latest version.

4. Instruct FlashBuilder to use the new SDK by going to Window > Preferences > Flash Builder > Installed Flex SDKs, and then click “Add”. If you want to keep track of the different AIR versions related to Flex then make up a new naming convention for the SDK such as “Flex 4.6 – AIR 3.3″.

5. For existing projects which are using the older versions of AIR, such as Flex mobile projects, you’ll need to manually update the app.xml file to use the correct SDK version number in the namespace (xmlns). This file can be found in your FlashBuilder Project using the Package Explorer. If you don’t make this change you’ll get a compiler error. Your app.xml namespace should look like this. Note that when you create a new mobile project it should automatically be created with the correct xmlns settings.

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<application xmlns="http://ns.adobe.com/air/application/3.3">

<!-- Adobe AIR Application Descriptor File Template.

	Specifies parameters for identifying, installing, and launching AIR applications.

	xmlns - The Adobe AIR namespace: http://ns.adobe.com/air/application/3.3
			The last segment of the namespace specifies the version
			of the AIR runtime required for this application to run.

	minimumPatchLevel - The minimum patch level of the AIR runtime required to run
			the application. Optional.
-->

Here’s an example of the error you’ll get if you don’t do this. You’ll see something like “Namespace 3.1 in the application descriptor file should be equal or higher than the minimum version 3.3 required by the Flex SDK.”

References:

Adobe Doc – Overlay the AIR SDK with the Flex SDK

Tags: ,
Posted in ActionScript, FlashBuilder | No Comments »

My recent Antarctica Flex/ActionScript app had a requirement for tokenized asynchronous requests. That way I could use a centralized HTTP controller through which every outbound request was submitted. By attaching a ‚Äútoken‚ÄĚ to each request, I could properly manage the response payload for the dozen‚Äôish different processes that were going on. In other words, you attach a unique identifier to the outbound request. When the server sends back its response to the client application, this unique identifier is passed along in the payload. Quite cool, right?!

I‚Äôve used this technique in heavy-duty, server-side applications before but¬†only a few times¬†in a web client. In practice it works brilliantly and it allowed me to easily organize¬†the HTTP responses from many different types of requests and keep them all straight. At the heart of controller was this pseudo-code. If you haven’t done this before, there are just a few tricks to make it work right. I’ve included all the code to make your life easier. The token variable is a String that you create and then pass to the AsynchResponder.

                               
_http = new HTTPService();
_http.concurrency = "multiple";
_http.requestTimeout = 20;
_http.method = "POST";

var asyncToken:AsyncToken = _http.send( paramsObject );  
                                     
//you pass the token variable in as a String
var token:String = "someValue";
var responder:AsyncResponder = new AsyncResponder(resultHandler,faultHandler,token);
asyncToken.addResponder(responder);

Elsewhere in the app, the other classes that used the controller received the response payload via the event bus and then filtered the response by the tokens using a switch/case statement. AppEvent is my custom event bus that would broadcast the payload to the entire application via an Event. This allowed me to fully decouple the http controller from being directly wired into my other classes. It made the app very flexible in that action would only be taken when the response came back. If you want a few more details about this architecture, then check out my blog post on it. Here’s the HTTP response handler pseudo-code that is inside the controller.

Just a note, the HTTPData Class is a custom object I wrote to manage the response data. You could manage the data anyway you like. This is just one example of how to do it.

private function resultHandler(result:Object, token:Object = null):void
{	
	var httpData:HTTPData = new HTTPData();
	httpData.result = result.result;
	httpData.token = token; 
	AppEvent.dispatch(AppEvent.HTTP_RESULT,httpData);
}

And, here’s the response handler that’s inside one of the applications pages (views) that recieve the payload via my event bus:

AppEvent.addListener(AppEvent.HTTP_RESULT,httpResultHandler);

/**
 * Handles setting up many of the user variables based on tokenized,
 * asynchronous HTTP requests.
 * @param event AppEvent from HTTP request.
 */
private function httpResultHandler(event:AppEvent):void
{
    var json:String = event.data.result as String;	
    
    //route the tokens through a switch/case statement
    switch(event.data.token)
    {
         case "getallgpspoints":
              parseGPSPoints2(json);
              break;
    }
}

You can download the entire controller example here. If you use it for your own work, you’ll have to comment out anything you don’t need like some of the import statements and the custom events. Have fun!

Tags: , , , , , , , ,
Posted in ActionScript, FlashBuilder, Internet | 1 Comment »

Live From Antarctica ‚Äď the final 7th Summit.

Our team just finished a massive 5 weeks push to building an app for the Romero family, and in particular Jordan, to follow him on his climb of the final summit on the continent at the bottom of the world. You can find the app on his home page today http://jordanromero.com, or access it directly here http://edn1.esri.com/antarctica.

It was actually Jordan’s dream to climb the highest summits on the major continents. And, he is now on his way to accomplish all that…and before his 16th birthday during what is considered summer in Antarctica. I’m amazed at what he has done. I can’t help but think about what he might be able to accomplish in the future now that he has accomplished a feat that very few ever do.

The app is capturing live GPS coordinates (altitude, heading, speed, lat/lon), live weather and it also includes a Challenge component that anyone can take to conquer their own 7 summits on their own time by walking, swimming, running or biking.

I encourage you to check out the app and even take the Challenge!

For the techno-geeks reading this, here is some background info on the technology. GPS processing and ArcGIS mapping backend services were built in C#.NET by AL Laframboise. The Challenge service and REST endpoints were built in C#.NET by Nick Furness. I built the the Adobe Flex/ActionScript client application using Adobe FlashBuilder 4.5, and the ArcGIS API for Flex provided the client-side mapping. The look and feel were accomplished by the excellent help of UX engineer Frank Garofalo in Esri Professional Services. The client app uses a custom dependency injection model at the core, and the skins were built using Adobe Catalyst.

Tags: , , , , , , , , , , , , , , ,
Posted in ActionScript, Antarctica, C#, FlashBuilder | No Comments »

This post is for Adobe Flex/Actionscript/Flash developers who are looking to build commercial-grade mobile apps. I’ve tried to pull together a high-level check list of items you’ll need to build successful and stable apps based on Flex 4.5.1. I’ve also uploaded a fully-functional prototype that demonstrates these concepts in a real-time, GPS navigation app. You can download the app here. So, here goes.

1. Set your initial splashScreenImage and application icon. For your app to look professional you’ll want to display an image while it launches so there isn‚Äôt just a blank screen. Here‚Äôs a great blog post that goes into more detail and covers handling multiple screen resolutions. One caveat on the splashScreenMinimumDisplayTime property is use this with caution. If you delay the app start too much you run the risk of really annoying users.

<s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
splashScreenImage="@Embed('assets/splashscreen.png')"
splashScreenMinimumDisplayTime="1500"
splashScreenScaleMode="letterbox">

And, be sure to set the application icon. When you install your app, this is the image that will be displayed in the phone’s UI. Configure this in the yourappname-app.xml file. Note if you image icon isn’t the absolute correct size you’ll get a compiler error:

<icon>
     <image16x16>assets/appicon16x16.png</image16x16>
     <image32x32>assets/appicon32x32.png</image32x32>
     <image36x36>assets/appicon36x36.png</image36x36>
     <image48x48>assets/appicon48x48.png</image48x48>
     <image72x72>assets/appicon72x72.png</image72x72>
     <image114x114>assets/appicon114x114.png</image114x114>
     <image128x128>assets/appicon128x128.png</image128x128>
</icon>

2. Manage your applications life-cycle. The best article to read is the old but still very useful Hero View and ViewNavigator  РFunctional and Design Specification and this blog post on Understanding View and ViewNavigator. For some reason the ViewNavigatorEvent poperties listed below aren’t documented in the Adobe on-line help. I’ve complained and so should you!

  • viewActivate Event ‚Äď called when the view is fully activated. It actually happens after the creationComplete event. If you want to know more about view states in general then read this Adobe article.
  • viewDeactivate Event ‚Äď use this in a View if you want to handle certain things when the user changes to a different View and the current¬†one has been deactivated.
  • removing Event ‚Äď This is called right before the viewDeactivate Event. So if there is something you want to do right before the view is fully deactivated then use this event.
  • persistNavigatorState ‚Äď This property works at the application level and allows you to save the navigator‚Äôs view stacks and navigation history to a local persistent object. This is a property that is set in the main application‚Äôs mxml file and by default it is set to false. The standard architecture of a mobile app is to destroy the view contents when a user switches views so that the application saves memory. But, if there is a significant cost to destroying and recreating a particular view then you should test setting this property to never. Cost in this case means the amount of time, memory and CPU it takes to destroy and recreate a view. Also, if your end user is repeating this over and over that will ultimately affect battery life. Once a view is destroyed my guess is that memory is set for garbage collection. For info see this very informative Adobe blog post.
    <s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
         xmlns:s="library://ns.adobe.com/flex/spark"
         persistNavigatorState="true">
    
  • destructionPolicy ‚Äď This is a property that can be set on individual views and can prevent an individual view from having all its data destroyed when the view is deactivated. For example, you may allow some views to be destroyed where others are mission critical and shouldn‚Äôt be destroyed because it‚Äôs too expensive to recreate them. As I write this, I believe this only works if the persistNavigatorState property has been set but it‚Äôs been a while since I verified that.
    <s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
    		xmlns:s="library://ns.adobe.com/flex/spark"
    		destructionPolicy="never"
    		viewActivate="settingsViewActivateHandler(event)"
    		viewDeactivate="settingsViewDeactivateHandler(event)">
    

3. Manually changing views. Use pushView(), popView(), popToFirstview(), popAll() and replaceView().

  • pushView() navigates the user to a new screen.
  • Use popView() to move back to the previous screen.
  • popToFirstView() changes to the screen to the very first view that was opened. This is programmatically referred to as the view at the bottom of the view stack and uses the FIFO principal.
  • popAll() returns a blank screen. I‚Äôve never used this and I haven‚Äôt come across a use case (yet) that would require given the user a blank screen.
  • replaceView()¬†removes the current view and replaces it in the view stack with the new view you that you assign.

4. Passing data between views. One of the requirements of commercial apps is sharing data between different views. There are a number of ways to do this including singletons, dependency injection and using the data property in the pushView() method. Here are some good articles on all three:

  • Using singletons or tightly coupling data. This is typical for prototyping where you don‚Äôt want or need the overhead of a full framework. The prototype app download (link at top of page) uses a singleton model for simplicity.
  • Using framework-based, dependency injection. Use this when you want to use a framework such as Swiz, Parsely or Robotlegs.
  • Using the pushView() data property. When you have fairly simple data needs use this via the pattern pushView(viewClass:Class, data:Object = null, context:Object = null, transition:spark.transitions:ViewTransitionBase = null) Note that this pattern is for basic usage and the data object only supports standard content within the object such as Strings, Array, ArrayCollection, etc. If you have a custom class be sure to register them with the registerClassAlias() method or you‚Äôll get runtime errors when you go to switch views.

5. Set application permissions.These are root permissions that are set via manifestAdditions for Android and infoAdditions for iOS ‚Äď and these are located in the yourappname-app.xml file in your application‚Äôs root directory. Here‚Äôs an Adobe article with additional details. When the application is installed the user will be alerted to what permissions you are asking for.

<android>
     <manifestAdditions><![CDATA[
          <manifest android:installLocation="auto">
	       <!--See the Adobe AIR documentation for more information about setting Google Android permissions-->
	       <uses-permission android:name="android.permission.INTERNET"/>
	       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
	       <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
	       <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
               <uses-permission android:name="android.permission.WAKE_LOCK"/>
               <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
               <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
	   </manifest>
	]]>
     </manifestAdditions>
</android>

6. Shutdown the app. This only works on Android. On iOS, the user has to do this manually.

NativeApplication.nativeApplication.exit(); 

7. Temporarily disable the screen saver. This is required in apps where you don’t want the screen to go to sleep such as navigation apps where it may be open for a long time without any user intervention. You also need to set the WAKE_LOCK permission in the manifest file.

<uses-permission android:name="android.permission.WAKE_LOCK"/>

 

//Make sure we are on a mobile device and then
//keep the application awake so it doesn't go to sleep and close the screen.                                                      
if(Capabilities.cpuArchitecture == "ARM")
{                                                                             
     NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;                                                                            
}

8. Detecting when phone rotates. If you need to know when the phone rotates use this listener:

stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGE,stateChangeHandler);

9. Gracefully fail when network connection is lost. If your app needs network access then it’s a best practice to gracefully fail and let the user know when internet connection is lost and then again when it’s restored.

public function NetworkChangeController(autoStart:Boolean = false)
{             
    var req:URLRequest = new URLRequest(_MAP_URL);
    _urlMonitor = new URLMonitor(req);
    _urlMonitor.addEventListener(StatusEvent.STATUS,serviceMonitorStatusHandler);

    NativeApplication.nativeApplication.addEventListener(Event.NETWORK_CHANGE,networkChangeHandler);
}

private function networkChangeHandler(event:Event):void
{
     if(!_urlMonitor.running)
     {
          _urlMonitor.start();
     }
}

private function serviceMonitorStatusHandler(event:StatusEvent):void
{
     trace("Network Status Event: " + event.code + ", " + _urlMonitor.available);
     _urlMonitor.stop();
     event.code == "Service.unavailable" ? _doSomething = false : _doSomething = true;
}

10. Multiple Device Support ‚Äďsizing for different dpi‚Äôs. Last, but not least is using CSS and media queries to help with sizing and layout. Media queries are actually part of the W3C core CSS spec. The cool thing about them is they let you auto-majically detect the users screen dpi (dots-per-inch) and operating system and adjust your CSS accordingly. This saves a huge amount of work on your part:

@namespace s "library://ns.adobe.com/flex/spark";
/* DPI specific styles */
s|Button{
     color:#000000;
     fontWeight:bold;
}

@media (application-dpi:240)
{
     s|Button{
          color:#FF0000;
     }
}

@media (application-dpi:320)
{
     s|Button{
          color:#0000FF;
     }
}

/* Platform specific styles */
@media (os-platform:"IOS")
{
     s|Application{
          backgroundColor:#FFCCCC;
     }
     
     s|ActionBar{
          defaultButtonAppearance:beveled;
     }                      
}

@media (os-platform:"Android")
{
     s|Application{
          backgroundColor:#CCCCFF;
     }
}
Tags: , , , , , , , , , , , , , ,
Posted in ActionScript, Android, Flash Player, FlashBuilder, iPhone, Mobile | 9 Comments »

Debugging Flex-AIR apps on iPhone and iPad

Debugging iPad or iPhone apps that you built with FlashBuilder has a number of extra steps that you don’t need when developing with Android. This is especially true if you use Windows as your primary operating system. The good news is that once you’ve done it once or twice it should be fairly straight forward. So here are a few hints to get you going.

Step 0. If you¬†are building on Windows make sure¬†to install the latest version of iTunes.¬†Then¬†check that your iPad or iPhone can be synched with iTunes.¬†If you use a mac you’ve¬†most likely¬†already done this step (in your sleep a hundred times).

Step 1. Make sure you have a certificate and provisioning file. This must be configured under FlashBuilder Project > Properties > Flex Build Packaging. IMPORTANT: If the certificate and provisioning file are not set up or are not valid you will not be able to compile your project. If you don’t know what this is or how to do it, additional info can be found here in a great blog post by Holly Schinsky (@devgirlFL).

Step 2. Set up a Debug Configuration. If you don‚Äôt know where that is, select the pulldown next to the bug icon on the FlashBuilder toolbar and then choose Debug Configuration, or go to Run > Debug Configurations. Choose Apple iOS as your Target Platform. Be sure to select the On Device¬†Packaging Method > Fast! If you don‚Äôt do this and you choose the Standard option¬†it will take five or more minutes to compile the build each time you hit debug, and that can become a huge time waster really fast. One advantage of using the Standard option is it will perform more like the final release build.¬†In comparison,¬†the Fast version won’t be as performant. So, for the vast majority of your debugging you should probably use Fast, and when you want to test a final build then you might want to choose Standard. When you are ready select the Debug button.

Step 3.  You will then see a popup window with six important instructions. Once you have completed Steps one and two, select the Show package in Explorer link.

Step 4. Drag the .ipa file from your file browser window into the iTunes Library > Apps area.

Step 5. Select the Sync button on the bottom right hand corner of iTunes. You should see Sync In Progress screen on your device. Let the operation complete. When it’s finished you should see a message in the message box at the top of iTunes that says the sync was successful. If there was an error it will also show up in the message box at the top of the iTumes application window.

Step 6. Launch the application on your iPad or iPhone. You should get a popup window¬†titled Flash Debugger that asks for the IP address or hostname. ¬†Important: ¬†your¬†iPad or iPhone¬†and your development machine need to be on the same wireless LAN, if they aren’t then this step won’t work. If you don’t have a wireless LAN handy you can always log both machines into a MiFi or some other type of mobile hotspot. Then enter the IP address of your development machine. On a windows machine you can easily get that in a DOS prompt using the command ipconfig. Hit OK.

The Final Result. If all goes well the app will launch and you will start to see debugging output in FlashBuilder.

Tags: , , , , , , ,
Posted in ActionScript, Android, FlashBuilder, iPhone, Mobile | 3 Comments »