lukebayes / clix_flash_player

Command Line Interface to the Flash Player on OS X

This URL has Read+Write access

README.textile

CLIX FlashPlayer

This is a Command Line interface to the Flash Player for OS X.

This project was created because unlike the modern distributions of the desktop debug Flash Player on Windows and Linux, the OS X distribution does not behave properly when executed by another process.

The Problem(s)

We need to be able to execute and focus a specific instance of the Flash Player along with a specific SWF file. The Flash Player execution thread should block until the user selects File >> Quit (or hits CMD+Q), or until the parent application is interrupted (SIGINT) using CTRL+C.

The Flash Player should be focused and still terminate whether or not a runtime exception occurs in the first frame (or any frame) of the loaded SWF file.

Our solution should work each revision of the Flash Player, from 9.0.115 and greater.

Attempts

Open command

The first approach was to simply use the OS X open command. The problem with open, is that it expects a single application or file argument, not an application and file.

When open is sent a second argument, it appears to be the same as if open was called twice – this usually causes two instances of the Flash Player to be launched.

We can’t call open with only the SWF file because then it launches an arbitrary Flash Player and not necessarily the specific version that we need.

Finally, open has the additional disadvantage in that when we send SIGINT to the parent process, the child Players are orphaned.

Exec Flash Player.app with the SWF file as an argument

Of course, this doesn’t work because Flash Player.app is a directory. Thanks Steve!

Exec Flash Player.app/Contents/MacOS/Flash Player binary with the SWF file as an argument

This approach is the most promising yet in that it blocks the parent thread and returns when the Player is Quit and it kills the Player process when the parent is interrupted.

Unfortunately, this doesn’t work for us because the Flash Player is never focused, and actually launches behind all other applications.

AppleScript Wrapper

We can try writing a terminal application using AppleScript that will launch the Flash Player, activate it, and then open the requisite SWF file, which will presumably avoid breakage on runtime exceptions.

This worked great, except using the osascript application to call the AppleScript, apparently breaks the SIGINT relationship from parent to child. So when the parent is aborted, the child is orphaned.

AppleScript Application

Will the AppleScript behave differently as a full OS X .app?

This is awesome because the .app file actually throws a modal “Are you sure?” prompt – behind all other applications. It also doesn’t seem to accept command line parameters properly.

Exec Flash Player.app/Contents/MacOS/Flash Player binary with the SWF file as an argument, and use AppleScript to focus the damn thing

At first blush, this appears to work great, then we encounter the uncaught (actually uncatchable) runtime exception…

If the SWF file we send the player has an uncaught runtime exception, the dialog appears behind all other applications, our AppleScript process becomes locked, and no longer responds to SIGINT (CTRL+C). The whole mess must instead be sent the SIGSTOP (CTRL+Z) and later killed with SIGKILL (kill -9 [pid]).

Use rb-appscript to Launch Flash Player.app, Focus the app, and Open the SWF

This approach seems to work better than the exec and focus strategy because we are able to focus (activate) the player before sending it a failing SWF file. This at least gives us the error dialog in front of other applications. We get the added benefit in that if we manually dismiss the dialog, our process works normally.

Unfortunately, if we interrupt the parent process (CTRL+C) before dismissing the dialog, our parent process becomes locked and must be killed brutally with SIGKILL.

Solution

The only solution that I’ve been able to get consistently working, is to fork on the AppleScript features and use exec kill -9 [process] when we interrupt the application.

An example of this process can be seen in the lib and test packages of this project.

Example

You can install the latest version of this project as a gem with:


gem sources -a http://gems.github.com (you only have to do this once)
gem install lukebayes/clix_flash_player

You can use the library in your Ruby code like this:


require 'rubygems'
require 'clix_flash_player'

player = CLIXFlashPlayer.new
player.execute('bin/Flash Player.app', 'bin/MyProject.swf')

# Do something else here...

player.join

MIT License

Copyright (c) 2009 Pattern Park

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.