Posts filed under 'Adobe Air'
Adobe AIR – PHP Tutorial Videos
AIR – PHP Development Tutorial Video
This powerful Adobe AIR & PHP Development Training Video will introduce you to Adobe’s powerful desktop development framework and show you how you can create functional applications using familiar tools originally designed for use on the web
Adobe AIR & PHP Development Tutorial Video
Here’s an exciting Adobe AIR & PHP Development Tutorial Video that serious designers and coders should give a shot. Over a series of short, engaging videos, users can learn to write several types of Rich Internet Applications (RIAs) for the desktop to meet personal and business goals.
Although it began as a simple way for people to share basic information, the internet has blossomed into a wilderness of technologies and ideas that have the power to shape the way people live their lives. As it has increased in complexity, the need for applications that bridge the gaps and take advantage of the web’s diversity has rapidly increased, and the Adobe Flex programming system and AIR deployment environment offers just that.
These videos cover the the design and implementation of applications using Zend AMF, ActionScript 3, and Adobe’s Flex Builder for developers on both PCs and Macs. You’ll learn how to adapt and enhance traditional web technologies for use as native desktop applications, and get the tools and knowledge to write software on the cutting edge of personal interaction with the web. PHP expert Richard Bates lends expert advice at every stage, and hands-on examples with sample files are included so you can follow along. The videos are available online through an unlimited subscription plan or for permanent purchase on CD / DVD.
Adobe Flex: A Versatile Development Solution
Adobe Flex is a widely available developer toolkit for creating Rich Internet Applications for the browser and the desktop alike. When paired with the competitively priced Flex Builder, users can easily write and debug web-friendly solutions on short timelines. There are several impressive features that people may not know about.
Flex makes it easy to adapt existing applications. If developers have an existing Java web application, they can mix and match functionality with the Flex framework. It’s especially helpful for Java developers to write the back-end in Java and have Flex handle UI features. And the Flex AJAX bridge also lets you get the best of two worlds in your app.
Flex is competitively priced. The Flex SDK is free, and the Adobe Flex Builder has a number of tiered discounts and pricing plans. Special rates for students make it a great option for those developing for the future. Pairing Flex with open-source development frameworks has also proven successful, as you can see in the tutorial course.
Flex has a place in the business and enterprise world. Developers have already begun to take Oracle applications and find ways to implement them with Flex. When combined with the versatility of Adobe AIR, this could mean a fast and efficient deployment framework for some pretty advanced stuff.
Flex is not difficult to learn, with a little patience and the right resources. This is perhaps the most important point, because it can be a major barrier for entry. With this Adobe AIR & PHP Tutorial Video, not only will you get a good primer on Flex but a thorough look at how it integrates with AIR on the desktop.
1 comment June 17, 2009
Data driven AIR Tutorial Part 2
Data driven AIR Tutorial Part 2: ORM, ActiveRecord-style
Adobe AIR provides a complete SQLite database engine, but no high level API to manage data out of the box. Enter ActiveRecord.js – a Javascript library that brings Rails’ ActiveRecord-style data interfaces to your AIR applications. No more writing SQL queries, worrying about database connections or dealing with persistence – building serious database applications in AIR is a cinch with ActiveRecord.js. In this tutorial, we’re going to build a simple client management system with AIR,
Introducing ActiveJS
ActiveJS is an open source project from Aptana that provides a series of Javascript libraries, notably ActiveRecord.js. ActiveRecord.js supports a number of database backends, including Adobe AIR, Google Gears, and Aptana’s own Jaxer platform.
We’re about to build a simple client management system, to demonstrate using ActiveRecord to handle database connectivity, persistence, model construction, relationships and basic data retrieval.
Getting started
To build our AIR application, we’ll be using Aptana Studio, the official free IDE for Adobe AIR development. If you’ve used Eclipse before, head over to aptana.com and download the release for your platform, then install the Adobe AIR plugin from inside Aptana. If you’re new to Aptana/Eclipse, run through the installation guide in the “A Powerful Tool for Building AIR Apps” section on another AIR article.
Creating the project
Fire up Aptana, make sure you’ve installed the AIR plugin, then open File > New > Project. Select “Adobe AIR Project” from the “Aptana Projects” folder, click Next, and give your project a name – I’ve called mine “ClientProjects”. Click Next, and you’ll be offered two screens to change application properties – the default values should be fine. Click Next twice till you come to “Import AIR Frameworks” – here, make sure you check AIR HTML Introspector and AIR HTML Menu Builder, then click Next. We’ll be using jQuery for some DOM work, so check “jQuery 1.3″ (or similar – 1.1+ will be fine) in the “Import Javascript Library” screen, then click Finish to create your project.

