AIR Mobile loading time and splash screen preloader partial solution

Whilst testing an AIR mobile app I’ve noticed on first initialization a black screen is displayed for around six seconds. Initially researching around online it seems this is a problem a lot of people have experienced, even with very small programs. I’ve recorded how I went about trying to solve this problem here for anyone else that comes across it.

The issue seems to be caused by the time it takes for the air runtime to load up. First this is more of a problem on Android, as iOS requires a splash screen image to be packaged with the app that is displayed while the app is loading. Flex does offer a solution to this problem using ViewNavigatorApplication with the splashScreenImage property. I code in pure as3 with FlashDevelop, so to use this solution I had to wrap my as3 code in a mxml document. I found a good solution for wrapping pure as3 in MXML here (http://stackoverflow.com/questions/141288/possible-to-use-flex-framework-components-without-using-mxml). This worked, but didn’t offer a solution to my problem as I was still seeing a black screen for around 6 seconds, then the splash screen for a second, then the app. I had hoped that the splash screen image would be displayed before the air runtime was initialized but that isn’t the case. This means that when using AIR with Android you will always have this problem, although I’ve read in places that its less of a problem on newer phones. It also means that if you prefer to program in pure AS3 but wanted to use the splashScreenImage functionality of ViewNavigatorApplication you can easily make your own pure as3 splash screen that’s just as functional.

Essentially the splashScreenImage functionality is just a preloader built into flex and since flash developed on the web making preloaders for our flash programs is something most flash developers are used to. If you use FlashDevelop you should be familiar with the AS3 project with preloader project template. The same method used there also appears to work for mobile phone apps (I haven’t tested this thoroughly yet). I’ve pasted the code below of how I put a preloader into my AIR Mobile AS3 app.

Main Class

package 
{
import flash.desktop.NativeApplication;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;


/**
 * ...
 * @author Walex
 */
[SWF(backgroundColor='#FFFFFF', frameRate='30')]
[Frame(factoryClass="Preloader")]
public class Main extends Sprite 
{
	
	public function Main():void 
	{
		if (stage) init();
		else addEventListener(Event.ADDED_TO_STAGE, init);			
	}
	private function init(e:Event = null):void 
	{
		removeEventListener(Event.ADDED_TO_STAGE, init);
		
		// entry point
		stage.scaleMode = StageScaleMode.NO_SCALE;
		stage.align = StageAlign.TOP_LEFT;
		stage.addEventListener(Event.DEACTIVATE, deactivate);
		
		// entry point
		opaqueBackground = 0xEEEEEE;
		
		
	}
		   
	private function deactivate(e:Event):void 
	{
		// auto-close
		//NativeApplication.nativeApplication.exit();
	}
	
}
	
}

 

Preloader Class

package 
{
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.utils.getDefinitionByName;
import flash.desktop.NativeApplication;

/**
 * ...
 * @author Walex
 */
public class Preloader extends MovieClip 
{
	
	[Embed(source="../icons/ios/Default-Portrait.png")]
	private var splashScreenImage:Class;
	private var splashScreen:Bitmap
	
	public function Preloader() 
	{
		if (stage) {
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
		}
		addEventListener(Event.ENTER_FRAME, checkFrame);
		loaderInfo.addEventListener(ProgressEvent.PROGRESS, progress);
		loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioError);
		
		// Show Splash Screen
		stage.addEventListener(Event.DEACTIVATE, deactivate);
		splashScreen = new splashScreenImage() as Bitmap;
		addChild( splashScreen );
		
		//Resize Splash screen to fit the screen (comment this out if you don't want the graphic resized)
		var wScale:Number = stage.stageWidth / splashScreen.width;
		var hScale:Number = stage.stageHeight / splashScreen.height;
		if (wScale < hScale) {
			splashScreen.scaleX = wScale;
			splashScreen.scaleY = wScale;
		}else {
			splashScreen.scaleX = hScale;
			splashScreen.scaleY = hScale;
		}
		
		//Position splash screen
		splashScreen.x = (stage.stageWidth - splashScreen.width) / 2;
		splashScreen.y = (stage.stageHeight - splashScreen.height) / 2;
	}
	
	private function ioError(e:IOErrorEvent):void 
	{
		trace(e.text);
	}
	
	private function progress(e:ProgressEvent):void 
	{
		// TODO update loader
	}
	
	private function checkFrame(e:Event):void 
	{
		if (currentFrame == totalFrames) 
		{
			stop();
			loadingFinished();
		}
	}
	
	private function loadingFinished():void 
	{
		removeEventListener(Event.ENTER_FRAME, checkFrame);
		loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progress);
		loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioError);
		
		// Hide SplashScreen
		removeChild( splashScreen );
		splashScreen.bitmapData.dispose();
		splashScreen = null;
		splashScreenImage = null;
		
		startup();
	}
	
	private function startup():void 
	{
		stage.removeEventListener(Event.DEACTIVATE, deactivate);
		var mainClass:Class = getDefinitionByName("Main") as Class;
		addChild(new mainClass() as DisplayObject);
	}
	
	private function deactivate(e:Event):void 
	{
		// auto-close
		NativeApplication.nativeApplication.exit();
	}
	
}
	
}

The code above embeds the Default-Portrait.png that would be used as the iOS splash image into the preloader. It’s then resized and positioned in the center of the screen. There is also a function in place if you want to put in a loading animation. After the app is loaded the splash screen image is then removed from memory. This should help to limit the amount of time the black screen is visible on Android, particularly if the app your loading is very large. It may also help for iOS as I’ve read elsewhere that the default iOS splash screen disappears once the runtime is loaded, and displays a blank black screen whilst the app is being loaded. This method of preloading also has the advantage of producing a single SWF, where as other’s I’ve seen use a seperate loading SWF. This can be a life saver if you need a preloader but are worried about apple rejecting your app because it contains more than one SWF.

It should be possible to make a native java wrapper for Android AIR apps that display a splash screen whilst the AIR runtime is loading up, but I haven’t found this solution anywhere. If anyone comes across a way of doing that please post it here. I may look into making my own splash wrapper in the future with Java or Haxe, but it will have to wait for now.

7 thoughts on “AIR Mobile loading time and splash screen preloader partial solution

  1. Came across your post after looking for a solution myself. If you do figure out the java wrapper, I would be interested to see it in action. Newer phones do cut down on the load time.

  2. Your quick tutorial was quite brilliant. There is little material on the internet on how to build preloaders and yours was a breath of fresh air. While, like you said, it’s only a partial solution, I’ve managed to integrate it into my app quite well, with a few modifications, turning it into a full and operational preloader. Hope you don’t mind, but I’ve written about it and used your code for the most part (with giving credit, of course):
    http://verysimpleideastudios.com/actionscript3/pure-actionscript-3-preloader

  3. Hi Walex, thanks for sharing your code.

    Are there any compiler arguments required for this to work since Preloader class is not invoked when I try to compile it… Also, just to confirm, your Document class is Main? P.S. I’m working with pure AS3 project.

    Best regards,
    Vjeko

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>