Archive for the 'Brevity' category

iPhone App Launch Sequence

May 22 2009 Published by under Brevity, Extensibility, iPhone, Objective C

Send to Kindle

I was going over the stuff I’m going to cover next week in my “From Flash to iPhone” workshop at Flash on Tap, and I started getting into how an iPhone app launches when you tap its icon. It might be a bit heavy to go into detail on it at the workshop, but I thought it was pretty interesting and writing about it might shed some light for developers moving past the newbie phase.

Coming from the Flash/Flex world – app start up is pretty simple. You specify a main class. When the SWF is launched, that class is instantiated, calling its constructor. Whatever is in the constructor of that main class is what happens.

But in your typical iPhone apps, you have C files, Objective-C classes, xibs, pchs, frameworks, and plists. Which is the chicken, which is the egg, and which comes first?

First of all, realized that Objective-C is an extension of C to add object oriented capabilities. If you’ve ever taken a C course, or cracked open a book on C, you’re going to see a file like this:

#include <stdlib.h>

int main(int argc, char *argv[]) {
            printf("Hello World");
            return 0;
}

When you run the program, it looks for a function called “main” and runs it. It passes in the number of command line arguments (int argc) and an array of strings that are the arguments. It executes whatever code is in that function and then exits, returning an int – usually 0 means it exited as usual, anything else means some kind of error.

Well, it turns out that Objective-C programs launch in exactly the same way. In fact, if you fire up XCode and create a Window Based Application named “Test”, you’ll see a file under “Other Sources” called “main.m”. It contains this:

#import <uikit/UIKit.h>

int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

This is the first bit of code that gets executed when you launch an app. For the most part, you don’t want to mess with it, unless you really know what you are doing. So what does it do? Creates an autorelease memory pool and then calls a function called UIApplicationMain, passing in the command line arguments, and two other nil arguments. We’ll see what at least one of those is in a bit.

UIApplicationMain creates whatever UI you have created and starts the program loop. Which means it just loops and sits there waiting for events. Eventually at some point, the user quits the program. This ends the execution of the UIApplicationMain method, returning an int return value. The main function releases the memory pool it created and returns that return value to the system. That’s all.

So if UIApplicationMain is a standard function in UIKit, how does it know about your classes and interfaces and stuff? Well, one of the first things it does is to read your Info.plist file, which looks something like this, if you view it as xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>English</string>
	<key>CFBundleDisplayName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundleExecutable</key>
	<string>${EXECUTABLE_NAME}</string>
	<key>CFBundleIconFile</key>
	<string>icon.png</string>
	<key>CFBundleIdentifier</key>
	<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1.0</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>NSMainNibFile</key>
	<string>MainWindow</string>
</dict>
</plist>

You’ll notice the last key/value pair theire is NSMainNibFile, which is set to MainWindow. You can also set this value in the Target info window:

target_info

You see the “Main Nib File:” entry way down at the bottom. Setting the value in this window, simply rights it into the plist file.

And what do you know, we happen to have a .xib (nib) file called MainWindow.xib in our project! Coincidence? I think not. Let’s take a look at that. Double click on it to open it in Interface Builder. The window itself is uninteresting, but the Document window shows us all the stuff that’s defined in here:

xibcontents

So main starts UIApplicationMain, which looks at the Info.plist file, sees this nib is the main nib, and loads it in. For most of the items in there that are linked to classes, it will create an instance of that class, deserialize any properties, styles, etc. you might have set on it, and then hook up any outlets or actions you might have set on it. So what do we have here?

First we have an entry called “File’s Owner” This is linked to the UIApplication class. So an instance of UIApplication is created. Yay!As clarified in the comments, UIApplication is actually created by the call to UIApplicationMain. The entry here merely links to that instance that gets created. It exists here mainly so we can set its delegate, as we will see soon.

Then we have “First Responder”. This is a bit of a special case, i.e. I don’t fully understand it. ;) But my understanding is that this does not get instantiated per se, but is a fill in for another class that will be responding to events.