Your “Project” or “Navigator” view will now have a new entry with the AIR logo for your project name. Expanding it should display the above file tree.
Creating our application
We now have a basic AIR application template to work with. Aptana has included some sample code to demonstrate a handful of AIR features – we can safely clear this out to build our application. You can safely delete LocalFile.txt now. Replace the contents of ClientProjects.html with the following:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Client Database</title>
<link rel="stylesheet" href="sample.css" />
<script type="text/javascript" src="lib/air/AIRAliases.js"></script>
<script type="text/javascript" src="lib/air/AIRMenuBuilder.js"></script>
<script type="text/javascript" src="lib/air/AIRIntrospector.js"></script>
<script type="text/javascript" src="lib/activerecord/active_record.air.js"></script>
<script type="text/javascript" src="lib/jquery/jquery-1.3.2.min.js"></script>
</head>
<body>
<h1>Clients</h1>
<table id="target_clients" border="1">
<thead>
<tr>
<th>Client</th>
<th>Contact</th>
<th>Phone No.</th>
<th>Projects</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script type="text/javascript" src="application.js"></script>
</body>
</html>
Note that we include a laundry list of Javascript libraries in our <head> – let’s make sure these are in place.
You’ll need to change the “lib/jquery/jquery-1.3.2.min.js” line based on the version of jQuery that shipped with your Aptana. Alternatively, replace the src value with http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js – a copy of jQuery hosted on Google’s servers, and the same version I’ve used for this article.
If you aren’t using Aptana, you need to copy AIRAliases.js, AIRMenuBuilder.js and optionally AIRIntrospector.js from the frameworks/ folder inside the AIR SDK – this can be downloaded from the Adobe AIR tools page on Adobe.com. Make sure you reconstruct the file structure we have here, or modify the <head> section of the HTML to suit.
ActiveRecord.js can be downloaded from the Github repository – create a folder called activerecord under your project’s lib folder and save active_record.air.js there. I’m using the latest as of 2009-04-25.
Building the application framework
We’re going to keep our code in a Javascript file called application.js inside the main project folder, so create that now. The easiest way to create files in Aptana is to right click on our project – ClientProjects (or similar) – in the Project pane on the left, then select New > (file type). Aptana will take care of storing the file on the filesystem and keeping track of it within our project. Let’s start off our new application.js some basic structure – copy the following in:
application = {
models: {},
_init_database: function() {
},
_init_menus: function() {
},
events: {},
init: function() {
application._init_database();
application._init_menus();
application.draw_clients();
}
}
This will offer us some basic structure for our application. One global application object will prevent us from filling the mainspace, and we can easily see where our application logic is. In particular, note the models and events objects that are currently empty – we’ll use models to store our ActiveRecord models so that we have a centralised location for any application component to access them; events will simply store functions that respond to events.
Let’s start by configuring ActiveRecord for our database.
Up and running with ActiveRecord
Copy this over the _init_database function we created in application.js a moment ago:
_init_database: function() {
ActiveRecord.connect(ActiveRecord.Adapters.AIR, 'application_db');
var Client = ActiveRecord.define('clients', {
name: '',
contact: '',
contact_phone: '',
}, {
valid: function() {
if (application.models.Client.findByName(this.name)) {
this.addError('Client name already in use.');
}
}
});
Client.hasMany('projects');
var Project = ActiveRecord.define('projects', {
project_name: '',
client_id: 0,
});
Project.belongsTo('client');
application.models.Client = Client;
application.models.Project = Project;
application.models.Client.afterCreate(function (row) { application.draw_clients(); });
application.models.Project.afterCreate(function (row) { application.draw_clients(); });
application.models.Client.afterDestroy(function () { application.draw_clients(); });
},
We first start a connection via ActiveRecord to an AIR database by the name of ‘application_db’. This will be automatically dealt with on the fly – if the database does not exist, it will be created. Next, we define two models, Client and Project. Notice we don’t actually ask for these to be created – if the database tables need to be created, they will be, but ActiveRecord will handle persistence transparently and check to see if they already exist. ActiveRecord allows us to define validation on models, so for now we’ll just enforce unique names on any Client we add to the system. We also relate both these models to each other, using hasMany and belongsTo – we can now use getProjectList() on any client row, and access the client property on any project row. We add a few events to our models – we’ll look at these in just a moment.
We’ll keep these models in application.models for future reference.
Creating our menus
We’ll use the AIR Menu Builder framework, similar to our previous Data Driven AIR article. Create a new file in your main project folder called application_menus.xml, and copy over the following:
<?xml version="1.0" encoding="utf-8"?>
<root>
<menuitem label="Actions">
<menuitem label="New Client" onSelect="newClient" />
</menuitem>
</root>
We can now define our _init_menus() function. Head back to application.js and copy this over _init_menus:
_init_menus: function() {
var windowMenu = air.ui.Menu.createFromXML('application_menus.xml');
air.ui.Menu.setAsMenu(windowMenu);
},
Also, copy this into the very end of application.js:
function newClient() {
application.events.newClient();
}
This allows our AIR Menu Builder to find our application.events.newClient() function, which we’ll define in just a minute.
When we run our application, we’ll have a simple “Actions” menu – either a standard native application menu (OS X), a window menu (Windows). We don’t actually need an exit menu item in our application (system chrome / application menus provide the same functionality), but we can easily add one using the “Menu_exit” function from our last Data Driven AIR article.
Handling events
To create some “New Client/Project” buttons, we’re going to need to handle the events. We’ll point all our button handlers at functions inside the events object we added to application.js‘ application. Copy this code over the events: {}, line:
events: {
newProject: function(client_id) {
var params = {};
params.client_id = client_id;
params.project_name = prompt('Project Name');
application.models.Project.create(params);
},
newClient: function() {
var params = {};
params.name = prompt('Client Name');
params.contact = prompt('Client Contact');
params.contact_phone = prompt('Client Contact Phone');
application.models.Client.create(params);
}
},
Notice we don’t have to worry about any SQL – ActiveRecord will take care of actually validating and creating the database entry. We simply prompt the user for all field values, construct an object with properties matching column names, and hand over to the create method of our model. Models come with a number of methods like this – see this API documentation page for more details.
Constructing our table
We’re nearly finished – our backend is in place, now we just need to pull data out of our database and display it on the screen. This is where jQuery comes in.
In the HTML we started with, we had a table with a thead and tbody explicitly defined. In particular, the tbody was empty – we need to use jQuery to fill it with rows retrieved from our database. We explicitly define a tbody so that we can clear out the table before retrieving a new recordset from the database, without clearing the table header.
Create a new draw_clients function inside the application object definition in application.js – e.g. between events and init:
draw_clients: function() {
$("#target_clients tbody").empty();
var clients = application.models.Client.find({all: true, order: "id ASC"});
for (i=0;i<clients.length;i++) {
var client = clients[i];
var projects = client.getProjectList();
var project_cell = $('<td>');
for (i=0;i<projects.length;i++) {
$(project_cell).append(projects[i].project_name + '<br/>');
}
$(project_cell).append($('<a>').attr('href', '#').data('id', client.id).text('Add').click(function() {
application.events.newProject($(this).data('id'));
}));
$("<tr>").append($('<td>').text(client.name))
.append($('<td>').text(client.contact))
.append($('<td>').text(client.contact_phone))
.append(project_cell)
.appendTo("#target_clients tbody");
}
},
This is quite an intricate block of code, so let’s have a closer look.
var clients = application.models.Client.find({all: true, order: "id ASC"});
This line will simply fetch all clients in our database, and store them in clients, which is now an array of objects. Notice we use an “order” parameter – there are a number of options available for this method, but are not presently documented. A “limit” options is available, and takes an integer number of rows to retrieve, which is generally passed onto the database adapter as an SQL LIMIT clause.
var projects = client.getProjectList();
Given a single client in client, we can call the get(RelatedModelNameInCamelCase)List() method to retrieve related rows. This is one of the methods created by declaring the hasMany relationship earlier.
$(project_cell).append($('<a>').attr('href', '#').data('id', client.id).text('Add').click(function() {
application.events.newProject($(this).data('id'));
}));
Here, we create a link for our users to add projects using the events.newProject function we defined earlier. This function needs to know what client to add a project to, so we take advantage of jQuery’s data system to bind the correct client ID to the row without messy HTML attributes or other markup-based data storage.
The final cog
There’s just one line left – we need to set the wheels in motion for our application, by handing over to the init method that we defined when we first created application.js. Add this to the very end of application.js:
application.init();
And we’re done! Fire up the application using the “Run” (green play icon) button in Aptana:

The application appears, but it’s a little bare – let’s enter some sample data:

Add some projects to clients, and we’re ready to roll.

The best bit is, this is all automatically persisted – close the application, open it up again using the Run button, and all your data is still perfectly intact!
Wrapping up
Here’s our final code for application.js:
application = {
models: {},
_init_database: function(){
ActiveRecord.connect(ActiveRecord.Adapters.AIR, 'application_db');
var Client = ActiveRecord.define('clients', {
name: '',
contact: '',
contact_phone: '',
}, {
valid: function(){
if (application.models.Client.findByName(this.name)) {
this.addError('Client name already in use.');
}
}
});
Client.hasMany('projects');
var Project = ActiveRecord.define('projects', {
project_name: '',
client_id: 0,
});
Project.belongsTo('client');
application.models.Client = Client;
application.models.Project = Project;
application.models.Client.afterCreate(function (row) { application.draw_clients(); });
application.models.Project.afterCreate(function (row) { application.draw_clients(); });
application.models.Client.afterDestroy(function () { application.draw_clients(); });
},
_init_menus: function(){
var windowMenu = air.ui.Menu.createFromXML('application_menus.xml');
air.ui.Menu.setAsMenu(windowMenu);
},
events: {
newProject: function(client_id) {
var params = {};
params.client_id = client_id;
params.project_name = prompt('Project Name');
application.models.Project.create(params);
},
newClient: function() {
var params = {};
params.name = prompt('Client Name');
params.contact = prompt('Client Contact');
params.contact_phone = prompt('Client Contact Phone');
application.models.Client.create(params);
}
},
draw_clients: function() {
var clients = application.models.Client.find({all: true, order: "id ASC"});
$("#target_clients tbody").empty();
for (i=0;i<clients.length;i++) {
var client = clients[i];
var projects = client.getProjectList();
var project_cell = $('<td>');
for (j=0;j<projects.length;j++) {
$(project_cell).append(projects[j].project_name + '<br/>');
}
$(project_cell).append($('<a>').attr('href', '#').data('id', client.id).text('Add').click(function() {
application.events.newProject($(this).data('id'));
}));
$("<tr>").append($('<td>').text(client.name))
.append($('<td>').text(client.contact))
.append($('<td>').text(client.contact_phone))
.append(project_cell)
.appendTo("#target_clients tbody");
}
},
init: function(){
application._init_database();
application._init_menus();
application.draw_clients();
}
}
function newClient() {
application.events.newClient();
}
application.init();
You can download a working copy of the Aptana project here (suitable for import – extract the archive, then see File > Import : General > Import Existing Projects…).
Further reading
You might find these resources useful in exploring AIR databases, ActiveRecord.js, and general data peristence.
Add comment May 4, 2009
Adobe Air Tutorial – Create a Application
Practical hands-on Adobe Air Tutorial. This easy to follow series will show you how to use Adobe AIR to create a fully functional Personal Information Management application.
Data-driven Adobe AIR
Relational databases form the core of most data-driven applications. The SQLite database engine is fast, lightweight, and well suited to client-side data management. In this tutorial, I’ll show you how to build data-driven Adobe AIR applications using the SQLite components.
Getting Started
To follow this Adobe AIR tutorial, you’ll need a text editor, and a copy of the Adobe AIR 1.1 SDK (the upcoming 1.5 release should be compatible). A basic understanding of AIR is required.
To start the project, we need a folder to store our code files. I’ll be using C:\AIR\datadriven, and you can substitute this in examples with the path to your project folder. (If the path has spaces, remember to quote it when working in a terminal / command prompt.) Make sure you know the absolute path to bin/adlin your AIR SDK folder – for example, mine’s at C:\AIRSDK\bin\adl.
We’ll be using the jQuery Javascript framework for this application. Grab a copy at jquery.com.
Building the application
We’re going to build a simple Personal Information Management (PIM) utility. The application will simply allow us to create arbitrary “pages” to manage textual information, stored in an in-memory SQL database. An extension of this application could create a complete personal content management system / single-user wiki.
Creating the application descriptor
Open your text editor and create an application.xml file in the project folder. Our application descriptor has a little more detail this time:
<?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://ns.adobe.com/air/application/1.0"> <id>com.example.html.datadriven</id> <version>1.0</version> <filename>datadriven</filename> <description>Data-Driven Adobe AIR Sample</description><initialWindow> <title>Data-Driven Adobe AIR</title> <content>datadriven.html</content> <visible>true</visible> <resizable>false</resizable> <minimizable>false</minimizable> <maximizable>false</maximizable> <width>800</width> <height>600</height> <minSize>800 600</minSize> </initialWindow> </application>
This tells Adobe AIR that we are building an application named “Data-Driven AIR” to be installed in /datadriven. I’ve bolded the additional properties — here’s what they represent:
<description>: this is displayed in the AIR application installer, to explain your app to the user.
<minimizable>, <maximizable>: these control how the user can interact with your initial application window. Keep in mind that any new windows you create (e.g. through Javascript) are not automatically managed with these same guidelines.
<minSize>: this defines an absolute minimum size for your initial application window. The “width height” format is used – no “x”. This is useful to maintain some control if resizing is permitted. Similarly, <maxSize> is available and uses the same format.
Remember, the samples/descriptor-sample.xmlfile in your AIR SDK folder has a full example of the options available.
Creating the HTML framework
We’ll need a fairly basic HTML structure for this application – create datadriven.html with your text editor and copy in the following:
<html> <head> <title>Data-driven AIR Sample</title> <link href="sample.css" rel="stylesheet" type="text/css"/> <script type="text/javascript" src="AIRAliases.js"></script> <script type="text/javascript" src="AIRMenuBuilder.js"></script> <script type="text/javascript" src="jquery-1.2.6.min.js"></script> <script type="text/javascript" src="behaviour.js"></script> </head> <body> <div id="nav"> </div> <div id="body"> </div> </body> </html>
We reference our copy of jQuery (I’m using the minified and gzipped copy of 1.2.6), as well as behaviour.js which will contain our behaviour code. Create this file now, and leave it empty. Also create the sample.cssfile for our CSS styles, and copy in this code:
body { font-family: Tahoma; margin: 0; padding: 0; border: 0; height: 100%; max-height: 100%; } #nav { position: absolute; top: 0; bottom: 0; left: 0; width: 200px; height: 100%; background-color: #eee; padding: 5px; } #body { position: fixed; top: 0; left: 200px; right: 0; bottom: 0; background: #fff; padding: 5px; }
Our references also include the AIRAliases.js file, as well as the menu builder framework AIRMenuBuilder.js. You’ll need to copy both of these from your AIR SDK directory – they’re located under frameworks/ – and place them in your project folder.
We can easily check if this is working so far, using the command line adl utility. Assuming the same paths I mentioned in “Getting Started”, open up a command line window and type the following:
C:\>cd C:\AIR\datadriven C:\AIR\datadriven>C:\AIRSDK\bin\adl.exe application.xml
The application window will appear, with a light-gray navigation pane down the left. We’re all set to start building on AIR!
The Menu System
AIR provides a menu builder framework to make complex menu structures easy. In our last AIR tutorial, we looked at manually constructing AIR menus for power and flexibility. Today, we’re going to use the menu builder framework – in AIRMenuBuilder.js – to make menu creation quick and easy.
With your text editor, create the menus.xml file and copy this in:
<?xml version="1.0" encoding="utf-8"?> <root> <menuitem label="File"> <menuitem label="New Page" onSelect="Menu_createPage" /> <menuitem label="Exit" onSelect="Menu_exit" /> </menuitem> </root>
This XML document represents the structure of our menus. Tree-style data is best represented in some sort of hierarchical format – constructing menus in vanilla Javascript is slightly time consuming to allow for switching contexts. Here, we simply define a menu item, ‘File’, and because our following menu items – ‘New Page’, ‘Exit’ – are within the File node, the menu builder framework will automatically create them as submenu items.
We stil need to create the menu, however. Open up behaviour.js, and copy in the following:
$(document).ready(function(){ $("#body").text('Select a page or create a new one.'); createMenus(); createDB(); populateDB(); refreshPage(); }); function createMenus() { air.ui.Menu.setAsMenu(air.ui.Menu.createFromXML('menus.xml')); }
The first section of this code block points to the various functions we need to construct the page. Using jQuery, any code within a $(document).ready() block is executed once the page DOM has loaded. The createMenus() function instructs the menu builder framework to generate menus from the XML tree in menus.xml, and set that as the standard menu for the application window.
Connecting to a database
AIR allows developers to create an in-memory SQLite database on the fly, for quick and easy data storage. In another tutorial, we’ll look at persisting the database on disk; today, we’ll quickly create a database to store our pages.
At the end of behaviour.js, add the following:
function createDB() { db = new air.SQLConnection(); try { db.open(null); } catch (error) { air.trace('Could not open in-memory DB.'); } } function populateDB() { stmt = new air.SQLStatement(); stmt.sqlConnection = db; stmt.text = "DROP TABLE IF EXISTS pages"; stmt.execute(); stmt.text = "CREATE TABLE pages (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT)"; stmt.execute(); }
Here, the createDBfunction tries to establish a new SQL connection, and set the global db variable to the connection handle. This will allow us to conduct operations on this particular database later; AIR is built for multiple synchronous database connections as needed.
The populateDB function proceeds to create our pages table, which will store the titles and content of the various pages in our application. Notice we establish an air.SQLStatement object, and point it to our database connection first. Long-running queries can be run in asynchronous mode to avoid locking up the interface; for now, we’ll just execute our queries immediately.
Listing pages in the menu
Add this code to the end of behaviour.js:
function refreshPage() { stmt.text = "SELECT id,title FROM pages"; stmt.execute(); result = stmt.getResult(); $("#nav").empty(); if (!result.data) return; for(i=0;i<result.data.length;i++) { var row = result.data[i]; $('<a>').attr('href', '#') .text(row.title) .click(function(){viewPage(row.id);}) .appendTo('#nav'); $('#nav').append('<br/>'); } }
This will, whenever requested, print out a fresh list of page titles from the database into our navigation bar. When we run a SQL query and expect results, we can retrieve a result object from air.SQLStatement.getResult(), which has a data property – an array – which in turn has a length property informing us of how many rows are in the result set. We can use this to iterate over result.data, and use the power of jQuery to quickly construct links. Whenever the page link is clicked, we call the viewPage function – so let’s go ahead and define that now.
Add this to the end of behaviour.js:
function viewPage(id) { stmt.text = "SELECT content FROM pages WHERE id = ?"; stmt.parameters[0] = id; stmt.execute(); $("#body").html(stmt.getResult().data[0].content); }
Once again, we query our SQLite database to find the particular page ID requested, and insert its contents into the <div id="body"> on the page.
Creating pages; Menu behaviours
Finally, we need to allow the creation of new pages, to get data into the system. We also need a behaviour for the menu button.
Recall in menus.xml, we referenced the Menus_createPage and Menu_exitfunctions:
<?xml version="1.0" encoding="utf-8"?> <root> <menuitem label="File"> <menuitem label="New Page" onSelect="Menu_createPage" /> <menuitem label="Exit" onSelect="Menu_exit" /> </menuitem> </root>
Let’s define these now in behaviour.js:
function Menu_createPage() { title = prompt('Please enter a page title.'); content = prompt('Enter your page content.'); stmt.clearParameters(); stmt.text = "INSERT INTO pages (title, content) VALUES (?, ?)" stmt.parameters[0] = title; stmt.parameters[1] = content; stmt.execute(); stmt.clearParameters(); refreshPage(); } function Menu_exit() { var event = new air.Event(air.Event.EXITING, false, true); air.NativeApplication.nativeApplication.dispatchEvent(event); if (!event.isDefaultPrevented()) { air.NativeApplication.nativeApplication.exit(); } }
We use the Javascript prompt system to take textual input from the user. AIR displays a full-size text input for our usage. We then use a SQL statement with parameters – the ? question marks in our query represent placeholders, and any data passed in through parameters is sanitized to avoid security issues. We need to remember to clear parameters afterwards, as we share our SQLStatementobject between many SQL queries. Once we have created the new page, we refresh the current page list by calling the refreshPage function.
The exit function is identical to the one we used last time – we check if any other areas of the runtime want to stop exiting at this point, and if not, we go ahead and terminate the application.
Wrapping up
Here’s our completed behaviour.js:
$(document).ready(function(){ $("#body").text('Select a page or create a new one.'); createMenus(); createDB(); populateDB(); refreshPage(); }); function createMenus() { air.ui.Menu.setAsMenu(air.ui.Menu.createFromXML('menus.xml')); } function createDB() { db = new air.SQLConnection(); try { db.open(null); } catch (error) { air.trace('Could not open DB.'); } } function populateDB() { stmt = new air.SQLStatement(); stmt.sqlConnection = db; stmt.text = "DROP TABLE IF EXISTS pages"; stmt.execute(); stmt.text = "CREATE TABLE pages (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT)"; stmt.execute(); } function refreshPage() { stmt.text = "SELECT id,title FROM pages"; stmt.execute(); result = stmt.getResult(); $("#nav").empty(); if (!result.data) return; for(i=0;i<result.data.length;i++) { var row = result.data[i]; $('<a>').attr('href', '#') .text(row.title) .click(function(){viewPage(row.id);}) .appendTo('#nav'); $('#nav').append('<br/>'); } } function viewPage(id) { stmt.text = "SELECT content FROM pages WHERE id = ?"; stmt.parameters[0] = id; stmt.execute(); $("#body").html(stmt.getResult().data[0].content); } function Menu_createPage() { title = prompt('Please enter a page title.'); content = prompt('Enter your page content.'); stmt.clearParameters(); stmt.text = "INSERT INTO pages (title, content) VALUES (?, ?)" stmt.parameters[0] = title; stmt.parameters[1] = content; stmt.execute(); stmt.clearParameters(); refreshPage(); } function Menu_exit() { var event = new air.Event(air.Event.EXITING, false, true); air.NativeApplication.nativeApplication.dispatchEvent(event); if (!event.isDefaultPrevented()) { air.NativeApplication.nativeApplication.exit(); } }
Finalising, further reading
And we’re done! We can run the completed application at command line again:
C:\>cd C:\AIR\datadriven C:\AIR\datadriven>C:\AIRSDK\bin\adl.exe application.xml
To explore further, the online documentation for AIR has a number of resources you might find handy:
Add comment December 3, 2008
Beginners Adobe AIR Tutorial – Part 2
This Beginners Adobe AIR Tutorial covers the fundamentals for creating a simple AIR application.
Getting Rich with Adobe AIR
Adobe AIR provides developers with a rich set of tools to build applications with web technologies. Alongside HTML, CSS and Javascript, AIR applications can use native menus, system tray / dock icons, drag and drop of files and other media, clipboard manipulations, and even file system APIs. In this tutorial, we’ll look at some of the many APIs that Adobe AIR provides.
Getting Started
To follow this tutorial, you’ll need a text editor, and a copy of the Adobe AIR SDK. A basic understanding of AIR is also helpful. We recommend you read through the first tutorial in our Adobe AIR series, “Getting Started with Adobe AIR“, to setup your development environment and explore the basics of the AIR platform.
To start the project, we need a folder to store our code files. I’ll be using C:\AIR\richair, and you can substitute this in examples with the path to your project folder. (If the path has spaces, remember to quote it when working in a terminal / command prompt.) Make sure you know the absolute path to bin/adl in your AIR SDK folder – for example, mine’s at C:\AIRSDK\bin\adl.
We’ll be using the jQuery Javascript framework for this application. Adobe AIR has excellent support for most major frameworks, and jQuery in particular is extremely popular for AIR applications. Grab a copy at jquery.com.
Building the application
We’ll build our application in three stages: we’ll start with the application descriptor file, construct a HTML framework, and then add behaviour in an external Javascript file.
Creating the application descriptor
Open your text editor and create an application.xml file in the project folder. This will tell AIR how to install and run our application. As usual, we don’t need too much meta data here – just copy in the following:
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/1.0">
<id>com.example.html.richair</id>
<version>1.0</version>
<filename>richair</filename>
<initialWindow>
<title>Rich AIR</title>
<content>richair.html</content>
<visible>true</visible>
<resizable>false</resizable>
<width>640</width>
<height>480</height>
</initialWindow>
</application>
This tells Adobe AIR that we are building an application named “Rich AIR” to be installed in /richair, and the entry point for the application will be the richair.html file. Additionally, the window will start out as 640×480 and be visible. We have a couple of extra properties this time: <title> and <resizable>. The first provides AIR with a general title to use for the application, e.g. when installing and when no title is provided by the HTML. The second tells AIR if it should allow end users to resize the application window: in this case, we’ve told it not to.
We’re only using a small subset of the configuration There are hundreds of options available – check out the samples/descriptor-sample.xml file in your AIR SDK folder for a full example.
Creating the HTML framework
We’re going to be exploring the various AIR APIs, by creating an application that records lists and saves them to the file system. We’ll need a fairly basic HTML structure – create richair.html with your text editor and copy in the following:
<html> <head> <title>Rich AIR: Exploring the AIR APIs</title> <script type="text/javascript" src="AIRAliases.js"></script> <script type="text/javascript" src="jquery-1.2.6.min.js"></script> <script type="text/javascript" src="behaviour.js"></script> </head> <body onload="Run()"> <p>Existing items:</p> <ul id="items"></ul> <p> <button onclick="Save()">Save</button> <button onlick="Quit()">Exit</button> </p> </body> </html>
We reference our copy of jQuery (I’m using the minified and gzipped copy of 1.2.6), as well as “behaviour.js” which will contain our behaviour code. Create this file now, and leave it empty.
Also note we’re referencing AIRAliases.js, a framework included in Adobe AIR to provide easy aliases to common APIs. Most of the APIs are hidden under lengthy structures such as window.runtime.media and similar, and this file will give us abstracted, easy access to these functions. You’ll need to copy this from your AIR SDK directory – it’s under frameworks/ – and place it in your project folder.
Testing our application
It’s time to test that our application is working. We’ll need to run it from a command line using the adl utility we discussed in “Getting Started” above. It needs a single argument, the path to our application.xml file, so let’s switch to our project directory and run it from there.
Load up a command prompt and type the following:
C:\>cd C:\AIR\richair C:\AIR\richair>C:\AIRSDK\bin\adl.exe application.xml
The application window will appear, with the text “Existing Items” and nothing else. We’re all set – let’s start adding behaviours with the APIs.
Adding menus
Load up behaviour.js in your text editor and add the following:
function addItem(event) { alert('clicked'); }
function Run() {
nativeWindow.menu = new air.NativeMenu();
fileMenu = nativeWindow.menu.addItem(new air.NativeMenuItem("Actions"));
fileMenu.submenu = new air.NativeMenu();
btnItem = fileMenu.submenu.addItem(new air.NativeMenuItem("New Item"));
btnItem.addEventListener(air.Event.SELECT, addItem);
}
Remember we called the Run() function in our onload event back in our HTML? This will launch the function defined here, which for now simply creates our menu system. The AIR menu model is quite simple; windows or applications have menus, depending on whether the target platform is Windows or OS X.
The window menu is actually the menu bar, on which you place a menu as the submenu property, and items here are placed into the submenu of the menu itself. Each item, whether it’s a menu title or an option within a menu, is a NativeMenuItem, while the container for items is a NativeMenu. Be aware that on OS X an application menu is already present, and this poses certain other challenges. The manual has an excellent platform sniffing workaround sample.
Linux would function similarly to Windows; AIR is quite effective in this regard, as we don’t really have to worry at this stage, and when AIR for Linux is out of beta our applications will still run fine.
Working with the clipboard
We then need to allow the user to add an item. Remember that addItem()function we used earlier? It will show a prompt for the text of the item, but first we’ll check the clipboard to see if the user has copied text that they want to use.
AIR provides a simple API to access the OS clipboard, but we have to remember that not all content on the clipboard is plain text; for example, the current clipboard item could contain images, one or more files, or maybe even rich HTML text. For now, we’ll just look for plain text.
Head back to behaviour.js and update our addItem function with this code:
function addItem(event) {
var defaultText = "";
if(air.Clipboard.generalClipboard.hasFormat(air.ClipboardFormats.TEXT_FORMAT)) {
defaultText = air.Clipboard.generalClipboard.getData(air.ClipboardFormats.TEXT_FORMAT);
}
itemText = prompt("Enter item text:", defaultText);
newItem(itemText);
}
This will check if any “text” is stored on the clipboard, and if so create a copy before passing on to prompt(). We then hand over to the newItem() function, which we should define now:
items = new Array();
function newItem(text) {
if (text) {
items.push(text);
$("<li></li>").html(text).appendTo("#items");
}
}
Now when we enter a new item, we will store the item text in our items stack, as well as add a new entry to the <ul> on the page.
Saving our list
Once we’ve worked out our list of items, we’ll want to save it somewhere. Let’s provide a simple save mechanism to store the data on the filesystem, inside the user’s home directory. Add this to the end of your behaviour.js:
function Save() {
var data = "";
for (i=0;i<items.length;i++) {
data += items[i] + "\n";
}
var target = air.File.documentsDirectory.resolvePath("airitems.txt");
if (target.exists) {
alert("File exists!");
return;
}
var fileStream = new air.FileStream();
fileStream.open(target, air.FileMode.WRITE);
fileStream.writeMultiByte(data, air.File.systemCharset);
fileStream.close();
while(items.pop());
$("#items").empty();
}
This will save each item, one per line, to a file called “airitems.txt” in our documents directory. If the file exists, it will alert us first, to avoid overwriting any critical data. Notice we use a file stream here – we can keep pushing data to the file, e.g. when streaming the data over a network. The AIR manual has further information on file workflow.
Exiting
Finally, we need a way for the user to quickly exit. Our exit button already calls the Exit() function, so we simply have to define it in behaviour.js.
AIR provides a sophisticated event framework for everything from opening a file to terminating the application. Part of events, however, is checking if we need to stop an event, and terminating the application is a good example. What if we are in the middle of an important operation? Thankfully, AIR provides a simple framework to prevent actions, and check if actions are prevented. Copy this into the end of behaviour.js:
function Quit() {
var event = new air.Event(air.Event.EXITING, false, true);
air.NativeApplication.nativeApplication.dispatchEvent(event);
if (!event.isDefaultPrevented()) {
air.NativeApplication.nativeApplication.exit();
}
}
This way, if any part of your application (or of the AIR runtime) needs to prevent your app from exiting, the exit button is effectively disabled for as long as needed.
Wrapping up
Here’s our completed behaviour.js:
function addItem(event) {
var defaultText = "";
if(air.Clipboard.generalClipboard.hasFormat(air.ClipboardFormats.TEXT_FORMAT)) {
defaultText = air.Clipboard.generalClipboard.getData(air.ClipboardFormats.TEXT_FORMAT);
}
itemText = prompt("Enter item text:", defaultText);
newItem(itemText);
}
items = new Array();
function newItem(text) {
if (text) {
items.push(text);
$("<li></li>").html(text).appendTo("#items");
}
}
function Run() {
nativeWindow.menu = new air.NativeMenu();
fileMenu = nativeWindow.menu.addItem(new air.NativeMenuItem("Actions"));
fileMenu.submenu = new air.NativeMenu();
btnItem = fileMenu.submenu.addItem(new air.NativeMenuItem("New Item"));
btnItem.addEventListener(air.Event.SELECT, addItem);
}
function Save() {
var data = "";
for (i=0;i<items.length;i++) {
data += items[i] + "\r\n";
}
var target = air.File.documentsDirectory.resolvePath("airitems.txt");
if (target.exists) {
alert("File exists!");
return;
}
var fileStream = new air.FileStream();
fileStream.open(target, air.FileMode.WRITE);
fileStream.writeMultiByte(data, air.File.systemCharset);
fileStream.close();
while(items.pop());
$("#items").empty();
}
function Quit() {
var event = new air.Event(air.Event.EXITING, false, true);
air.NativeApplication.nativeApplication.dispatchEvent(event);
if (!event.isDefaultPrevented()) {
air.NativeApplication.nativeApplication.exit();
}
}
Finalising, further reading
And we’re done! We can run the completed application at command line again:
C:\>cd C:\AIR\richair C:\AIR\richair>C:\AIRSDK\bin\adl.exe application.xml
To explore further, the online documentation for AIR has a number of resources you might find handy:
- Working with native menus
- Working with the file system
- Copy and paste
- Application launching and exit options
In the next Adobe AIR Tutorial we are going to look at how to create a Personal Information Management application with AIR, SQLite and Jquery.
3 comments November 10, 2008
Beginners Adobe Air Tutorial – part 1
Getting Started with Adobe AIR
Adobe AIR is a Flash-style runtime for web technologies. It bridges the gap between desktop applications and web applications, enabling developers to work with HTML and JavaScript while still performing common desktop tasks such as clipboard manipulation and native menus. In this tutorial, we’re going to take a first look at building an application with Adobe AIR.
Introducing Adobe AIR
AIR application files are essentially “static” web application files packaged up for distribution. An end user installs the AIR runtime, just like the Flash runtime, and can then open up .air files containing HTML pages, CSS sheets and other resources. However, AIR applications are effectively “installed” to the end user’s computer – Adobe AIR provides a standard installation dialog, and HTML resources inside an .air application file are then extracted to a folder on the user’s computer (e.g. %PROGRAMFILES%\MyAIRApp under Windows).
As developers, we then build web application using JavaScript on steroids – AIR runs a Webkit-based browser with excellent support for XHTML, CSS and JavaScript, and provides various operating system APIs through JavaScript. For example, AIR developers can use JavaScript to create native menus and system tray / dock icons.
Setting up the SDK
To build applications with AIR, we’ll need to install the AIR software development kit, or SDK. This includes the tools we need to test and compile our applications, so that we can distribute them to our users as single .air files. The installer is available for Windows and OS X, and Adobe Labs is working on a Linux version currently in alpha. Head over to the download page to grab a copy, and install it somewhere handy; instructions are available on the AIR docs page.
We’ll need to jump to the command line to run some of the tools in the SDK. For this tutorial, we’ll assume your development machine runs Windows and the AIR SDK has been extracted to C:\AIRSDK, such that C:\AIRSDK\bin exists.
Building your first Adobe AIR application
Once we’ve installed the SDK, we’re all set to build our first AIR application. Here, we’ll build our application with a single HTML file, as well as an XML file called the application descriptor. This descriptor file, typically stored as application.xml in the main directory of the AIR app, is sort of the front line for the program and includes some meta data – in particular, the origin of the program, and how to open it.
We’re going to build a simple script to demonstrate the power of AIR. While we use all our standard web development tools – HTML, CSS, JavaScript and the like – AIR has in particular lifted various security restrictions (albeit introduced a few others) to suit the context. While retrieving content from other pages with AJAX isn’t normally possible on the web, any existing code will pull it off just fine in AIR, and we’re about to see how.
The application descriptor file
Let’s start by building the descriptor file. Open your favourite text editor and bash out the following:
<?xml version=”1.0″ encoding=”UTF-8″?>
<application xmlns=”http://ns.adobe.com/air/application/1.0″>
<id>com.example.html.xdomainxhr</id>
<version>1.0</version>
<filename>xdomainxhr</filename>
<initialWindow>
<content>xdomainxhr.html</content>
<visible>true</visible>
<width>640</width>
<height>480</height>
</initialWindow>
</application>
There are all sorts of other options we could include, such as install directories, icon files, and even file type associations – check out the manual page for more info. Here, we’ve just defined the basic properties of our application, including a (generally) unique ID, and some info on what page to open in the AIR browser to start the application. When we refer to xdomainxhr.html, AIR will launch this app at this HTML page on starting, inside a 640×480 window with minimal chrome.
Create a new folder for your application – mine’s at C:\AIR\xdomainxhr – and save this XML as application.xml within that folder.
The application HTML/JS
Now we get to create our actual HTML file. Head back to your text editor and create a new file, the xdomainxhr.html we referenced earlier. Then copy this out:
<html>
<head>
<title>Cross-domain XHR Sample</title>
<script type=”text/javascript”>
function xhr_run() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
alert(‘Cross-domain XHR complete!\n’ +
‘responseText: \n’ +
xhr.responseText.substring(0,199));
}
};
xhr.open(‘GET’, ‘http://www.example.com/’, true);
xhr.send(null);
}
</script>
</head>
<body>
<button onclick=”xhr_run()”>Start Request</button>
</body>
</html>
First, we have a standard HTML file. Running in the right conditions, this code would function just fine inside a web browser being served over the internet. However, it would need to be served from example.com, and since this is reserved (and not under our control!), this isn’t an option. Workarounds are available, but AIR allows us to simply execute as normal. Let’s have a look by running our application.
Running our AIR application
To test this app, we’ll need to jump to command line and use one of the utilities included in the SDK. The ADL binary represents the AIR debug launcher, enabling us to test our applications without actually installing them. The ADT script, on the other hand, is the AIR developer tool, and provides a number of handy functions from signing applications to actually packaging them for distribution. We’ll use ADL today.
Bring up a command line (Windows – Start > Run, ‘cmd’, Enter) and navigate to the folder with your application.xml and xdomainxhr.html files, then run the application descriptor through ADL within the bin directory of your AIR SDK. Here’s the commands under a DOS prompt:
C:\>cd C:\AIR\xdomainxhr
C:\AIR\xdomainxhr>C:\AIRSDK\bin\adl application.xml
Sure enough, running these produces the application window. When we click on the button inside, the AJAX request is dispatched, and upon completion will produce our alert window. Here’s how it looks on my machine:

Notice the window looks just like a typical application, blending in to the operating system chrome. Of course, within the application the default white background is quite apparent. Remember that this mini window is actually a complete Webkit-based browser with some handy extensions, which we’ll explore in a later article.
We used the standard AIR SDK to test run our application here. However, the SDK is already available within two excellent IDEs that you may be familiar with: Aptana and Dreamweaver CS3 both have AIR plugins that automate many development tasks, such as toolbar / keyboard shortcuts for running applications. Both even have interfaces for dealing with application descriptor files, which can get quite lengthy and complex in production. Have a look at the Adobe AIR Tools page and Aptana’s AIR guide for more details.
Further Reading
Now that we’ve built a simple AIR application, it’s easy to explore the AIR runtime features. You might find these useful:
Developing on Adobe AIR with Aptana Studio
Finally, the various quirks of programming with HTML and JavaScript within the AIR runtime are covered in a seperate section on the developers guide.
2 comments October 23, 2008
