Showing posts with label ExternalInterface. Show all posts
Showing posts with label ExternalInterface. Show all posts

Moving from Authorware to Flex

english mobile

I started out as an Authorware developer, and one reason I am now doing Flex is that Adobe announced the End of Development of Authorware just over a year ago. I saw that Flex offered a lot of the advantages of Authorware--it does a great job of integrating various media into a cohesive whole and you can make an application that runs from the web or the desktop from approximately the same code.

Adobe's decision left many people scrambling to figure out where they would go, so Randy Nielsen from the Flex documentation team worked with a few Authorware developers to get a stub page up when Flex 3 was released so that Authorware developers could document what their experiences have been to help ease the process of making the migration for those who felt that Flex was the best Authorware replacement for them.

At long last, I managed to make some time to add my 2¢ worth to the document. So I'm happy to announce that the Moving to Flex from Authorware page at the Flex documentation wiki has been updated. There is one section that I wrote that for some reason isn't included, and I feel it may be useful to some people, so I'm posting it here:

Using Flex files inside Authorware
In large existing projects, it might not be feasible to migrate the entire project to Flex over night. One strategy is to create new functionality in Flex and embed that in Authorware. When Authorware finally is abandoned, the Flex functionality will still be useful.

Flex Side
Flex and Flash have an object, ExternalInterface, that allows them to communicate with whatever application contains the swf file. Normally, this is used in a swf embedded in the browser to communicate with javascript that is written in the HTML page.
At the moment that the swf loads, the child components of the swf don't yet exist, so any attempt to set any properties on them will cause an error, which will probably stop your Flex application from proceeding any further. So you should wait until everything is created before initiating communication with the container. This means that you should run a function on creationComplete that will use ExternalInterface to call out to the container and tell it that it is ready to receive data. This function should also set up the callback functions, which are the functions inside your Flex application that are accessible to the container.
The container should then respond by calling a function and providing data your Flex application needs as an argument. This can be a user name, lesson status, or XML that represents a menu. The function should perform whatever parsing is needed on the data and set object properties based on the data.
When the user interacts with the swf, it should again use ExternalInterface to tell the container what happened.
Once you have created your Flex file, you should make sure to export a release build by going to Project>Export Release Build. This file will be smaller and run more efficiently than the debug build that is built by default.

Authorware Side
The Authorware file will have a Shockwave Flash Object ActiveX control icon in it. The development machine should have Flash Player version (Randy, what's the minimum version of the Flash Player for Flex 3?) on it, and you'll need to make sure that the users have at least that version installed.
Next, you'll need a calculation icon that sets up the path to your swf file so that Authorware can find it. This will start the loading process, which will culminate in the creationComplete event.
Once the creationComplete event fires, the swf will generate an event that can be seen in Authorware by using ExternalInterface. To catch this event, you'll need to use an Event Response on an Interaction icon. The response should be set up to respond to the FlashCall event. This seems to work best as a perpetual response on an Interaction that is below the ActiveX Sprite on the flow line, but above the calculation that sets the path to the swf.
The information contained in the #request property of the EventLastMatched variable will be an XML formatted string, so you'll need to use an XML parser object to access its contents. The same event response will trigger every time the Flex Application calls ExternalInterface.call, so you'll need to look at the name of the root element to see what "function" the Flex file thinks it is calling and branch based on that.
In the branch that you set up for the initial call where the swf tells you it is started, you should respond by issuing a CallSprite command to the Flash ActiveX Sprite icon that calls a function in the swf with the data you want to see in Flex. Other branches should contain logic to respond to different calls the swf sends with ExternalInterface.

Download the example files.

Problems with HTML within XML

english mobile

Around a month ago, I promised more fun and exciting posts about passing XML through ExternalInterface from Authorware to be used within Flex. The specific task I was trying to accomplish is taking a series of xml nodes and displaying their contents on screen using a repeater control. The contents could be images, text, or swfs.

The problem I had was with the text. It seems that Flex is very persnickety about its XML formatting, so each XML node must be indented and on a new line. This is fine for ordinary XML, since who cares how it looks to Flex, but when you have line breaks and tabs added around your <b > tags, that is a problem!

The irritating thing is that the problem occurs not once, but twice! The first time is when the XML gets passed through ExternalInterface. I did eventually find a way to defeat that one, but since it also happens again when you pass the string to the XML() object to make the data source for the repeater, that didn't help much. Flex essentially ignores CDATA tags put into the XML nodes and formats the data anyway, so that didn't help either.

What I eventually wound up doing is replacing the "<" characters in embedded html with "^", then replacing that in the final step before rendering. I'm thinking now that I probably also could have gone with a separate text file for each bit of HTML text and told the Flex file to read that in and display it. However, at the time I didn't know how to get a non-air Flex file to read directly from the hard drive, so it didn't occur to me.

Updated September 18, 2008:
I think this was caused by the prettyPrinting and prettyIndent settings on the global XML object itself. I think that if I'd set prettyPrinting to false, I could have avoided the hassle. One day I may even revisit that component...I'll let you know how it turns out.

More on ExternalInterface

english mobile

One of my first posts was about using ExternalInterface to call Flex from Authorware, and about how there is virtually no documentation on how to use this API to run functions inside a Flex swf from an ActiveX control embedded in an executable (in this case, Authorware). I've found some more anomalies which are worth jotting down for my own future reference and the reference of anyone who's bored enough to read my blog.

It seems that the <arguments> parameter does not recognize the full spectrum of data types supported by Flex. So far, I have found that if your Flex function expects an int or a Boolean argument, these values must be wrapped in a <number> tag. I guess Flex knows ExternalInterface can't handle these data types, and converts them from generic numbers into the appropriate data type by pfm in the background.

Ain't life grand?

Calling Flex from Authorware

english mobile

So I finally had my datagrid calling my ASP page, which squirted out XML. I embedded my Flex swf and could not for the life of me figure out how to call the functionality from Authorware. I did a lot of Googling and banging my head up against a wall, and here is what I came up with:

CallSprite(@"Flash", #CallString, "CallFunction('<invoke
name=\"myFlexFunction\" returntype=\"void\"><arguments><string>hello
world</string></arguments></invoke>')")


If you're not familiar with Authorware, it has two methods for embedding swf files. One is a sort of proprietary method called the Flash Asset Xtra. It actually contains the Flash player so the user does not need to have the player installed. Problem is, it only goes up to Flash 6. So this Flash Sprite is the other type, the Flash 9 ActiveX control embedded in Authorware. #CallString is a method of the CallSprite function that allows you to get access to all methods of a given sprite, even ones that aren't exposed in the way Authorware recognizes. All of this is a long hand way of saying if you're not using Authorware, you'd probably use the CallFunction function some other way.

However, the important part is the XML string, which the Flex documentation doesn't, well, document. I haven't found anything but examples, but I'll give it a stab from my surmises which have borne out through trial and error so far.

<invoke>-root level tag. It has a name property that tells Flex what to invoke (i.e. the name of your function). Those backslashes you see there in my code are to tell Authorware those are literal quotes that should be passed on through to the function. Also has a returntype property, which, presumably, is the return type you expect. Probably this can be any valid return type a function could have from Flex.
<arguments>-nested within invoke, this is a container for all the arguments your function is expecting. Each argument should, again presumably, be wrapped in a tag that tells Flex what type of argument it is. IMO a cleaner implementation would be <argument type="string>foo</argument> but then I'm just a random spong so I don't control these things.

If there's anything else that you could put in here I haven't found it.

Note that I am really curious as to whether a function that returned a value would return it back to Authorware and what form that would take, but not quite curious enough to try it until I need to.