суббота, 29 сентября 2012 г.

Flex compiler mxmlc extensions. Forcing compiler language.

Few people know, that there's a possibility to create extensions for mxmlc compiler adding some custom functionality (https://bugs.adobe.com/jira/browse/SDK-18718). In this post I'm going to write a short guide describing creating and applying extension process.

First of all you'll need Flex SDK version 4.1+ and JDK.
Create new java project and set location {FLEX_HOME}\lib as a libraries location directory. Flex provides us several types of extensions:

  • IApplicationExtension (Defines the API for extensions, which run at the end of a OEM API application compilation)
  • ICompcExtension (Defines the API for extensions, which run at the end of a command line library compilation)
  • ILibraryExtension (Defines the API for extensions, which run at the end of an OEM API library compilation)
  • IMxmlcExtension (Defines the API for extensions, which run at the end of a command line application compilation)
  • IPreCompileExtension (Defines the API for extensions, which run before each compilation)
  • IPreLinkExtension (Defines the API for extensions, which run before each PreLink run. PreLink's run can be executed multiple times)

Each of the extensions runs in a different phase of compilation.
We're to see how it works on  IMxmlcExtension example, which runs after flash project is compiled. Create a class implementing  IMxmlcExtension interface and implement run method.

import flex2.compiler.extensions.IMxmlcExtension;
public class MyMxmlcExtension implements IMxmlcExtension
 public void run(String[] strings)
  System.out.println("Hello from mxmlc extension!");

 We're going just print a message and see, that extension is running. We need to build jar.
The next step is editing manifest file. We should add the following line to MANIFEST.MF to let flex compiler know, where is our extension  extensions-mxmlc: MyMxmlcExtension
Ok, now we can compile the jar including edited manifest file (don't include libraries jars in the output jar).

So, we can create new flex project to test the extension. Put extension jar in the project root. To enable extension we need to pass extension file as the following parameter to mxmlc arguments  -extension=MyExtension.jar (relative path basedir is project root, or you can use absolute path). Ok, finally, we're ready to compile flex project and see the result.
It works :)

Ok, let's do another thing. Sometimes it happens, that compiler cannot display output correctly if it's not English (I faced problem of cyrillic symbols many times), because compiler uses operating system language. So, let's force compiler to use english regardless of system language. We're going to create IPrecompileExtension

import flash.localization.LocalizationManager;
import flex2.compiler.*;
import flex2.compiler.common.Configuration;
import flex2.compiler.extensions.IPreCompileExtension;
import flex2.compiler.util.ThreadLocalToolkit;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class MyPrecompileExtension implements IPreCompileExtension
 public void run(FileSpec fileSpec, SourceList sourceList, Collection<Source> classes, SourcePath sourcePath,
     ResourceContainer resourceContainer, ResourceBundlePath resourceBundlePath,
     CompilerSwcContext compilerSwcContext, SymbolTable symbolTable, Configuration configuration,
     SubCompiler[] subCompilers, PreLink preLink, Map map, List<Source> sources)
  LocalizationManager m = ThreadLocalToolkit.getLocalizationManager();

Add extensions-pre-compile: MyPrecompileExtension to MANIFEST.MF and build jar file. Now we'll see English only.

So, you see, that extention is a really nice tool, but it's not ducumented unfortunately, and it's up to us to explore it.

вторник, 12 июля 2011 г.

Exploring Flex Proxy class

Proxy is a rather interesting class. It gives you an opportunity to override basic behaviour of some actionscript 3 operators (such as "for each...in", "for...in", "delete", "[]"). You cannot create Proxy instances directly, you must override it and override needed methods.
Proxy is a good class to build enumerable collections. Let's create a custom collection, which overrides Proxy and implements some its basic behaviour.
First I'm going to implement enumeration logic. There are 3 methods in Proxy class, which will help us:

nextNameIndex(index : int) : int
nextName(index : int) : String
nextValue(index : int) : *

nextNameIndex is called within each iteration in "for each...in" and "for...in" loops. It receives index, which is being incremented every iteration by 1 (starting with 0). In this method you're supposed to return an int, which will be next passed to nextValue ("for each...in") or nextName ("for...in"). An important moment here: you return 0 to stop the loop.

There'll be an array as the source of our collection.

flash_proxy override function nextNameIndex(index : int) : int
 return index < source.length ? index + 1 : 0;
flash_proxy override function nextName(index : int) : String
 return (index - 1).toString();
flash_proxy override function nextValue(index : int) : *
 return source[index - 1];

Pay attention, that all methods are declared in flash_proxy namespace, so don't forget to add  "use namespace flash_proxy" before class declaration.
As you see, we return (index + 1) in  "nextNameIndex", because we cannot return 0 as index. But we use (index - 1) in "nextName" and "nextValue".

To override "[]" operator we should implement "getProperty" and "setProperty" methods.

flash_proxy override function getProperty(name : *) : *
 if (name is String && !isNaN(parseInt(name)))
  return source[int(parseInt(name))];
  return undefined;
 flash_proxy override function setProperty(name : *, value : *) : void
 if (name is String && !isNaN(parseInt(name)))
  source[int(parseInt(name))] = value;
  throw new Error("Illegal index");

Using our class:

var col : CustomCollection = new CustomCollection();
for (var i : int = 0; i < 3; i++)
 col[i] = i.toString() + "str";
trace("For each loop:");
for each (var elem : * in col)
trace("For loop:");
for (var key : String in col)
 trace("Key: " + key + ", value: " + col[key]);

 More info about Proxy class you can find here.

пятница, 22 апреля 2011 г.

Creating and applying custom preloader to Flex application (part 2)

In part 1 I created custom preloader for Flex app using Flex API (IPreloaderDisplay). In this post I'm going to apply my preloader through loading Flex compiled SWF. Here I'm using the same SWC with progress bar movieclip as in part 1.

Main steps:

1. Create pure AS3 application.
2. Show custom preloader.
3. Load external SWF with Loader.
4. Catch loading events, update preloader view.
5. Pass flashvars to loaded application.
6. Hide preloader, show application.

четверг, 21 апреля 2011 г.

Creating and applying custom preloader to Flex application (part 1)

I'm sure, you can find much information on this issue on the internet, but i'll try to explain the process in a detailed way, that it'll be easy to understand. I'm going to show you 2 ways of creating and applying your custom preloader for Flex application.