Different code for different versions of Flash Player

306 views Asked by At

I'm writing an universal graphics engine that will work on FP11 using molehill advantage and also works in FP10 using old software blitting.

So, I'm woundering what is the best way to achive this?

First I thought that if I will compile swf for FP11 and will not use new classes if the version of player is not 11, everything will work fine. But I was wrong. To my surprise I'm getting "VerifyError: Error #1014. Couln't find class flash.display3D::Context3D" error if I run code with imported FP11 libraries even if they are not called.

I thought FP will throw this message only when I will try to access an absent class, but that is not right. It throws error just when I'm trying to run .swf

So, is there any way to do it? I thought of loading different SWFs depending on the version using preloader, but maintaining and compiling 2 different SWFs is quite confusing.

Are there any other ways?

3

There are 3 answers

0
starmole On

flash apis are not forward compatible. if you want a flash 11 api, you need to make a flash 11+ swf. the reason for this is that a swf 10 could happily create it's own Stage3D class. if it suddenly would conflict with the built in class in swf 11 this would break backwards compatibility. so you can have only one, backward or forward compatibility.

0
xxbbcc On

If you're using Flash (as opposed to Flex or some other tool), your only option may be conditional compilation, I believe. When I had to deal with this in CS5, I couldn't find anything else.

What I ended up doing was I defined several constants for the various configurations and then I compiled several versions of the .swf. I loaded the right .swf file based on player detection code in the browser. It's really a mess if you want your .swf on places like Newgrounds, etc.

0
skozin On

Edit

Sorry, I didn't notice that you don't want to support different versions of the library. In this case there is no way — when FP processes the bytecode of an SWF and when it finds an unknown reference, it throws VerifyError. Of course, you can use getDefinitionByName() and dynamic access, but it's very slow.

To minimize the amount of separately supported code, you can use an SWC with main functionality and SWFs with version-dependent functionality, so at the stage of initialization the main class of your lib will check FP version and load the appropriate SWF.


This is called dynamic linking, and there is a way:

  1. Create an interface of all player version dependent functionality (public interface MyInterface...). This interface should not contain any references to version dependent APIs. Compile this interface (it may be just single .as file) into SWC (let it be lib-intf.swc).

  2. Create two independent implementations of this interface; the first will use the new APIs, the second won't (it may be just a placeholder, but also may be an alternative implementation). Later we'll need to compile these implementations into SWFs, so we need main classes that extend Sprite. The simpliest way to do the trick is to make these main classes implement our interface (i.e. public class MyImplementationA extends Sprite implements MyInterface..., and the same for MyImplementationB). They will be just empty Sprites, but they will contain interface methods.

  3. Compile these two implementations independently into separate SWFs (lib-a.swf and lib-b.swf). When compiling, include lib-intf.swc as an external library (-external-library-path compiler parameter or "external" linking type in IDEs).

  4. Now, when compiling your root application, include lib-intf.swc as usual library (-library-path compiler parameter or "merged into code" linking type in IDEs). Don't include version-dependent classes at all. Thus, in the root application you will have just references to the interface, which is version-independent. When your application starts, check FP version, and depending on it load appropriate SWF using Loader class. You'll have to load it into the main application domain, not a child of it (which is default option; more details).

  5. When the SWF is loaded, cast it to the interface: var versionDependentImpl:MyInterface = loader.content as MyInterface. Remember that main classes of our SWFs implement MyInterface, so this cast would work.

  6. That's it — now you can use your implementation: versionDependentImpl.someMethod(). Of course, someMethod should be defined in MyInterface.

So, the trick here is to dynamically load implementation from an SWF file. Though the root application doesn't know anything about classes inside this SWF, we can use methods of it's main class because we made it implement an interface that we have compiled into the root application.

This approach is scalable: for example, you can define main interface which have methods that return other interfaces. You can even include concrete classes that are shared between implementations into lib-intf.swc, as long as they don't use version-dependent APIs.