Next up we have “Test App Delegate” which is linked to the class TestAppDelegate. If you jump back into XCode, you’ll see that you do indeed have a class with that name. So this class is instantiated.

Finally, we have “Window”, which is of type UIWindow. So we get one of those.

So the result of this is we now have instances of UIApplication, TestAppDelegate, and UIWindow created. Now, if you click on the Window object and look at the Attributes tab in the Inspector, you’ll see there are various properties you can set on it, such as scale mode, alpha, background color, tag, opaque, hidden, etc. The size tab also has dimensional and layout properties that can be assigned. Any properties set here are then set on the newly created objects.

Finally, we go to the connections tab. This is where our outlets and actions are defined. If you look at UIApplication, you’ll see it has an outlet called delegate, which is set to Test App Delegate. This is the same as calling setDelegate on the UIApplication instance, and passing in the instance of TestAppDelegate. Also note that TestAppDelegate has an outlet called window which is set to the Window instance. We are not going to dive into UIApplication’s code, but if you look at TestAppDelegate.h, you’ll see it has a @property called window, which is indeed a UIWindow.

#import <uikit/UIKit.h>

@interface TestAppDelegate : NSObject <uiapplicationDelegate> {
    UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

So now our UIApplication instance has a reference called delegate which points to our instance of TestAppDelegate, and that has a referenced called window which points to the UIWindow instance. We are done with the nib.

Now, UIApplication starts its event loop. When certain events occur, it passes them over to its assigned delegate to handle. The first, and most important event it delegates is “applicationDidFinishLaunching”. This means that all this plist and nib loading and deserializing and whatever else it needs to do, is done. So it calls the applicationDidFinishLaunching on its delegate.

And, look at that, our TestAppDelegate class just happens to have a method with that very same name.

- (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

All this does by default is take that window that was set and make it the key, visible window.

And that’s where it ends. If you want to do more, you would add code in that applicationDidFinishLaunching method to create views, view controllers, or whatever else.

Now, if you had created a View Based application, a lot of this would be the same, but you’d also have a TextViewController nib. This would be loaded by the MainWindow nib. This new nib would contain a reference to the TestViewController class, and a UIView linked to the view outlet on that view controller. So an instance of this view controller and a UIView would be created. In applicationDidFinishLaunching, this view would be added to the window:

- (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Override point for customization after app launch
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
}

OK, but say you don’t even want to use nibs. Can you just create a UIWindow by yourself and make it key and visible? And can you specify an app delegate without a nib? Yes and yes.

Back in our Test application, delete the MainWindow.xib file completely. Also go into Info.plist and remove the main nib file entry. Then open up main.m

Remember when we called UIApplicationMain and we passed in two nil args at the end? Now we see what those are for. They are string representations for two classes. The first one is the principle class name. If you pass in nil, this will use UIApplication as the principle class. Unless you know enough about UIApplication to recreate it or at least subclass it, you probably don’t ever want to mess with this. The last argument is the name of the delegate class you want to use. Again this is a string. So, now that we’ve gotten rid of our nib, we can tell UIApplication to use our TestAppDelegate directly:

#import <uikit/UIKit.h>

int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"TestAppDelegate");
    [pool release];
    return retVal;
}

So now we have our UIApplication instance and our TestAppDelegate instance. But we need our window. We can create this in applicationDidFinishLaunching. It usually looks something like this:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
	window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [window setUserInteractionEnabled:YES];
    [window setMultipleTouchEnabled:YES];
	[window setBackgroundColor:[UIColor whiteColor]];
    [window makeKeyAndVisible];
}

If you now wanted to add a view, you could do so something like this:

UIView *view = [[UIView alloc] initWithFrame:window.frame];
[view setBackgroundColor:[UIColor redColor]];
[window addSubview:view];

Well, hopefully that explains a bit about what happens when you fire up your app. And gives you a little more control and a few more options on how to do things.

Send to Kindle

7 responses so far

HEAD FAIL

Oct 25 2008 Published by under Brevity, Conferences

Send to Kindle

