Bundling With AIR Captive Runtime


(Zachary Lewis) #1

Overview

Sometimes, the hardest part of making a game is distributing the game after it’s been made. If your game is designed to be played as a standalone experience, playing a game in-browser can be a large disappointment. This tutorial is designed to show you how to turn your finished game into a standalone, executable file (either a .exe or .app, depending on your target operating system) that doesn’t require installing Adobe AIR — just double-click and play.

This guide is written mainly from a Windows perspective, but the adt tools are the same on OS X.

Ingredients

  • A game that’s ready to distribute
  • Adobe AIR (anything after AIR 3.0, but I’ll be using AIR 14.0)
  • A self-signed certificate (FlashDevelop can generate this for you)
  • Optional Some basic knowledge of scripting on your OS

Instructions

Setting Everything Up

Before you start powering out some command-line hacker crap, you’ll need to be sure you have your AIR binaries added to your system’s path.

  • [Editing System Path (Windows)] path-win
  • [Editing System Path (OS X)] path-osx

To make sure the AIR tools are properly added to your path, open a command line window and attempt to call the AIR Developer Tool, adt. You should get something like this:

$ adt
Adobe (R) AIR (R) Developer Tool (ADT)
Version 14.0.0.178
Copyright (c) 2008-2014 Adobe Systems Incorporated. All rights reserved.

No arguments were found
usage:
  adt -checkstore SIGNING_OPTIONS
  adt -certificate -cn <name> ( -ou <org-unit> )? ( -o <org-name> )? ( -c <country> )? ( -validityPeriod <years> )? ( 1024-RSA | 2048-RSA ) <pfx-file> <password>
  adt -help
  adt -migrate SIGNING_OPTIONS ( <air-file-in> | <airn-file-in> ) <output-file>
  adt -package SIGNING_OPTIONS ( -target air )? <output-package> ( <app-desc> FILE_OPTIONS | <input-package> )
  adt -package SIGNING_OPTIONS -target airn <output-package> ( <app-desc> FILE-AND-PATH-OPTIONS | <input-package> )
  adt -package -target ( apk | apk-debug | apk-emulator | apk-captive-runtime ) ( CONNECT_OPTIONS? | LISTEN_OPTIONS? ) ( -airDownloadURL <url> )? ( ARCH_OPTIONS )? SIGNING_OPTIONS <output-package> ( <app-desc> PLATFORM-SDK-OPTION? FILE-AND-PATH-OPTIONS | <input-package> PLATFORM-SDK-OPTION? )
  adt -package -target ( ipa-test | ipa-debug | ipa-app-store | ipa-ad-hoc | ipa-test-interpreter | ipa-debug-interpreter | ipa-test-interpreter-simulator | ipa-debug-interpreter-simulator ) ( CONNECT_OPTIONS? | LISTEN_OPTIONS? ) ( -sampler )? ANE_LINK_OPTIONS? AOT_MODE_OPTIONS? SIGNING_OPTIONS <output-package> ( <app-desc> PLATFORM-SDK-OPTION? FILE-AND-PATH-OPTIONS | <input-package> PLATFORM-SDK-OPTION? )
  adt -package SIGNING_OPTIONS? -target native SIGNING_OPTIONS? <output-package> ( <app-desc> FILE-AND-PATH-OPTIONS | <input-package> )
  adt -package SIGNING_OPTIONS? -migrate SIGNING_OPTIONS -target native SIGNING_OPTIONS? <output-package> <app-desc> FILE_OPTIONS PATH-OPTION
  adt -package SIGNING_OPTIONS? -target bundle SIGNING_OPTIONS? <output-package> ( <app-desc> FILE-AND-PATH-OPTIONS | <input-package> )
  adt -package SIGNING_OPTIONS? -target ane <output-package> <ext-desc> ANE_OPTIONS
  adt -prepare <airi-file> <app-desc> FILE_AND_PATH_OPTIONS
  adt -sign SIGNING_OPTIONS ( -target ( air | airn | ane ) )? ( <airi-file> | <unsigned-ane-file> ) <output-file>
  adt -devices          PLATFORM-OPTION PLATFORM-SDK-OPTION?
  adt -installRuntime   PLATFORM-OPTION PLATFORM-SDK-OPTION? DEVICE-OPTION? ( -package <apk-file> )?
  adt -installApp       PLATFORM-OPTION PLATFORM-SDK-OPTION? DEVICE-OPTION? -package <apk-file | ipa-file>
  adt -uninstallRuntime PLATFORM-OPTION PLATFORM-SDK-OPTION? DEVICE-OPTION?
  adt -uninstallApp     PLATFORM-OPTION PLATFORM-SDK-OPTION? DEVICE-OPTION? -appid <app-id>
  adt -launchApp        { PLATFORM-OPTION PLATFORM-SDK-OPTION? DEVICE-OPTION? ( -debuggerPort port )? -appid <app-id> }
  adt -runtimeVersion   PLATFORM-OPTION PLATFORM-SDK-OPTION? DEVICE-OPTION?
  adt -appVersion       PLATFORM-OPTION PLATFORM-SDK-OPTION? DEVICE-OPTION? -appid <app-id>
  adt -version

