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);
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:
- The contentLoaderInfo property of the Loader object will become null
- Any assets that are loaded with the secondary SWF will be unloaded.
- 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.
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
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.
- 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.