Sorry to all of you who showed up at the <head> conference to watch my presentation. I’m not sure exactly what happened, but we just couldn’t keep the sound up. The microphone kept cutting out. I tried two different microphones on my computer, switched over to Chris Allen’s computer, even switched Internet connections. No matter what we did, the sound would stay up only long enough for me to get a sentence or two out, then cut out.

So eventually we just gave up and went to Q and A. Cool to notice that about 50 people hung out for the whole session even though I couldn’t talk!

After that, someone mentioned that Flash 10 might be causing problems with Connect. So Chris downgraded his Flash Player to Flash 9. He was then able to get up and running and give his whole presentation without a problem. I know lots of others have mentioned having sound problems, so if you still need to speak, you might want to think about switching over to Flash 9. No guarantees, but it might save you some frustration.

Anyway, we might go ahead and record my session and make it available later. We’ll let you know if and when that happens.

[To clarify: the title does not mean that the <head> conference failed, only that my session failed. From all accounts, though mine were far from the only technical difficulties, the people who are attending a lot of sessions are enjoying it and getting a lot out of it.]

Send to Kindle

4 responses so far

Preloaders in AS3

Jan 21 2007 Published by under Brevity, Flash

Send to Kindle

[Note, although this post is right now over a year and a half old, it continues to be one of the most visited pages on my site. If you are just showing up here now, you should note that the data here is a bit dated and may not work exactly as described in the current version of the Flex SDK. In fact, I am pretty sure it DOESN'T work as described anymore. Feel free to read through this for some overall info, but check all the comments as well, which may have more info or links to more up-to-date data. I haven't had to deal with this situation since I first wrote this, so don't have the current method for making AS3 preloaders to hand.]

It’s an age old problem. Let’s go back to AS2: You have a relatively large SWF, consisting of exported movie clips in the library, and/or a good deal of code contained in classes. All classes and exported assets load in prior to frame one being displayed, so the viewer sees nothing while it is all loading in.

Solution: Turn off “export first frame” on your exported assets, and place an instance on some frame in the timeline to force them to be compiled into the SWF. For classes, set classes to export to some later frame. Then put your preloader on frame one, stop the timeline, loop until everything is loaded, then jump to an initialization frame.

Now jump to AS3 with mxmlc. There is no timeline. Embedded assets and all classes load in prior to frame one as in a default IDE-created SWF. So, how do you create a preloader?

Well, if you are using Flex, it’s all programmed in there for you, and while I don’t know the specifics, I know you can specify a custom preloader in Flex, and there is obviously a default preloader in a Flex app. Since the Flex framework is all written in AS3, I knew there must be some way to do this in an AS3 only project, but it wasn’t very clear. In fact, you might say it was rather hidden. My first idea was to check the compiler arguments. These two seemed interesting:

frames.frame label class name [...]
Specifies a SWF file frame label with a sequence of class names that are linked onto the frame.
This is an advanced option.

generate-frame-loader=true|false
Toggles the generation of an IFlexBootstrap-derived loader class.
This is an advanced option.

But that is the entire extent of the documentation on the subject, and doing a web search didn’t turn up a whole lot more.

Then, last Thursday, Ted Patrick happened to be in Boston, and stopped by for a tour of Brightcove. We were sitting there talking to Brian Deitte, who was also part of the Flex team til a few months ago and it occurred to me that one of these guys must have the answer. They pointed me to the [Frame] metadata tag, and said to check out the source for mx.core.Application. Sure enough, I see the following:

/**
* The frameworks must be initialized by SystemManager.
* This factoryClass will be automatically subclassed by any
* MXML applications that don’t explicitly specify a different
* factoryClass.
*/
[Frame(factoryClass="mx.managers.SystemManager")]

And, checking out SystemManager, I see a few interesting tidbits:

// NOTE: Minimize the non-Flash classes you import here.
// Any dependencies of SystemManager have to load in frame 1,
// before the preloader, or anything else, can be displayed.

and

* The SystemManager is the first display class created within an application.
* It is responsible for creating an mx.preloaders.Preloader that displays and
* mx.preloaders.DownloadProgressBar while the application finishes loading,
* then creates the mx.core.Application instance.

And finally, the create() method, which is basically called when the movie is fully loaded in:

[as]
public function create(… params):Object
{
var mainClassName:String = info()["mainClassName"];

if (mainClassName == null)
{
var url:String = loaderInfo.loaderURL;
var dot:int = url.lastIndexOf(“.”);
var slash:int = url.lastIndexOf(“/”);
mainClassName = url.substring(slash + 1, dot);
}

var mainClass:Class = Class(getDefinitionByName(mainClassName));
return mainClass ? new mainClass() : null;
}[/as]

A bit more searching around led me to this post by Roger Gonzalez, which explains it a bit more, though highly oriented towards Flex. Even he describes the Frame tag as “semi-secret and bizarre”. :) He also mentions that it is basically an inline alias for the “frames” compiler configuration option. So, with a bit more work I could probably figure out how to do it that way, but the metadata way seems easier so far.

