Tom Krcha's FlashRealtime

Hey amigo!
I am Tom Krcha, Gaming Evangelist at Adobe. These are my notes


HOWTO: Join multiple SWF files into one with AIR for iOS

February 3rd, 2012

A while back, I promised to write some of the backstage tips that made it possible for Machinarium (1 GB sources!, 28 SWFs!) to run on an iPad with AIR, which requires only a single SWF.

One of the issues you run into is how to join/concatenate 28 SWFs into single SWF. I wrote an article about using SWC libraries for that here Compiling big Flash/AIR projects with lot of SWFs for iOS. This sometimes works, but very often the workflow is more complex and you want to keep the same SWF files for Android and iOS and use them at least in a bit similar way. On Android you can however load SWF files at the runtime and this is very effective for the memory usage. On iOS you have to watch this, especially when you have everything in a single SWF. So, ideally you place all assets into separate files and load them and dispose them on-demand. But that’s more of a general problem you should keep in mind - every asset that doesn’t contain AS3 (pictures, videos, music), put aside. But back to the topic.

Now comes the magic by David ‘Oldes’ Oliva (the lead developer of Machinarium) from Amanita Design, who made it all possible and wrote a script which can be used for joining SWFs together.

Note: This solution allows you to use multiple SWF files containing AS3 script and logic in each of them, not only for assets. That’s why it’s so powerful.

*prerequisite: you’ll need to understand how to work with the command-line on Mac or Windows.

Steps:

1) Prepare SWFs like you were using them the standard way, but instead of loading them dynamically via the Loader class, SWFLoader or a similar mechanism, each SWF has to be Class (or contain at least one, can contain more), which you can instantiate. That’s because once you join all SWFs together, you will be instantiating it’s contents, not loading.

2) Download the samples package rswf-join-example.7z (for unzipping use 7-zip compatible tool) / UPDATE: the file has been updated to support bitmap reduction

3) Download the REBOL script view environment http://www.rebol.com/download-view.html

Using the tool:

4) Navigate to the samples folder. There are three scripts that you might want adjust to fit your workflow:

compile-and-run.r
- this is the rebol script that does part of the job and runs Game.bat

Game.bat
- here you want to adjust the path to your Flex/AIR SDK so it points to the adl command

cd ./public/
/path/to/AIR_SDK/bin/adl Game.xml

Game.rswf
- here you specify the SWFs you want to compile together, in the samples, you can see FLAs and it’s content to understand how to prepare your own workflow.

5) Run the compilation (of course change the path to rebol to the directory, where you have downloaded it or stored it)

/path/to/REBOL/rebol compile-and-run.r

*At this point, if you get permission denied on some of the files, make sure all the processing files have the proper rights; you can set the rights using chmod, for instance:

chmod 777 filename.bat

also 777 is pretty open rule, so consider 755 or 775 or similar.

6) Once the compilation is done, the SWF will open and you can successfully use it with adt command from the Flex/AIR SDK to compile the final IPA for iOS.

If you have any questions, please ask in the comments.

Good luck!

Facebook comments:

19 Comments »

  1. Awesome!! This is a killer tip for AIR mobile developers ~!

    Comment by Peter — February 3, 2012 @ 2:58 pm

  2. Tomas, thanks for this. I love your blog, btw!

    This is a workable flow, but as you noted, your SWFs still have to be prepared by having classes defined in them - in other words you can’t access the “MainTimeline” or “document class” of those assets. And if you’d taken care to define classes in your assets (aka export symbols to ActionScript), you might as well have published SWCs with them and compiled them together with mxmlc.

    So unfortunately for me, who’s never taken care to define classes in my asset SWFs, I think I’m still outta luck for porting to iOS.

    Comment by Jeff Ward — February 3, 2012 @ 5:34 pm

  3. Hi Jeff, it’s actually a bit different thing. As stated above regarding SWC: “This sometimes works, but very often the workflow is more complex”. What I have seen in SWC is that some assets have been excluded and not accessible. In SWF, all is there, also it’s better for Android + iOS workflow at the end without having two separate file types.

    Comment by tom — February 3, 2012 @ 10:35 pm

  4. Jeff, you don’t have to use classes in SWFs. It will join everything, the only SWF tags which are skipped are ScriptLimits, FileAttributes, metaData, setBackgroundColor, DefineSceneAndFrameLabelData. In the rest are recounted tag IDs. If you have some real content in the SWFs, the depth is also modified = the later SWF is placed over the previous.

    I should note that in this example, it is not clear, why not to use SWCs, but at least in the time I was working on it was embedding SWC unstable and slow. I’m sure Adobe want to address this joining issue.

    I must also note, that the RSWF script is not just for joining. Joining is just one of possibilities what it can do - RSWF means REBOL/FLASH dialect which I was using years ago to examine and produce SWF files.

    The joining is actually SWF-IMPORTING, which logic is mostly defined in this part of the script:

    https://github.com/Oldes/rs/blob/master/projects-rswf/swf-parser/latest/parsers/swf-importing.r

    (sorry that the scripts are so unclean - I was not polishing them)

    Comment by Oldes — February 3, 2012 @ 10:44 pm

  5. As the RSWF is not documented and the old web is down, I just uploaded the current dialect rules here: http://rebol.desajn.net/rswf/

    Comment by Oldes — February 4, 2012 @ 12:40 am

  6. Does this practically package each SWF as a packaged class such that each SWF can be instantiated as a Class and doesn’t need to be loaded? OR is it something else.

    Comment by Pulkit Gupta — February 4, 2012 @ 8:39 am

  7. Hi Pulkit, exactly like you say. On iOS you will instantiate and addChild to the scene, on Android you will use Loader, but basically you could use same SWFs

    Comment by tom — February 4, 2012 @ 9:11 am

  8. Thankssss Tom, this is a great approach. I wonder why I did not think about this before. You do a great job of educating us.

    Comment by Pulkit Gupta — February 4, 2012 @ 4:36 pm

  9. Yes, I can same file for iOS and Android (in real life I have separate files as there is different resolution and I use automatically rescaled content with hand made optimization)… but the code is almost same. On Android I just access the level classes using something like:

    loader.contentLoaderInfo.applicationDomain.getDefinition(levelClassName) as Class;

    Comment by Oldes — February 6, 2012 @ 11:52 am

  10. Been trying to use this and it took me a while to understand that compile-and-run.r has to be modified!

    I had to replace call/console "adl Game.xml" with call/console "Game.bat".

    I hope this helps!
    Next step: try to build something out of this.

    Comment by Quentin — February 7, 2012 @ 12:20 pm

  11. Also, can you explain what FileAttributes 2#{0 11 01000000000000000000000000000} does, in Game.rswf? That’d help!

    Comment by Quentin — February 7, 2012 @ 12:30 pm

  12. Wow! That’s great news.
    I don’t understand the process yet, but it’s great to know it’s possible.
    Let’s hope Adobe will build something like this into Flash CS6!

    Comment by BD — February 7, 2012 @ 4:27 pm

  13. Quite an elegant solution, thanks for sharing this :)

    Comment by Swn — February 8, 2012 @ 2:38 pm

  14. Hi, thanks for the tutorial. I’ve followed all the process but there’s a question i would like to ask.
    Consider if i had many pages game like Machinarium , I would like to put a loading in each page my game change. So how could this made done with a single SWF ? Thanks

    Comment by Rio — February 10, 2012 @ 8:38 am

  15. @Rio: I’ve updated the example here: http://amanita-design.net/download/rswf-join-example.7z

    You can find there a new ExampleMain_noJoin.fla and ExampleMain_noJoin.as - it’s just a very simple example how you can load the levels as separate files without need to join them using classic Loader (everywhere except iOS).

    Comment by Oldes — February 10, 2012 @ 10:55 am

  16. @Quentin: it’s FileAtributes tag in binary format.. check details here: http://www.adobe.com/content/dam/Adobe/en/devnet/swf/pdf/swf_file_format_spec_v10.pdf

    Comment by Oldes — February 10, 2012 @ 11:00 am

  17. @Oldes: pardon me as I couldn’t understood it properly - “you don’t have to use classes in SWFs. It will join everything” - if I understood this part correctly then we wouldn’t require to declare an AS class externally for any SWF to join - but in that case how can we attach that particular SWF inside the application as demonstrated in the example ExampleMain.as -

    currentLevel = new ExampleLevel2() as Sprite;

    Since my new SWF maybe named ExampleLevel3 doesn’t have any subclass defined somewhere (?)

    Comment by Santanu — March 7, 2012 @ 1:50 pm

  18. We’re using this process and everything seems to be working except that when I install the app on to my device and launch it there is only a black screen with no message. I’m not certain what I’m doing wrong at this point. Any thoughts?

    Comment by Alex Bethke — May 4, 2012 @ 9:27 pm

  19. Hello,

    I’ve been trying to get this working despite having very little command line knowledge and could do with some help! I keep getting the error ‘not recognized as an internal or external command, operable program or batch file’ which seems to suggest that the Game.bat file isn’t being found?

    Any advice would be helpful, I’m getting nowhere myself.

    Comment by Alice — June 25, 2012 @ 4:55 pm

RSS feed for comments on this post. / TrackBack URL

Leave a comment

Comment moderation is enabled. Your comment may take some time to appear.