External swf plays very slow on iOS - ios

I'm writing an application using as3 and adobe air that loads external SWF files and plays them internally in the application. The container works just fine with android and the animation of the external swf file is very cool.
However, on the iOS (iPad 2), it runs very slow as if its playing only 1 frame per second.
Is there anyway at all to make it play faster.
My application configuration is as follow:
<initialWindow>
<autoOrients>false</autoOrients>
<aspectRatio>landscape</aspectRatio>
<renderMode>gpu</renderMode>
<fullScreen>false</fullScreen>
<visible>true</visible>
<softKeyboardBehavior>none</softKeyboardBehavior>
</initialWindow>
This is the part of code where I load the external swf:
public function set url(value:String):void
{
_url = value;
object.source = File.applicationDirectory.resolvePath(value).url;
object.addEventListener(Event.COMPLETE , onLoaded);
}
protected function onLoaded(event:Event):void
{
object.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
protected function onEnterFrame(event:Event):void
{
if((object.content as Object).currentFrameLabel == "stop")
(object.content as Object).stop();
}
I also tried to comment the Enter frame event listener but nothing changed.
Thanks in advance.
Edit:
I figured out something that is very strange actually. When I run the application from the application with the Fast configuration, it runs fast. But when I publish it or use the Standard option while running it runs really slow.
Tested with AIR 3.2

try setting your render mode to direct:
<renderMode>direct</renderMode>
Remember, when you are rendering exclusively to the GPU, it will slow things down if you are rendering animations. Although rendering to the GPU is fast, allocating Video Memory to the GPU is slow. If you render exclusivity to the GPU, on every frame, the video memory will need to be updated.
Another thing is that all vectors will be rasterized so some things will render pixelated.

A couple of things:
You aren't allowed to load SWFs that have any code in them, in AIR for iOS. This is forbidden by Apple.
You should only use swf at most as a library of graphics / resources when compiling for iOS. If a movieclip inside has stop(); on one of the frames, then this counts as an 'addFrameScript()' under the hood, which means that SWF contains ActionScript.
I suggest if you need functionality as such, create a list of predefined behaviours to be compiled into your main app, then run these behaviours based on the type or name of asset you are instantiating from your SWF library, attaching them at runtime.
Besides, if you are doing this to allow updates -- or the ability to modify the app, post-release, then you may as well compile it into the release build, and just republish next time you want an update to the app. This will help your ranking in the app store to some extent, and remove a lot of versioning issues down the line.

Related

actionscript3 how to manage memory in ios

So we have developed an app using AIR that runs smoothly on android but crashing on iOS. The app just has a preloader and a folder containing a bunch of precompiled SWF files. The user loads one of the SWF called labs files and runs it. It looks something like this:
Now, everything worked fine and all, but once a person loads a lab, the new lab has multiple frames and in the beginning the app runs smoothly but as the user keeps loading frames the app crashes without any errors. I used the debugger in Adobe Flash Professional CC 2016 and there was no error, checked logs etc. still no luck. In the end I just used Instruments and looked up the memory usage. Apparently as frames loaded the application used up all the memory and in the end crashed. The Activity Monitor looked really nasty :
now my question is, is there a specific method to manage memory in actionscript3 from adobe's side?

How to duplicate a MovieClip in AS3 that is contained in an external SWF, loaded from an iOS air application?

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?
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.

Audio never loads on iPad but it works perfect on emulator - PhoneGap + Howler.js

I am using Howler.js on my PhoneGap application. Because my audio files are large (more than 10Mb) im an setting the buffer attribute to true (forcing HTML5 Audio).
var theSound = new Howl({
urls: ['assets/Sound.m4a'],
buffer: true,
sprite: {
scene0 : [ 1966000, 27000] }
When I test my application on the emulator and my iPad Mobile Safari everything works well. But when I run the application on the iPad as an app, the audio never starts. Using the web inspector I have noted that the audio file tries to load again and again like an not ending loop. You can see an attached screenshot of the resources tab on the web inspector both both the emulator and the iPad, running the same PhoneGap app.
Any idea on what could be the problem?
I've been looking into this for a while.
From what I've gathered, Howler defaults to Web Audio API, and this SO answer says you need a "user input event" to make it work on iOS, because by default it mutes everything. I even tried Howler's own interactive demo on my iPad 2 with iOS 5 (I still haven't updated) here and NONE OF THE SOUNDS WORK. My first link has a link to Apple's documentation, and I haven't tried it yet, but it looks like the convenience of Howler has to be replaced with a lower level implementation that takes about 5-10 lines with XMLHTTPRequest (see the Apple link), or another more versatile library. I'm still learning about what exactly I need, but I have a very similar problem I've been working on resolving today.
But then Howler falls back to HTML5 Audio. OK so I'm just googling that now, and this link comes up, and it's just reminding me of the pletora of compatibility considerations between OGG ACC MP3 etc on various browsers vs. browser layout engines vs. operating systems. So I'm left believing your file format M4A, related to MP3 as far as I can tell, isn't working in the target brower on the target iPad OS. I'm not familiar enough yet to give exact specifics but certainly since Howler doesn't work on my iPad that proves there's at least a problem with that.
The whole point I chose Howler to use was to abstract all the above away! I'm going to go look for another more comprehensive library now =D
the problem might be file size. IPad has a limited cache memory size and if you overflow it assets will not work. The only solution to this problem is smaller file size. Another possibility is html audio will not load or play except in a user event (touch). Web Audio will load but starts muted and only unmutes with a play call inside of a user event.
SoundJS is a library I help develop that handles as much of this stuff as possible. In particular I think you would find the Mobile Safe Approach useful. It is well tested on iOS and Android devices. Unfortunately we do not support sound sprites yet.
Hope that helps.

iOS app using Air 3.9 - how can we reload a swf that was previously loaded?

We are developing an iOS app using the air 3.9 sdk. Our application is such that we have 2 SWFs packaged inside the ipa file i.e.the main.swf and an experience.swf.
The main.swf is loaded initially using application.xml. A button-click within the main.swf loads the experience.swf (which is located within the bin folder in the ipa, NOT remotely downloaded). This experience.swf contains assets and code.
When we create an ad-hoc build, experience.swf loads perfectly the first time, but if the user returns to the main.swf and then tries loading the experience.swf again, it doesn't load. Just the default stage color is visible. (This problem only occurs on the ad-hoc build. The debug build has no such issues)
To load this experience.swf we are using the flash.display.loader with loaderContext set as the ApplicationDomain.currentDomain.
mcExperience = new MovieClip();
var url:URLRequest = new URLRequest("ChristmasExperience.swf");
var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
loader.load(url, loaderContext);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, CompleteHandler);
addChild(mcExperience);
private function CompleteHandler(e:Event):void
{
trace("I HAVE LOADED .... SWF loaded... , waiting for the constructor call back..." + e.target.loader.content);
//mcExperience.addChild(loader);
mcExperience.addChild(MovieClip(e.target.loader.content));
//TODO : Set the Session ID Here
m_experienceBase.SetSessionID(int(m_ExperienceSessionID));
m_experienceBase.SetLocalPlayer(m_localPlayer);
//(loader.content as MovieClip).soundTransform = new SoundTransform(0);
//addChild(loader);
//setChildIndex(m_tfConsoleMsgDisplay, numChildren - 1);
}
When the experience is unloaded, we remove the holder MovieClip of the experience.swf and unload the flash.display.loader. This still does not re-load the previously loaded experience.swf.
if (mcExperience)
{
mcExperience.removeChildren();
removeChild(mcExperience);
mcExperience = null;
}
We are using swf-version=22 for both main and experience swf.
This is quite a big problem for us and we've gone through a bunch of posts, to help understand this issue better (a few examples below):
Adobe AIR, IOS, and Multiple SWFs - Returning to a previously loaded SWF
Load and reload external SWF in AIR for iOS
http://blogs.adobe.com/airodynamics/2012/11/09/packaging-and-loading-multiple-swfs-in-air-apps-on-ios/
Is there any way to reload a secondary swf within an ios application?
Don't know if you checked here:
http://blogs.adobe.com/airodynamics/2012/11/09/packaging-and-loading-multiple-swfs-in-air-apps-on-ios/
Basically you cannot reload an swf on IOS and this is from Adobe's mouth.
To overcome this, Adobe came with a NOTE:
"Note: Reloading of pure asset SWFs will work with AIR 3.7 builds which can be downloaded from here"
Pretty lame if you ask me
So what you must do?
Well put the hole code as before in older air versions, in the first swf and use the second swf purely as graphic/animation resource.
While this is a big drawback, blame Adobe :D
Eventhough it says reloading of pure asset SWFs (SWF's w/o ABC) will work with AIR 3.7, I found problems with 4.0. I had SWF's with no code that did not work, and I needed a solution. I answered how I did it here: Load and reload external SWF in AIR for iOS and more fully here: http://www.eqsim.com/blog/?p=400

Display offline html5 website

For my business I need to be able to show a potential client a website I generate with a program called Pano2VR, which is a virtual tour program. This program takes some panoramic photos linked with each other and can generate a virtual tour out of them (as example: www.casas-fotoart.de/virtualtours ). The output this App gives can be either HTML5, Flash or both (flash if available and html5 for mobile devices, for example).
I need to be able to show that on my iPad while offline. i haven't found any solution for that so I tried to build a easy App for that, which I thought it wouldn't be complicated.
I generated a html5-only virtual tour and I droped the output into the "Suporting Files" group on the Xcode project. I added a UIWebView and on viewDidLoad I set it so it loads the html file.
The files I'm droping are like these (these inside the ipad folder):
The html file loads into the webView, but it just displays "This content requires HTML5/CSS3, WebGL, or Adobe Flash Player Version 9 or higher.", even though when loading these files from the net, it loads perfectly. I know this message comes from the html file.
Any idea on how to make it work will be much appreciated. Thanks in advance.
Your problem is this probably - XCode is mangling the JS files, I assume because it's trying to compile them

Resources