This was enough for me to start testing in AS3 only. Here’s the deal:

First you create your main class as usual, and point the compiler to that as the class to compile.

You then use the [Frame] metadata tag, passing in another class as the factoryClass, like so:

[Frame(factoryClass="MyFactoryClass")]

This is where the magic happens. Basically, the Frame tag forces the compiler to create a two-frame SWF. All of your embedded assets, your main class and any classes that are used by the main class are forced into frame two. The only thing that goes into frame one is your specified factory class and any classes or embedded assets that it uses. Hence the above warning to include minimal other classes in this class.

So, this factory class is where you create your preloader. Generally, you want to stop the timeline, and then set up an enterFrame listener, or a timer to check currentFrame against totalFrames. When they are equal, it means that the rest of your classes and assets are loaded in and ready to go. You then want to call nextFrame() to move to frame two so those classes and assets will be available. At that point, you can instantiate your main class, using getDefinitionByName(). This allows your factory class to create a new instance of the main class without compiling a reference to that class into it – which would force the main class and everything else to load in frame one and defeat your preloader.

The slightly weird thing about this setup is that you are usually used to your main class being the “document class”. That is, the main class represents the main timeline of the SWF. In this setup though, the factory class actually becomes the document class. This has a few ramifications:

  1. The factory class has to extend MovieClip. NOT Sprite! It actually has frames, so it should be a MovieClip.
  2. When you create an instance of your main class, you then have to do an addChild to get it onto the display list.
  3. Your main class will not be the at the base of the display list. It will be a child of your factory class.
  4. Because you instantiate your main class, and THEN add it to the display list, be careful not to have its constructor call code which will refer to stage, as its stage property will not be available until after it is added.

OK, let’s look at an example. First we have the main class, which we will target with mxmlc:

[as]package {
import flash.display.Sprite;
import flash.display.Bitmap;

[Frame(factoryClass="com.bit101.MyFactory")]
public class FrameTest extends Sprite
{
[Embed(source="big_asset.jpg")]
private var Asset:Class;

public function FrameTest()
{
init();
}

public function init():void
{
var asset:Bitmap = new Asset();
addChild(asset);
}
}
}[/as]

This doesn’t do much other than embed a large jpeg image, which makes the SWF come in at over 3 MB. If you were to compile this normally, the end viewer would see a blank screen until that jpeg fully loaded in. But the addition of the line:

[Frame(factoryClass="com.bit101.MyFactory")]

causes the main class, along with the embedded jpeg, to go into frame two. Note that in this case it is safe for the the constructor to call the init function directly. But, as mentioned earlier, you might want to delay that until the instance is actually added to the display list, to avoid null stage references, etc.

Now let’s look at the factory class:

[as]package com.bit101
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.utils.getDefinitionByName;

