1
votes

I have an iOS application for a catalog that loads assets (with no ActionScript) from a remote server, so those assets (a catalog), can be updated by the catalog editors in order to create a new issue of the catalog every month.

Air for iOS allows you to load SWF files without ActionScript code on them. So I´m loading my assets from external SWF files and testing succesfully by compiling in Ad Hoc, or App Store modes.

Some of those assets are animated movieclips (with intenal movieclips, several frames and motion animations) which need to be instantiated several times (a random number of times) in the app, for an interactive feature.

SOME BACKGROUND:

  • The standard way to create repeatable items is by assigning them a Linkage Class Name in the Flash IDE, which works fine for desktop apps, but this seems to be interpreted as code by iOS, so it is not imported when I load the assets, so the element can not be instantiated from the APP.
  • There are several attempts to replicate the old as2 duplicateMovieClip function but they don´t duplicate internal movieclips, motions and internal movieclips. This is an example.
  • In this question, they say it´s not possible and propose a solution in which the movieclip has to be included in the main app, but in that way the editors would not be able to update the graphics and the animations once the app is approved in the store. The whole point is to allow the editor to update the products catalog.
  • Here is an additional discussion about the topic.

POSSIBLE SOLUTIONS TO EXPLORE:

  • I´m thinking of implementing some kind of recursive iteration creating every DisplayObject from scratch, but I still can´t find a concistent way to duplicate a shape created by the editor in the Flash UI. In fact, they say it´s not possible either, all that can be done is to create "bitmap" copies which is likely to be too heavy in processing specially if one create too many copies.
  • I guess, probably the only way is to find some compilation hack to make let the external SWF define the new Class so the instance can be created in the main app. For now, the editor is not going to be able to change duplicable objects.
  • There is also the possibility of having the duplicable element in a separate SWF, and load it several times, but I don´t know if that would work although that would be a little unglier for the designer.
  • I also tried to serialize an unserialize the whole movieclip, but I have not been able to find a concistent method for that either.

A note for the developers of Adobe Flash : The ARM/iOS implementation of the AS3 Loader class should be changed to include the linked classes in the execution context, because the developer expects to be able to instantiate movieclips with a linked class even if they are contained in an external SWF loaded from an iOS air application. Currently the instantiation fails in iOS-air, but it works fine in desktop. I understand that apple does not allow the execution of code loaded from the external SWF, but this is not code execution, this is just a Class linkage that can be used to create multiple instances of the movieclip from the actual application code.

Can anyone help?

1
Try allowCodeImport with LoaderContextRajneesh Gaikwad
Doesn´t work. I was usign new LoaderContext(false, ApplicationDomain.currentDomain, null), so I included loaderContext.allowCodeImport = true;, but no luck.jacmkno

1 Answers

1
votes

Had the same issue myself, and I ended up using the duplicated symbol on the stage of the external SWF. I duplicated the symbol about 30 times on the stage

I named the instances sequentially, e.g. card0 card1 card2 etc

Then in the code, I have a for loop that gets a reference to these objects, inside the loaded SWF, and puts them in an pool (Array) and then removes them as children from the external swf

The garbage collector doesn't seem to delete the objects, as they are still referenced by the Array

I then have code that manages the allocation of items from the pool, rather than instantiating them.

It does make the external swf a bit bigger, but not much for the 30 items in my pool as they are only references to the symbol in the library

You could write a JSFL script to do the duplication and naming in the FLA to automate the process.

BTW.

I tried a few other (cleaner) methods, but none of them worked on iOS

On the PC I was able to get the class definition from the symbol inside the external SWF if I marked it as Export For ActionScript, and then instantiated the class. e.g.

applicationDomain.getDefinition("Card") as Class;

Note. I set the loader context

var ldrContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain );

for the loaded swf to be the same as the current application domain, as otherwise iOS isnt able to load and use the SWF at all.

However this only worked on the PC and strangely not on the Mac (OSX).

My next attempt was to put one copy of the symbol on the stage and use e.g.

_cardSWFClass =  Object(_contentSWF.card).constructor;

where contentSWF is MC object of the externally loaded swf, and "card" is the instance name on stage of of the object to be cloned.

This method works on both the PC and the Mac, but not on iOS

However, I have a feeling that this was only working, on PC and Max, because, I may have had the same class name in the FLA that was loading the external SWF, as the external SWF, as I'd copied the symbol from the App to the external content.

It also makes me wonder if whether it would be worth trying having the external MC use the same package name as the App code, rather than the external swf that was loaded in my case didn't have a class or package name defined for the SWF

i.e define empty classes in the App FLA / code, and in the external SWF reference the same class names, within the same package as the App FLA.