SIGNING_OPTIONS      : -storetype <type> ( -keystore <store> )? ( -storepass <pass> )? ( -alias <aliasName> )? ( -keypass <pass> )? ( -providerName <name> )? ( -tsa <url> )? ( -provisioning-profile <profile> )?
FILE_OPTIONS         : <fileOrDir>* ( ( -C <dir> <fileOrDir>+ ) | ( -e <file> <path> ) )*
ARCH_OPTIONS              : -arch (armv7 | x86)
CONNECT_OPTIONS      : -connect <host>
LISTEN_OPTIONS       : -listen <port>
ANE_LINK_OPTIONS     : -hideAneLibSymbols ( yes | no )
ANE_OPTIONS          : -swc <swc> ( -platform <name> (-platformoptions <file>)? <fileOrDir>* ( -C <dir> <fileOrDir>+ )* )*
FILE-AND-PATH-OPTIONS: ( PATH-OPTION | FILE-OPTIONS ) FILE-AND-PATH-OPTIONS?
PATH-OPTION          : -extdir <dir>
PLATFORM-OPTION      : -platform (android | ios)
PLATFORM-SDK-OPTION  : -platformsdk <platform-sdk-home-dir>
DEVICE-OPTION        : -device ( deviceID | ios-simulator )
AOT_MODE_OPTIONS     : -useLegacyAOT ( yes | no )

Those are the tools you’ll be working with, so get ready. It’s time to cook.

Basic Bundling

To create a bundle with the AIR Captive Runtime (remember, that’s the bit that allows it to run without requiring AIR to be installed), you’ll be using the bundle target. That means, you’ll want to use the item from the list that adt graciously provided you with the -target bundle argument. In case you can’t find it, here it is:

adt -package SIGNING_OPTIONS? -target bundle SIGNING_OPTIONS? <output-package> ( <app-desc> FILE-AND-PATH-OPTIONS | <input-package> )

Got that? Let’s break it down.

  • SIGNING_OPTIONS This is where you slap that self-signed certificate in.
  • output-package This is the name of the file to output, like dist\windows.
  • app-desc The AIR descriptor XML (should be generated by FlashDevelop)
  • FILE-AND-PATH-OPTIONS This one can be tricky, but it’s a list of all the assets required by your application XML, including mygame.swf.

Bundling In Action

Now that you know the tools, let’s look at a sample game, Super Sample. You would probably have a bundle call that looks very similar to this:

$ adt -package -tsa none -storetype pkcs12 -keystore "cert\supersample.p12" -storepass sspassword123 -target bundle dist\windows application.xml -e "bin/supersample.swf" supersample.swf -C "icons/desktop/icons" . -extdir lib