public class MyFactory extends MovieClip
{
public function MyFactory()
{
stop();
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

public function onEnterFrame(event:Event):void
{
graphics.clear();
if(framesLoaded == totalFrames)
{
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
nextFrame();
init();
}
else
{
var percent:Number = root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal;
graphics.beginFill(0);
graphics.drawRect(0, stage.stageHeight / 2 – 10,
stage.stageWidth * percent, 20);
graphics.endFill();
}
}

private function init():void
{
var mainClass:Class = Class(getDefinitionByName(“FrameTest”));
if(mainClass)
{
var app:Object = new mainClass();
addChild(app as DisplayObject);
}
}
}
}[/as]

Note that it extends MovieClip. It immediately stops the timeline and adds an enterFrame listener. In that handler, it checks to see if framesLoaded == totalFrames. If so, it calls nextFrame() to make the main class available, and then calls init, which gets a reference to the main class, instantiates it, and adds it to the display list.

While second frame is still loading, it simply draws a progress bar on the stage, using root.loaderInfo.bytesLoaded and root.loaderInfo.bytesTotal to access the percent loaded.

This is a pretty simple example, but shows you how it works. I’m pretty sure it’s the only documentation out there on how to do this in AS3, so feel free to share it around.

Send to Kindle

133 responses so far

Brevity and Flash 9 AS3 Preview

Jun 28 2006 Published by under Brevity

Send to Kindle

Cool new feature of Flash Professional 9 ActionScript 3 Preview: Document Class.

Install Flash 9 Preview, create a new document, and in the Properties Panel, you’ll see a new field, “Document Class”. You can enter the name of an AS3 class here, as long as it’s in your class path, and it will serve as the main class of your swf. The class you uses must extend MovieClip or Sprite (or something else that extends one of those).

Now, when you create a Brevity App, what actually gets created is an AS3 class that extends org.brvty.core.BrevityApp, which extends Sprite. This means that Brevity integrates nicely with Flash 9 AS3 Preview.

1. Create a Brevity App with the Brevity IDE. Save it and parse it. This will create an AS3 class.
2. Create a new movie in Flash 9. Save it in the same directory as the Brevity App.
3. In the Document Class, put the name of your Brevity App, which should be the same as the class.

4. In Publish Settings, ActionScript 3.0 Settings, add a new class path and set it to the “classes” directory of your Brevity install.

5. Publish the swf in Flash 9 as usual.

Note that properties in the setup() function of your Brevity App will be ignored in this case. Background color, movie size and frame rate are all set in the IDE.

Send to Kindle

4 responses so far

Brevity SVN Repository Live

Jun 24 2006 Published by under Brevity

Send to Kindle

http://svn1.cvsdude.com/osflash/brevity/source/

Hosted by OSFlash. Thanks Aral.

Now you can get my latest bugs without waiting for the next release!

Send to Kindle

Comments are off for this post

Brevity Alpha 1 Released

Jun 24 2006 Published by under Brevity

Send to Kindle

http://www.brvty.org/alpha_1/

Go get it!

I almost feel like I should apologize here. While it’s pretty cool so far, in my mind it is still just a pale proof of concept to what I envision Brevity could become. But I’ve been talking it up so long, I figured I better put something out there for people to mess around with, and get some feedback, etc.

There’s a Windows executable package and a Python package, which should work just fine on a Mac. I also wrote up some quick documentation and a dozen or so sample files which I just tested on the PC and Mac, and they are all working fine for me. So now I sit back and cringe and wait for all the reports of how it doesn’t work on your machines… :)

Before you dive in, definitely read the documentation. There’s a config file in there where you have to set your paths to the compiler and player. If those are wrong, it’s not going to do much of anything.

