Archive for the ‘AIR’ Category

Zinc 3.0, AIR, SQLite

Monday, February 11th, 2008

It was with great interest that I noticed a new release of the zinc 3 flash projector tool, and looking at the features it would appear to do everything I need.

To explain, the products I work on are distributed and sold in 2 ways, DVD and web access. Previously, we’d had 3 separate distributions in effect : a disk based executable for windows, one for mac, and a server based one for the web site. All did (and still do) use the same assets, but nevertheless it’s a big effort to keep all 3 in sync and up to date (This, of course, costs us money).

So, the promise of one common code base (or, at least, much much further towards one), and a pretty well identical and consistent interface on both DVD and web was a big plus for me to sell to the company when I suggested a flex version.

So far it’s gone extremely well (As I’d hoped). I’ve abstracted out the database access (initially, prior to Apollo/AIR I used a socket server built in haxe for the local version, but now it’s remoting using flourine for web and AIR’s native sqlite access for the disk), and apart from that and a couple of file save classes I do have 2 projects that share 95% of their code. Cross platform. Sorted.

Except for one thing, which is that it’s a requirement to have some sort of copy protection on the disks we sell.
AIR , being a runtime, makes that a little less straightforward to implement than a standalone executable, and I’ve yet to decide quite how I’m going to do it.
The system we use at the moment (Sony’s Securom) relies on the executable being encrypted against the DVD, but of course I can’t do that on the AIR runtime…
I have some thoughts involving protecting the “stub” exe that air seems to use, using a web based licensing system (we tried that before, with no great success), or maybe having a socket based “licence server” that runs off the disk itself. To be honest I don’t much like any of them, being the one who has to answer the support calls when all these schemes fail (Copy protection problems are 90% + of our support calls, and I hate it …).

At this point it’s worth reading this interesting article “AIR is not a projector tool”, which makes the points of difference between AIR and projector tools rather better than I can (and uses zinc 3 as an example).