Let’s dissect this call.


$ adt -package

Call the AIR Developer Tool, instructing it to package an application for distribution.


-tsa none -storetype pkcs12 -keystore "cert\supersample.p12" -storepass sspassword123

Here are the signing options.

-tsa none -storetype pkcs12 -keystore "cert\supersample.p12" -storepass sspassword123

This section instructs the tool to not check the certificate timestamp. This can be useful if your computer isn’t connected to the internet or if your certificate file is out of date (shame on you).

-tsa none -storetype pkcs12 -keystore "cert\supersample.p12" -storepass sspassword123

This section tells the tool what certificate to use for signing. The conversation might go something like this:

The certificate is a [PKCS 12] pkcs-12 certificate. The certificate is found at cert\supersample.p12. The password for the certificate is “sspassword123.”


-target bundle dist\windows application.xml

This tells the tool to create an executable bundle with the AIR Captive Runtime in the dist\windows directory based on the information in application.xml. The XML file will describe the name of the application as well as any other files needed by the application. Since the application’s name is stored in application.xml, it will use this to name the resulting executable (in this case, it’ll probably be supersample.exe).


-e "bin/supersample.swf" supersample.swf -C "icons/desktop/icons" . -extdir lib

Here are the file and path options. As I mentioned before, these can be tricky, but I’m sure you’ll get the hang of them. The main thing you need to know are the two flags, -e and -C. -e describes an explicit file, while -C describes a directory change. Here we go.

-e "bin/supersample.swf" supersample.swf -C "icons/desktop/icons" . -extdir lib

The bundle should include the file located at bin/supersample.swf, and this file should be in the root directory and named supersample.swf.

If for some reason you needed to change the location or name of the file, you can do that as well. Supposing you goofed real bad and built your file to output-files/goofed.swf and set your application.xml to look for swfs/main.swf, you could change this to:

-e output-files/goofed.swf swfs/main.swf
-e "bin/supersample.swf" supersample.swf -C "icons/desktop/icons" . -extdir lib

This describes an entire folder (in this case, this folder contains the icons to use for the executable file).

Switch to the directory icons/desktop/icons. Now, put all the icons there into the root of the bundle.

Again, you can change the output, ., to point to the proper location in your bundle.

-e "bin/supersample.swf" supersample.swf -C "icons/desktop/icons" . -extdir lib

This specifies any external libraries you may need in your application. This is often used when working with Native Extensions, (such as FRESteamWorks fresteamworks, which provides your AIR application access to the steamworks libraries).

Look for Native Extensions in the lib directory and bundle those on up as well.

Advanced Bundling Maneuvers

Once you’ve gotten the hang of bundling your AIR applications, make life easier on yourself with simple tools.

Power Bundling

It can be a pain to keep a command window open, and typing all your stuff in sucks. Make life easier by writing a little batch script like this:

bundle.bat

@echo off

set SIGNING_OPTIONS=-storetype pkcs12 -keystore "cert\supersample.p12" -storepass sspassword123
set APP_XML=application.xml
set DIST_PATH=dist
set DIST_NAME=windows
set FILE_OR_DIR=-e "bin/supersample.swf" supersample.swf -C "icons/desktop/icons" .

set OUTPUT=%DIST_PATH%\%DIST_NAME%

if not exist "%DIST_PATH%" md "%DIST_PATH%"

set AIR_PACKAGE=adt -package -tsa none %SIGNING_OPTIONS% -target bundle %OUTPUT% %APP_XML% %FILE_OR_DIR% -extdir lib

call where adt
call adt -version
echo $ %AIR_PACKAGE%
call %AIR_PACKAGE%

This little bad-boy will not only bundle Super Sample by just double-clicking on it, but will also check the location and version of adt, create your output folder (if it doesn’t exist) and show you the exact command it is calling. Additionally, editing it is easy since all the variables are broken out.