These classes would probable need to be empty (possibly no AS file at all), as iOS is not supposed to load external SWF's that contain code. However in practice it seems that iOS will load external SWF's that contain timeline code, but the code is removed by the loader.

Further avenues to explore could be the method that is available to build code for externally loaded SWF's inside the core App code, and which is somehow bound at run time.

A byproduct of this may allow instantiation of external symbols (in fact I guess it would definitely need to, otherwise it seems pointless)

i.e as in this overview http://blogs.adobe.com/airodynamics/2012/11/09/packaging-and-loading-multiple-swfs-in-air-apps-on-ios/

However time pressures prevented me from exploring this any further.

Edit. Ignore the link. I think its a red herring.

Edit 2.

I have a partial, solution which may work for some people.

My hunch about using the same package names and class names in both the class that loads the SWF and the external SWF itself seems to be correct.

However it only works using this method where there is an instance of the symbol on the stage of the external content, which can be used to access the constructor for the external symbol. It doesn't seem to work using the getDefinition method.

e.g. this code gets the Class of the instance called "card" in _contentSWF

_cardSWFClass =  Object(_contentSWF.card).constructor;

Also note, that on the PC (though not on the Mac and possibly not on the iOS), it was necessary for the Class in question to define all of its named sub objects i.e as if you were not automatically declaring instances on the Stage.

In my case, my "card" symbol had a TextField named txt, and some other attributes I needed to store data, so I had to add these to the class e.g.

package DragAndDrop 
{
    import flash.display.MovieClip;
    import flash.text.TextField;

    /**
     * ...
     * @author Roger Clark
     */
    public class Drag extends MovieClip 
    {
        public var txt:TextField;
        public var originalX:Number;
        public var originalY:Number;
        public var itemData:XML;
        public function Drag() 
        {

        }

    }
}

One Note.

The Class that is instantiated is not DragAndDrop.Drag (or just Drag) i.e although both PC and Mac report that trace(_cardSWFClass); is [class Drag] on the Mac this fails at runtime and gives an error #1034 (Type Coercion failed) as the runtime type was reported as DragAndDrop.Drag@9a40e51 on my Mac

So its necessary to declare the object type as :MovieClip that is instantiated. It doesn't seem to be possible to cast it to Drag (only to MovieClip)

Just one caveat. I've not done extensive testing to see if there are any other limitations to this, but it does appear to work for me using AIR 4 and iOS6.

Edit 3.

I just spotted one more thing. Its not necessary for the Class source file to be accessible by the external FLA when the SWF is "published". I realized that I had accidentally got the paths wrong, and that my external FLA didn't have access to the class AS file, and was creating its own empty class definition on the fly.

I retested it, with the correct paths, and it didn't seem to make any difference, i.e it still worked on PC, Mac and iOS

Additionally, I tried to remove the properties from the external Class definition file, for items which were not defined in the external FLA e.g. originalX and originalY, but without these, I get runtime errors on the PC.

I find these runtime errors quite strange, as I'm declaring the class that is instantiated as being a MovieClip and MovieClip is a dymanic class. So its as if Flash considers the class that its instantiating to be some special type of non-dynamic MovieClip

Edit 4.

I've come across another caveat to this work around. It appears that, under some circumstances, the symbols that are needed for duplication (by accessing their constructor), need to be present on frame 1 of the external SWF, and possibly all other frames in the external MC.

If you attempt to get the constructor of these instances, and they are not present on frame 1, the class that Flash returns is just MovieClip and not the class that has been defined for the symbol (defined in the library). Note. The symbols are marked for export on frame 1, so that's not the reason.

At the moment, I'm not entirely sure the exact circumstances when this occurs, as it may be something to do with the path the external swf is loaded from, or it could be caused when an AIR app loads the external SWF.

i.e it works OK when I load the SWF directly into another SWF (on the PC), but fails (on the PC) when the external SWF is loaded from an SWC which is compiled as part of an AIR App.

I will post more information if I ever get to the precise cause of these discrepancies.

Edit 5.

This is a bit of an ongoing saga.

I have found one issue with using this approach. On iOS you need to load the SWF into the current ApplicationDomain, otherwise the SWF can't be used at all. However, if you load different SWF's with symbols in them with the same class name, Flash caches the first instance (symbol) that is instantiated using this method.

The normal work around for this is to create a new Application domain for each swf that is loaded, and release the domain afterwards. See ApplicationDomain clarifiation needed

However this doesn't work on iOS as you appear to always need to load into ApplicationDomain.current domain

See problems with loading embedded swf files in air app

So although my work-around does work, it will not be of much use if you want to load multiple external swfs each with symbols with the same class name, but different graphic content.