We should also have an SVN repository up soon, courtesy of OS Flash, and there’s a mailing list (details at http://www.brvty.org). I would really, really, really appreciate keeping any feedback, problems, questions, etc. on the mailing list, rather than my personal email or blog.

Have fun. Looking forward to the feedback.

Send to Kindle

2 responses so far

Brevity Mailing List

Jun 18 2006 Published by under Brevity

Send to Kindle

I’m still picking away at Brevity when I can find the time, and it is getting very cool, if I do say so myself. Aral has set up a mailing list and SVN repository at OSFlash. You can sign up for the mailing list now, and I should have something up for download later this week. Mainly I need to work on a bit of documentation so that people know what to do with it.

I’ll also be looking for some help on the project. Particularly if you know some Python and py2app on OS X.

Send to Kindle

2 responses so far

Brevity News and Sample

Jun 09 2006 Published by under Brevity

Send to Kindle

Brevity is not dead. Some setbacks with lack of a pc lately. Getting used to the Mac, but it’s still slower for me.
http://www.brvty.org/doku.php?id=brevity_news

http://www.brvty.org/samplefiles/sample3d.html

Still looking for some py2app help, if anyone knows it well.

Send to Kindle

7 responses so far

Anyone know py2app really well?

Jun 03 2006 Published by under Brevity

Send to Kindle

Want to help on a cool open source application?

I’ve been plugging away at Brevity. I have it working pretty damn well on the pc, both in native Python, and compiled into an .exe with py2exe. I also have it working just as well on the Mac. In fact, I’m doing almost all Brevity development – both Python and ActionScript on the Mac, since my pc has been in the shop for a couple of weeks now.

I have managed to use py2app to create a Mac app that does not require Python/wxPython to run. But it’s not really working that well. I’ve learned that the app it creates is really like a special directory containing a python interpreter and all necessary packages, and running the app just runs the Python script in the directory. All cool, but the paths wind up all wrong. The Python script considers its “current directory” as the directory it’s in within the app, as opposed to the directory the app is in.

I was also getting really huge apps. Like 27 megs for a hello world app. Turns out that the current version of py2app copies all the Python documentation files into the app! Oops. Apparently the latest version on svn fixes this, but brings some other problems as it’s the first universal binary build. I’ve just been deleting the documentation out of there after I build.

So ideally, I’m looking for someone who really knows py2app who can become part of the Brevity team, and build out a decent setup script that will turn it into as small an app as possible that just works right.

Send to Kindle

Comments are off for this post

Brevity Mac update

May 28 2006 Published by under Brevity

Send to Kindle

So, as mentioned, my poor Toshiba is in the hospital. So for the last 6 days, 22 hours and 47 minutes, I’ve been confined to my Mac Mini. It could be another week or more, so I’ve settled down and tried to make the most of it.

I had some initial Python problems but finally got a good 2.4 install going, and got wxPython in there just fine.

I removed the ActiveX stuff from the Brevity IDE and it fired right up on the Python. That in itself is pretty amazing: that you can make a full featured, native UI application on Windows and run the same code on a Mac and get a native UI Mac application.

Now, getting the IDE to coordinate the other parts of Brevity: the parser, the compiler, and the player, was another story.

I spent hours trying to get the IDE to call the parser as an external Python program. I made it executable and chmod’ed it and everything. No go. Finally got it down to, print “hello world” and it still wouldn’t run. Yet a brand new Python program with the same code worked. So I copied and pasted the parser code into a brand new file and it worked fine. Arrrrrggghhhhh…. Some stray Windows bit must have copied over and Mac was choking on it. No idea.

Happily, the compiler had no major problems. Just changed the path and got that working pretty quickly.

Then onto the player. On Windows you can basically say:

SAPlayer.exe myfile.swf

So of cource I tried the same thing on the Mac, but it kept telling me it couldn’t execute the binary file. Finally after some searching I found out you’re supposed to do something like:

open -a SAPlayer myfile.swf

So now I can write Brevity code, press a button and have it save, parse, compile and launch. Not bad for a weekend’s work. Other than the open thing, all the code should continue to work on the pc side too. I’ll probably do a platform check in the launch method just so I don’t have to deal with multiple code bases.

Still some things here and there to clean up, but it’s functional enough so that I can go back to developing the AS3 classes and test them on the Mac.

Anyone know a good Mac AS3 editor? ;)

Looking for a public release some time in mid June.

Oh, also, if anyone has experience with py2app, drop me a line.

Send to Kindle

3 responses so far

Older posts »