All of which brings me back to Zinc 3, and in particular it’s sqlite access (since that’s the deal breaker for my application).
I will, however, start with the AIR sqlite implementation, which I have to say is extremely good.
Apart from some early hiccups in the first betas (writing blob binary data and a bug with some null results) plus the decision to remove full text search (quite understandable but a disappointment for me) it’s really well thought out and very usable indeed.
Data comes out typed and ready to use in flex, it deals with binary results, hell you can even specify an object to use as a result format or access fields by their name in the sql query. There’s also a nice api for analysing the database schema now rather than the rather clunky sqlite native method (Yes, I’ve used that and had to parse the results :( ). And it works, in that I can rely on it 100%, based on experience.

Now, compare and contrast with that in zinc 3, the documentation is here. It’s short (Drill down to Database > Objects > Database.SQLite) …

The first thing that I noticed is that there is no code completion for it in flex builder (I believe it uses some sort of run time resolver package instead, not thought that one through as yet though). Fair enough, I can live with that, so I ignored it and built a quick test using a production database and some very simple queries.

Next it seems that you have to make a call then check if there was a database error rather than a try/catch that one can use in AIR.
Fine, I guess that’s an abstraction that helps make the sqlite access compatable with the 3 others (mySql, Access, and ADO) that zinc supports.
However, I don’t particularly like it.

Next, all your results come back as a multi dimensional array. Of strings. Mnnnnn. So that’s quite a few parseInt()s then and whilst I’ve not tried it I suppose blob data is out of the question. Not only that, but you’re forced to use index based access to the results, which is not especially readable.
I did try the getXML() method thinking that it might bring back field names in the xml but I’m afraid that for me it just returns nothing at all. oops.

There doesn’t seem to be any way to use parameters in the query, rather you have to build the whole query as a string.
Now in this app I’m not concerned about sql injection and having to escape input, but I’d rather it was there for the time that I do.

Still, it did seem to work well enough to consider giving it a go for real, so that what I did. The service in question is roughly 2000 lines of actionscript, I guess it took me about 3 hours to port it over, which was tedious but not too bad.

It didn’t actually work first time (Yes, I expected that!) but fortunately it’s fairly easy with zinc to build a debugging projector and use the flex debugger.

Turns out that it doesn’t do what I can do with AIR, which is to just keep open a database connection for the life of the application (I’m relaxed about doing that in AIR, particularly since I can open the database read only, which I can’t in zinc as far as I can tell).
Instead you need to keep opening and closing the connection to the local file, and once I’d worked that out my results stopped having zero length (Hey, why no error raised? That would make more sense. If I’m stupid enough to query a closed connection then I should be told) and I could correct my own errors (unusually for me, I didn’t have all that many).

I’m happy to say that it does all work as expected in zinc now (which is good, this was not a trivial test, the db gets a lot of use), with a couple of important caveats.
Firstly, it’s slow. Noticeably so. Mainly in deference to the web version, I do regularly pull a large amount of data out of the db that gets sent to the client, which cuts down on the latency of making many smaller queries much more often. In c# or AIR, these big operations occur so fast as to be acceptable in actual use (probably in the order of a second at most, even on our minimum spec clients). In zinc, I’d say about 5 or 6 seconds on the fastest, which you do notice.
I’ve yet to profile it, it’s possible there are improvements to be made (though I did optimise the database open/close as much as I could).
However, the app itself is sluggish compared to both flash player and AIR, even when I’m not touching the database (memory usage appears to be fine, mind you).
The worst point is that the projector will crash, and I just cannot publish an application that does that at all regularly (AIR, by comparison, will not do so).
It may only have been a couple of times in a day or so, but that’s too many to get through QA and I’ve not been able to pin it down on any one particular point.

I think I’ll be waiting a while before giving zinc 3 another go.
Whilst this little review may seem harsh, I appreciate that it’s not easy at all to produce rock solid software at version .0 and I’m actually really glad to see zinc still out there and improving. I’m hoping it improves to the point where I feel that I can use, and quite confident that it will.
There are other features that whilst not must have will help us a great deal, so I’d like to be able to use them.
I should say that (perhaps unfairly) I’ve not contacted multdmedia with any of my concerns before writing this, and I’m very happy to stand corrected if anything is inaccurate, misleading or unfair.

dogs.jpg

AIR : Error #2041: Only one file browsing session may be performed at a time

Monday, January 14th, 2008

This one came as a bit of an unwelcome surprise, in a kind of “didn’t work as I expected” kind of way.

Consider, say, a config class that needs to prompt the user for two files to use (in the case where I came across this, a database file and a directory of images, for instance) .

I’ve found (at least with flexbuilder beta3 and windows XP), that you cannot chain one file browse operation from the select event of another. (BrowseForOpen or browseForFolder are the only ones I’ve tested so far) .

The example mxml text below should demonstrate this …

The trick to fix it is to call the second browse operation via callLater() (if your class extends UIComponent) or a timer (if not).
so to fix the below you would change “checkConfig() ;” in the function file1Selected() to : this.callLater(checkConfig);

I also noticed that in that file the first file browse dialogue appears *beneath* the main application widow, which is a bit rubbish really.

That does make sense, in that the application window may not be rendered to screen in AIR on creationComplete, therefore the browse widow is placed on screen before the window of the AIR application (which appears above it since it was rendered to screen later on).

So … Change the call to checkConfig to the “windowComplete” event of WindowedApplication.
(I first tried the “applicationActivate” event, but seems that gets called whenever the AIR window is focused (or something), so caused some chaos and , confusingly, the same error. Because, of course, checkConfig() was called whenever the file browser was closed and the AIR window activated. DOH!)

As I said, this didn’t work as I’d expected. Is it *wrong*? I don’t know. I’d prefer it didn’t work this way, but so long as I know it does, I can work with it.
Which is really the point of writing about it, hope it helps anyone else lost on the same thing.

View the final, error free mxml file here.

=> this is the original example (that didn’t work…)

<mx:WindowedApplication xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” width=”674″ height=”343″ creationComplete=”checkConfig()”>
<mx:Script>
<![CDATA[

[Bindable]
private var filePath1:String;

[Bindable]
private var filePath2:String;

private function checkConfig():void
{
if(filePath1 == null)
{
var file1:File = new File();
file1.addEventListener(Event.SELECT,file1Selected);
file1.browseForOpen(”pick a file, any file”);
return;
}

if(filePath2 == null)
{
var file2:File = new File();
file2.addEventListener(Event.SELECT,file2Selected);
file2.browseForOpen(”pick a file, any file”);
return;
}
}

private function file1Selected(event:Event):void
{
var f:File = event.target as File;
f.removeEventListener(Event.SELECT,file1Selected)
filePath1 = f.nativePath;
checkConfig();
}

private function file2Selected(event:Event):void
{
var f:File = event.target as File;
f.removeEventListener(Event.SELECT,file2Selected)
filePath2 = f.nativePath;
}

]]>
</mx:Script>
<mx:Text x=”142″ y=”33″ width=”492″ id=”txtFilePath1″ text=”{filePath1}”/>
<mx:Text x=”142″ y=”83″ width=”492″ id=”txtFilePath2″ text=”{filePath2}”/>
<mx:Label x=”10″ y=”83″ text=”config file 2″/>
<mx:Label x=”10″ y=”33″ text=”config file 1″/>

</mx:WindowedApplication>




mx:WindowedApplication StatusBar (showStatusBar)

Friday, December 28th, 2007

One of the things at the very bottom of my TODO list has been to remove that apparently useless 20 pixels blank bar that appears at the bottom of an AIR app by default.

I’d set it in my brain to “ignore for the moment, got more important things to think about” level, where it had remained for far longer than was healthy for it.

I think I’d had some sort of mental block as to what it was, because it wasn’t until something reared it’s little head in my tired synapses and shouted “It’s a status bar” completely out of nowhere, It had never occurred to me that an offline application would have a status bar by default. A browser, yes, but …
On subsequent checking, it seems that quite a few do, but oddly enough it’s something I’d never really noticed up until now, even after 10 years or so of using them. Wierd.

Anyway, to remove it set the attribute showStatusBar = false in your mx:WindowedApplication mxml tag.

I think that perhaps I should file this one under “LIKE DUH!” rather than AIR, perhaps?

At least I hadn’t posted the question to flexcoders and made an arse out of myself, like usual :)