Automatic Build & Bundle

Once you’ve created a bundling script like bundle.bat, you can instruct FlashDevelop to bundle that puppy upon successful build of your game — now that’s a next-level bundling maneuver!

In FlashDevelop, open your project’s properties and cruise over to the Build tab. Add your bundle batch file to the “Post-Build Command Line” area, making sure that “Always execute” is off (this prevents bundle.bat from being run if the build fails).

Now, whenever you build, FlashDevelop will also bundle for you!

If you want to get really fancy and always test your bundled application, hit up that Output tab, select “Run Custom Command…” under “Test Project” and click “Edit…” From there, enter the location of your bundle and save that beast. Now, when you run your application from FlashDevelop, it’ll run your standalone executable. Wow!

The End


Bit Dungeon II Steam Greenlight game made in flashpunk
(Darrin) #2

Wow, this is awesome. Thanks so much.

Windows 7 Setup

  1. The adt.bat is located under your flex SDK. The default install is: C:\flex_sdk_4.6\bin

  2. How to check the version of Air installed. Right-click on the Adobe AIR.dll file located inside the following directory. Look at the details tab. C:\Program Files (x86)\Common Files\Adobe AIR\Versions\1.0\Adobe AIR.dll

  3. Latest version of Air is found here and will update the Adobe AIR.dll.
    http://get.adobe.com/air/

  4. Add the “C:\flex_sdk_4.6\bin” to environment path. In start | search type in in “view advanced system settings.” Click on Environmental Variables. Ignore the user variables, go to path in System Variables. Edit and add at “C:\flex_sdk_4.6\bin” the end.

  5. Add java.exe to the environment path. Java run time is typically installed here: C:\Program Files (x86)\Java\jre7\bin. Click on Environmental Variables. Ignore the user variables, go to path in System Variables. Edit and add at " C:\Program Files (x86)\Java\jre7\bin" the end.

  6. Run cmd.exe and type in “adt.bat” to test output.


(Mike Evmm) #3

This is amazing! Why isn’t this integrated into FD? :frowning:


(Zachary Lewis) #4

It’s always good to know how your tools work. There will come a time when an automagic build process fails and you’ll have to fix it.


(Mike Evmm) #5

True, but if FD comes with an Air build-specific menu, and has a GUI for deployment target on HaXe, there really is no reason to not have this integrated.


(Darrin) #6

See above for notes on windows setup.


(Mike Evmm) #7

(I must’ve done something wrong, because I screwed up the custom made bat and the default FD packageApp.bat with 303 icon errors.)
(halp)
unscrewed it, icons folder must be inside bin directory.


(Ultima2876) #8

Yup, that’s exactly what you need to do. Find your java.exe, and add the location of that file to your environment variable PATH. Java is usually in C:\Program Files or C:\Program Files (x86).


(Mike Evmm) #9

I do have a question though, doesn’t this expose the .swf file a lot?


(Zachary Lewis) #10

If someone extracts the .exe or .app, the user can see your .swf. By the same token, if you download an Unreal game, you have access to the binaries they use, as well as the content packages.

Basically, by downloading the game, the user has access to the files that compose the game. :expressionless:


(B6ka) #11

Thank you, this is very useful :slight_smile:


(John Andersson) #12

Thank you. Amazing/10, now we need the next level exe wizardry where our swf will be hidden from evil people inside the exe.

Or is that way too advanced?


(Zachary Lewis) #13

I’m not really sure what you mean. The bundle is designed to run the .swf. Without the .swf, you don’t have an application.

Are you talking about code obfuscation?


(John Andersson) #14

Something like that, yeah. :stuck_out_tongue:


(Zachary Lewis) #15

(Lmahdi Adam) #16

thanks for sharing

I have a problem in adobe flash builder 4.6

i don’t have this line

Signed Application With Captive Runtime

thanks again