Packaging and loading multiple SWFs in AIR apps on iOS

In AIR SDK 3.6 for iOS, there is a new feature that allows application developers to be able to package and load secondary SWFs that contain ActionScript byte code (or ABC) in their apps. Presently, due to certain restrictions on iOS, AIR on iOS requires that all the ActionScript code of an application be present in the main SWF or the root SWF. With this feature, an application developer can have ActionScript code in local secondary SWFs and package them along with the main SWF.

A bit of background

AIR apps on iOS can be compiled either in AOT (ahead of time) mode or Interpreter mode. To know more about these modes, please refer to an earlier post on this blog: http://blogs.adobe.com/airodynamics/2012/07/04/aot-or-interpreter/

The AIR Developer Tool or ADT has targets that lets you package apps either for the AOT mode or Interpreter mode. The targets for packaging in AOT mode are ipa-app-store, ipa-ad-hoc, ipa-test and ipa-debug. The targets for packaging apps in interpreter mode are ipa-debug-interpreter, ipa-test-interpreter, ipa-debug-interpreter-simulator and ipa-test-interpreter-simulator. In the interpreter mode, as the SWF is interpreted and not translated to native machine code, hence it runs slower than when in AOT mode. All developers are advised that whenever they publish their apps on the AppStore, they should make sure that they are compiled in AOT mode. To read more about the ADT command and the iOS package targets please refer to: http://help.adobe.com/en_US/air/build/WS901d38e593cd1bac1e63e3d128cdca935b-8000.html

This feature affects only the AOT mode targets and the behavior of the interpreter mode targets is unchanged.

Until now, AIR required that when packaging in AOT mode, all the ActionScript code of an AIR iOS app should be present inside the main SWF. Any SWF other than the main SWF, that is provided at the time of packaging, is added to the final application package (IPA) as a resource. Any attempt to load a SWF (local or remote) dynamically that contains ActionScript byte code (or ABC) using either Loader.load() or Loader.loadBytes,  resulted in an “Uncompiled ActionScript” error. A screenshot of the error dialog is below:

After the user dismisses the error dialog, the behavior of the application is “undefined”. Developers should never ship or publish an app in which the user may see such an error dialog.

Please note that if the SWF that is being loaded dynamically does not contain any ABC and contains only assets like bitmaps or audio, the SWF will be loaded successfully (even with AIR 3.4 and before). In fact, few developers have used this technique, to host asset-only SWFs on web servers and these are fetched only when needed. By downloading asset-SWFs on demand at run-time, developers have been able to reduce the size of their applications.

What has changed ?

In addition to the main SWF, the application developer can now provide a secondary SWF that contains ActionScript bytecode at the time of packaging and then load such a SWF dynamically using the functions provided by Loader. However, while dynamically loading a secondary SWF inside the main SWF, one needs to provide the application domain in which the secondary SWF should be loaded. The AOT mode in AIR on iOS does not support multiple application domains.

Below is a code snippet for loading a secondary SWF that is packaged with the application.

var _urlRequest:URLRequest = new URLRequest(“mySecondarySwf.swf”);
var _loader:Loader = new Loader();
_loader.load(_urlRequest);

 

When the Loader.load() method does not specify a LoaderContext object, then by default, the SWF is loaded in an application domain that is a child of the loading SWF’s application domain. Multiple application domains are not supported in AIR on iOS, and hence the above code will not work on iOS and will result in the following error:

Error 3747: Multiple application domains are not supported on the operating system.

 

To overcome this error, the above code needs to provide ApplicationDomain.currentDomain as the application domain in the LoaderContext object. So the modified code is:

var _urlRequest:URLRequest = new URLRequest(“mySecondarySwf.swf”);
var _loader:Loader = new Loader();
var _lc:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
_loader.load(_urlRequest, _lc);

Loader.loadBytes

There is no change in the behavior of Loader.loadBytes() except for: In AOT mode, if the user attempts to load a SWF using Loader.loadBytes() and if the SWF version of the root SWF is greater than or equal to 19 (i.e. for the given build) then, the user needs to provide an application domain as part of the loader context which should be same as the root SWF’s application domain.

Loader.unload() & Loader.unloadAndStop()

The behavior of Loader.unload() and Loader.unloadAndStop() on iOS is below. When either of these functions is called the following will happen:

  1. The contentLoaderInfo property of the Loader object will become null
  2. Any assets that are loaded with the secondary SWF will be unloaded.
  3. Any references to AS classes in the loaded SWF remain in memory, and new objects of those AS classes can be created. This is different from the behavior on other platforms.

SWF Reloading

In AIR apps on iOS running in AOT mode there is a problem when a SWF is reloaded. Therefore reloading a SWF will not be allowed for AIR apps for iOS in AOT mode and attempting to do so will result in following error:

Error 3764: Reloading a SWF is not supported on this operating system

Note:If a SWF is accessed using different URLs like different paths referring to the same SWF, or using app:// and app-storage:// URI schemes to access the same SWF, then the two SWFs would be considered different and the SWF will be re-loaded. However, the behavior in such cases would be undefined.

Note: Reloading of pure asset SWFs will work with AIR 3.7 builds which can be downloaded from here

A bit about what happens behind the scenes …

The ABC code from the main SWF and all the secondary SWFs is extracted and placed in the main executable. The non-ABC parts of a SWF or assets in a SWF are kept inside the IPA (as assets). They are drawn in memory when explicitly asked using the Loader.load() call.

What will still not work?

1.Dynamically loading a ‘remote‘ SWF, that contains ActionScript code will continue to NOT work.
2.Embedding SWFs(having ABC code) using [Embed] tag will NOT work on iOS.

Where can I get the build?

The build with this feature can be accessed here

To summarize:

For locally packaged secondary SWFs:

  AOT (Ahead of Time) Mode Interpreter Mode
Local secondary SWF with ABC Earlier loading such a SWF gave the uncompiled AS Error.With this feature, this will work Works (unchanged)
Local secondary SWF w/o ABC Works (minor change required)* Works (unchanged)

For remote SWFs:

AOT (Ahead of  Time) Mode Interpreter Mode
Remote SWF with ABC Prohibited by Apple Prohibited by Apple
Remote SWF without ABC Works (minor change required)* Works (unchanged)

*The minor change is that when loading the SWF, the application domain should be the same as that of the main SWF i.e. ApplicationDomain.currentDomain.

Some FAQs

  • What is the loading order of ActionScript code among root SWF, secondary SWFs and ANEs?
    • The loading order is ANE, followed by main SWF, followed by secondary SWFs. This implies that if there is a class with the same name that is defined in the main SWF as well as the secondary SWF, then the class definition of the main SWF will be used.
  • Will I be able to load remote SWFs that don’t contain any ActionScript code?
    • As evident from the above table, the answer to this is YES.
  • Will I be able to use Workers API on iOS?
    • ActionScript workers is not supported on iOS. Worker.isSupported on Mobile (both iOS and Android) would continue to return false.

Points To Note:

  • Conflicting symbols (classes and global functions) in all the packaged swfs should be avoided, they might result into undesired behaviour.

52 Responses to Packaging and loading multiple SWFs in AIR apps on iOS

  1. Rob M says:

    Will the exact same code work on Android as well or will we need to do something different?

    • divij says:

      Yes the same code that works for iOS will work on Android as well. This functionality of allowing the loading of ActionScript bytecode from secondary SWFs is already present for AIR apps on Android.

  2. Pingback: tapzat » Packaging and loading multiple SWFs in AIR apps on iOS « AIR-o …

  3. Alan Lammers says:

    Hi Divij,

    We are working in a App that needs to load a secondary SWF with code, so this functionality is very importatn for us.
    The build you linked here is 3.5.460, but i think the correct build is 3.5.290.
    Could you please post the link to this build or send it to us by mail?

    Thank you very much in advance.

    Regards,
    Alan Lammers.

    • divij says:

      The feature is available in 3.5.290 as well as in 3.5.460. It was disabled in a later build which is 3.5.520. If you face any issues with this build then do let us know.

  4. Ed Guertin says:

    Very interesting to read about this as I have made a system to get around the no ABC code in external swfs problem. Maybe all my hard work is redundant if now AIR for ios can compile as3 code from a secondary swf! I am very confused though… in this article you said near the beginning:

    ‘Until now…. Any attempt to load a SWF (local or remote) dynamically that contains ActionScript byte code (or ABC) using either Loader.load() or Loader.loadBytes, resulted in an “Uncompiled ActionScript” error’

    Then towards the end you said:

    ‘Dynamically loading a SWF, that contains ActionScript code will continue to NOT work.’

    Can the new AIR load external swfs with ABC or not?

    Thanks very much if you have time to answer this.

    • divij says:

      The second statement should read ‘Dynamically loading a remote SWF, that contains ActionScript code will continue to NOT work.’ Missed the crucial “remote”. Thanks for your comment.

    • Jeff Ward says:

      Ed, it works for local SWFs – this means they need to be packaged in the app .ipa file (and hence ABC code is processed by the AOT compiler.) SWFs with code can’t be loaded from a server (remote, unprocessed).

  5. Clint Modien says:

    Does this mean we can load one and only one external swf with abc bytecode in it?

    • divij says:

      No, you should be able to load any number of external SWFs with abc. You just need to provide all such external SWFs at the time of packaging (i.e. when running the ADT command).

  6. James Hunt says:

    Do instance names count as ABC or just actual Classes’s/AS Code?

    Also if you unload and then reload the same SWF with just instance names would this result in the “random behaviour” you talk about?

    • divij says:

      If you have any AS code then your SWF contains ActionScript bytecode. If you only have asset files like JPEGS or mp3s in your SWF files, even then the SWF will contain ActionScript bytecode if you have exported AS Linkages.
      If you unload and then reload the SWF, then the behavior would be random. In some cases it may even possibly crash your application. We are working on this, and it will be modified, when this feature is released in a future AIR version.

  7. Adam says:

    I am currently using one of the 3.5 beta sdk, and am successfully loading swfs with exported linkage ids and creating new instances of them based on those ids. Are you saying that the 3.5 final release I will not be able to do this?

    • divij says:

      If you have secondary SWFs that have exported AS linkages, and if you try load such a SWF, and you compile your app in AOT mode (for iOS), then you would get an “Uncompiled AS warning” error if you try with AIR3.5 final release or any of the previous AIR (final) releases. The same would not happen with the previous AIR 3.5 beta releases.

  8. jian says:

    Could you explain more about the below statements, especially the first one?
    * Local secondary SWF with ABC + Interpreter Mode: Works (unchanged)
    * Remote SWF with ABC + Interpreter Mode: Prohibited by Apple

  9. John says:

    Is a Secondary SWF that contains frame labels and instance names considered a “Secondary SWF with ABC?”

  10. Kelsey says:

    Hi Divij,

    “The feature is available in 3.5.290 as well as in 3.5.460. It was disabled in a later build which is 3.5.520″

    Why has this feature been disabled in the final release? Will it be brought back in future releases?

  11. Ken Patel says:

    Is [Embed] supported or unsupported in this new feature?

    I am using the [Embed] tag to embed my secondary swfs. I installed the linked build of the AIR SDK, set my application.xml to reference 3.5, and added the -swf-version=18 option, but am still getting the ‘Uncompiled Actionscript’ warning dialog.

    Eager to hear back. Thank you very much!

    • Nimisha says:

      Thanks Ken for letting us know about this issue, we’re investigating it.

    • Jeff Ward says:

      Ken, embedding is unsupported. It won’t work because it stores asset bytes directly which bypasses the AOT compilation for the embedded SWF. Use a Loader instead as described above.

  12. Miguel Santirso says:

    Hello, I was very happy to read about this until I saw this:

    “reloading a SWF will not be allowed for AIR apps for iOS in AOT mode”

    If I understand correctly, that makes this new feature completely useless :S The whole point of loading multiple swfs is being able to load resources “on demand” and unloading them when you don’t need them.

    The most obvious use case is a game in which the assets for each level are packaged into one .swf. Then you would load the assets when the player enters a level, unload them when he changes to a different level. But, obviously, I would need to reload the .swf of the first level if the player decides to play it again in the same session.

  13. Gaius says:

    Hi,
    Can you confirm; I need to import SWF display assets, there is ABC in them (not from me, and I don’t use or need it). I had assumed that it was just stripped out and not used during release, but you are saying that there is an error dialog _even_ for release?
    Do you know if there is an option to expressly ignore and prohibit ABC so as to treat the SWF purely a an asset library?
    G

  14. Jason says:

    I see that Beta 3.6 is out. Is this feature working and available in the beta version? Also does Android have any restrictions on loading remote swfs with actionscripting?

    • divij says:

      Yes, this feature is available in the 3.6 Beta. Please set swf-version as 19 to use this feature.
      There are no restrictions when loading remote SWFs on Android.

  15. Yoyo says:

    Dear Divij,
    I try to embed SWF file with ActionScript to IOS application using Adobe Air. I use adobe air 3.6 and flash builder to load the secondary swf (existing SWF as an asset). On compiling I have added “-swf-version=19″, but still no success. The swf is loaded but not the ActionScript.
    This is my code :

    var urlRequest:URLRequest = new URLRequest(“assets/secondFile.swf”);

    // Prepare the loader context to avoid security error
    var loaderContext:LoaderContext = new LoaderContext(false,ApplicationDomain.currentDomain,null);
    loaderContext.allowLoadBytesCodeExecution = true;
    loaderContext.allowCodeImport = true;

    // Load the SWF file
    loader = new Loader();
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onChildComplete);
    loader.load(urlRequest,loaderContext);

    • divij says:

      Are you using the “Embed” tag to package the secondary SWF in your main SWF? Embedding a SWF (with ABC code) will not work.

      However, if a secondary SWF contains ActionScript code, package it via the ADT command (without specifying the “Embed” tag). Also, do make sure to use namespace=3.6 and -swf-version=19.

  16. talata_bao says:

    thanks, I have done but still a little buggy when I removeChild swf file and try to load the file is not.please help me

  17. Julie says:

    It’s great application! If everyone is interested in, here are some adobe.com coupons code: http://sslash.com .

  18. pqbao1987 says:

    Hi divij,

    i’m using method:
    var _loader:Loader
    btn_load.addEventListener(MouseEvent.CLICK,onLoadSwf);
    function onLoadSwf(e:MouseEvent):void{

    var _urlRequest:URLRequest = new URLRequest(“mySecondarySwf.swf”);
    _loader= new Loader();
    var _lc:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
    _loader.load(_urlRequest, _lc);
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadCompelte);
    function onLoadCompelte(e:Event):void{
    addChild(loader);
    }
    }
    btn.addEventListener(MouseEvent.CLICK,onCheck);
    function onCheck(e:MouseEvent):void
    {
    if(loader) removeChild(loader)
    }

    when I removeChild and try reload “mySecondarySwf.swf” file is not,

  19. Andrea says:

    Hi,

    i have install AIR 3.6Beta SDK to Adobe Flash Pro CS6 IDE and compile my iOS application that load external SWF but every time i finished to create .ipa i receive a warning: as code into SWF loaded externaly will not execute into iOS devices.
    What can i do to load externaly SWF? I don’t known how set swf-version as 19.

    Thanks

  20. Lorenzo says:

    What happens if I load a bunch of graphic SWF (no code) and then I unload them to save some space? How can I reload them consequently if I need to show that graphic again?

  21. Luiz Fernando says:

    Is this feature avaiable on 3.5.0.600?

  22. Does this support the loading of nested swfs? i.e. Can a loaded swf load another swf?
    I have been able to get my main application to load 2 child swfs individually but when I have one of the child swfs loading the other, it doesn’t work. I get one progress event from the loader that tells me 0 bytes have been loaded (total bytes also traces correctly). Then the app appears to completely freeze. I am also using the same context object created by the parent swf with the same Application domain.

    • Nimisha says:

      Hi Joshua,

      Nested SWFs are supported and should work. Can you send a sample app (swfs, app-xml and source code)with which you’re facing this issue @nimisha1@adobe.com.

  23. Pingback: (转)Adobe AIR读取本地外部SWF文件的功能概览 | 湖心小筑

  24. Alex says:

    I am using a system whereby any sounds that need to loop are kept in external swfs that I load on arriving at a screen and then unload on exiting the screen. I’ve just discovered that this leads to the problem of not being able to re-load the same swf if I later try to return to the screen. I get the error ’3764 – Reloading a SWF is not supported on this operating system.’
    Is there really no way around this? How does it know that I’ve loaded that swf before?

    • nimisha says:

      Hi Alex,
      1.How does it know that I’ve loaded that swf before?
      Ans: Runtime for iOS has been implemented like this where reloading of a SWF is prohibited.
      2.Is there really no way around this?
      The best way to deal with reload problem is that to not unload a SWF from your app instead just use/un-use it. I don’t know how you’re implementing things in you app’s SWFs but if the SWF is visible then then just make it invisible at the time of un-usage. To use this workaround you need to have different loaders for different SWFs.

      • Alex says:

        Hi nimisha, thanks for your reply. Regarding your suggestion of not unloading the swfs, the problem with this is that i would then quickly run out of memory on mobile devices. I wanted to use this functionality to allow me to load swfs that just contain audio (music) that I wish to loop seamlessly. If I kept each swf (and hence each music loop) in memory, uncompressed, it would use up all available memory.

  25. tom says:

    I have problem too. CAN SOMEONE HELP PLEASE!
    I want to load and reload swfs. It’s not working with air3.6. When I test on PC it’s fine – work well I reload swf meny times. On iPad works only one. I can not reload swf. I put simple code. Can someone help me to fix it?

    stop();
    import flash.events.MouseEvent;

    var myLoaderSWF:Loader = new Loader();
    var mc:MovieClip;

    btnSkyview.addEventListener(MouseEvent.MOUSE_DOWN, initSkyview);
    btnGround.addEventListener(MouseEvent.MOUSE_DOWN, initGround);

    function initSkyview(e:MouseEvent):void
    {
    btnSkyview.visible = false;
    btnGround.visible = true;
    initSlide(“slide_skyview”);
    }

    function initGround(e:MouseEvent):void
    {
    btnSkyview.visible = true;
    btnGround.visible = false;
    initSlide(“state_sampt”);
    }

    function initSlide(_names):void
    {
    unloadSWF2();
    var _loadURL:String = “source/” + _names + “.swf”;
    myLoaderSWF = new Loader();
    //myLoaderSWF.contentLoaderInfo.addEventListener(Event.COMPLETE, loadSWFComplete);
    var url:URLRequest = new URLRequest(_loadURL);
    var loaderContext:LoaderContext = new LoaderContext(false,ApplicationDomain.currentDomain,null);

    myLoaderSWF.load(url, loaderContext);

    //loadSWF is movie clip created on stage puted on layer
    loadSWF.addChild(myLoaderSWF);
    }
    function unloadSWF2():void
    {
    var mcSWF2:MovieClip = myLoaderSWF.content as MovieClip;

    if (myLoaderSWF.content && mcSWF2.totalFrames > 1 && mcSWF2.totalFrames)
    {
    myLoaderSWF.unload();
    }
    }

  26. Pingback: Packaging and loading multiple SWFs in AIR apps on iOS « AIR-o … | S60Aplicativos

  27. Kelsey says:

    In my application, I have a game that has many different themes. All themes share an almost identical codebase (including package and class definitions), but the graphics are completely different. In the Android version, I was able to load and unload the swfs successfully by loading them into a child domain of the Application.currentDomain. But for iOS, since they must be loaded into the ApplicationDomain.currentDomain, the result is that the first swf works fine, but thereafter, many of the graphics from the inital swf are being displayed instead of graphics from the new swf.
    Is there a solution to properly overriding the class definitions created from the inital swf? Or will I have to go into each swf and rename every class definition so they don’t conflict?

  28. Kev says:

    Hi,

    I have multiple secondary swfs that requires loading, however, flashdevelop seems to only package only the first swf, hence the application will not run when other swfs are loaded and used.

    I tested each swf one by one, and they work fine, if they are the only swf in the bin folder, has anyone got any advice regarding this?

    • Kev says:

      Also, I’ve tried the external loading with air 3.7

      The externally stripped swfs seem to generate the error 1042: not an abc file.
      Any clues on this too?

      • Abhinav says:

        Hi Kev

        Could you please confirm the following 2 things :
        1. SWF version of the Root SWF of your application ?
        2. The packaging target in which the IPA has been packaged ?

        • Kev says:

          Hi Abhinav

          Please ignore the second comment I posted, it seems to work fine when transfered to the iphone.

          But the first problem still exists, the swf version is 20, the packaging target is ad-hoc. On a side note, loading swfs seem to have a weaker performance than just including it as an internal swc library.

          The same problem persists, even when compiling them as local swfs. It seems as though only the first swf ( alphabetically) can be used, and no the others. Using any other than the first one will result in the game not loading anything.

          regards,
          Kevin

  29. Kev says:

    Just to add a little on the situation, using the loader to load the other SWFs results in the debugger prompting an internal debugger exception.

  30. Nathan says:

    Hello,

    I can get this to work when testing through the adl in Flash, but it does not work on my iPad..

    I’m using AIR 3.7 and I’m trying to load a local file. The file is a Captivate swf that shows the preloader when loaded, but does not load the rest of the swf.

    Any thoughts?

    Thanks.
    Nathan

  31. Pingback: Flash cs 5.5 embed - Flashforum

  32. biscito says:

    use loadermax and i’ll works fine,

    _assets = new LoaderMax({name:”mainQueue”, onProgress:progressHandler, onComplete:completeHandler, onError:errorHandler});
    _assets.append(new SWFLoader(“LevelA1.swf”, {name:”levelA1″, context:new LoaderContext(false, ApplicationDomain.currentDomain, null)}));
    _assets.append(new SWFLoader(“LevelA2.swf”, {name:”levelA2″, context:new LoaderContext(false, ApplicationDomain.currentDomain, null)}));

  33. cyberprodigy says:

    Best news ever :)

  34. FionaPass says:

    Hello – I am having terrible trouble with the AIR 3.8 upgrade: I am loading external swfs without code into a main timeline with ProLoader. It works fine when I run as a test export but the swfs are not loading when I publish to device. Here is that code. Can anyone please help? I have been struggling with this, literally, for weeks! And, yes, the files are loaded in the AS settings panel.

    //start button

    start_button_TRI_coelophysis.addEventListener(MouseEvent.CLICK,
    fl_ClickToLoadUnloadSWF_01_3,false,0,true);

    import fl.display.ProLoader;
    import flash.events.Event;

    var fl_ProLoader_01:ProLoader;
    var fl_ToLoad_01:Boolean = true;

    function fl_ClickToLoadUnloadSWF_01_3(event:MouseEvent):void
    {
    if(fl_ToLoad_01)
    {
    fl_ProLoader_01 = new ProLoader();
    fl_ProLoader_01.load(new URLRequest(“dinofilms/triassic_coelophysis.swf”));

    fl_ProLoader_01.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete_01)
    addChild(fl_ProLoader_01);
    fl_ProLoader_01.x = 0;
    fl_ProLoader_01.y = 144;
    }
    else
    {
    if(fl_ProLoader_01!=null) {
    removeChild(fl_ProLoader_01);
    fl_ProLoader_01.unloadAndStop();
    fl_ProLoader_01 = null;
    }
    }
    fl_ToLoad_01 = !fl_ToLoad_01;

    }

    function onComplete_01(e:Event):void {
    e.currentTarget.content.addEventListener(Event.ENTER_FRAME,OEF_01);
    }

    function OEF_01(e:Event):void {
    if(e.currentTarget.currentFrame==e.currentTarget.totalFrames) {
    e.currentTarget.stop();
    e.currentTarget.removeEventListener(Event.ENTER_FRAME,OEF_01);

    removeChild(fl_ProLoader_01);
    fl_ProLoader_01.unloadAndStop();
    fl_ProLoader_01 = null;
    }
    }