You would like to communicate with a server using a protocol that is not directly supported by Adobe AIR (e.g., communicate with an FTP server).
Use the Socket class in the AIR API to send binary or text data to the server and register for events that will alert you to incoming data from the server.
When communicating using protocols other than those directly supported by Adobe AIR, you may need to use the Socket API. The Socket API is an asynchronous API that lets you send data to a persistent socket endpoint and receive data from it in real time. You do not need to create a new Socket instance for each set of data sent to the same endpoint. The connection can be kept alive for the entire conversation between your client and the service to which you're connecting. This is the typical flow when using the Socket API:
Create a connection to the endpoint.
Listen for notification of connection success or failure.
Queue data that will be sent to the endpoint.
Send the data to the endpoint.
Listen for data incoming from the endpoint.
Repeat steps 3 through 5.
Close the connection.
The first step is to create a connection to the socket endpoint that consists of a host and a port number. For example, to connect to an endpoint the host might be foo.com and the port number might be 5555. Create the instance of the Socket class and connect to the endpoint using that information. At this time, we will also set up our listeners to listen for the different events that the Socket can dispatch:
var socket = new air.Socket(); socket.addEventListener( air.Event.CONNECT, onSocketOpen ); socket.addEventListener( air.ProgressEvent.SOCKET_DATA, onSocketData ); socket.connect( 'foo.com', 5555 );
We will also need to create the functions to handle the events for which we subscribed. The first event is the air.Event.CONNECT event. This event will tell us when the socket has been initiated and when communication with the service behind the endpoint is possible. In this example, we are sending the bytes of a UTF-8 encoded string to the service:
function onSocketOpen( event )
{
// This queues up the binary representation of the
// string 'Bob' in UTF-8 format to be sent to the
// endpoint.
socket.writeUTFBytes( "Bob" );
// Send the actual bytes to the server and clear
// the stream. We then wait for data to be sent
// back to us.
socket.flush();
}
The air.ProgressEvent.SOCKET_DATA event is dispatched whenever data is received. The service we are connecting to uses a simple protocol: we send a UTF-8 encoded string and it returns a UTF-8 encoded string. This makes accessing the data sent back to us very simple. To access this data, we measure the total number of bytes of data available on the Socket and read that many bytes as a UTF-8 encoded string using the readUTFBytes() method of the Socket class.
function onSocketData( event )
{
var data =
socket.readUTFBytes( socket.bytesAvailable );
air.trace( data ); // Hello Bob
}
In our example, the protocol of communication was just a single string. In some cases, depending on the service with which you're communicating, you may need to send and receive other data types. The Socket class provides methods for reading and writing many data types, such as ints, Booleans, floats, and more. For example, if we were talking with a fictional service that required us to send a Boolean followed by an int, our onSocketOpen function in the preceding example could look like this:
function onSocketOpen( event )
{
// First send the boolean
socket.writeBoolean( true );
// Now send an int
socket.writeInt( 10 );
// Now we send the bytes to the service and
// clear the buffer.
socket.flush();
}
This example provides a baseline of functionality that can be expanded upon to speak to many different protocols. The only current limitation is that there is not currently an SSL Socket implementation in AIR. For secure communication you will be limited to HTTPS:
<html>
<head>
<title>Communicating on a Socket</title>
<script type="text/javascript" src="airaliases.js">
</script>
<script>
var socket = null;
function init()
{
socket = new air.Socket();
// Create our listeners which tell us when the Socket
// is open and when we receive data from our service.
socket.addEventListener( air.Event.CONNECT,
onSocketOpen );
socket.addEventListener( air.ProgressEvent.SOCKET_DATA,
onSocketData );
// Connect to our service, which is located at
// host foo.com using port 5555.
socket.connect( 'foo.com', 5555 );
}
function onSocketOpen( event )
{
// This queues up the binary representation of the
// string 'Bob' in UTF-8 format to be sent to the
// endpoint.
socket.writeUTFBytes( "Bob" );
// Send the actual bytes to the server and clear
// the stream. We then wait for data to be sent
// back to us.
socket.flush();
}
function onSocketData( event )
{
var data = socket.readUTFBytes( socket.bytesAvailable );
air.trace( data ); // Hello Bob
}
</script>
</head>
<body onload="init()">
</body>
</html>
The application user has created numerous files offline, and you now want to send those to the server without blocking the user from doing any additional work.
The File class in Adobe AIR provides an upload() method that is designed specifically for this purpose, without having to create and manage HTML forms.
The File.upload() method can upload files via HTTP/S to a server for additional processing. The upload takes places just like a traditional multipart file upload from an HTML form, but without the need to manipulate forms on the client. The upload process also takes place asynchronously in the background, allowing the application to continue processing without interruption.
NOTE
The implementation of the receiving server is beyond the scope of this example. Numerous technologies, and tutorials for these technologies, elegantly handle file upload. You're encouraged to investigate your options.
The primary events that are useful are ProgressEvent.PROGRESS and Event.COMPLETE. These events handle notifying the application of upload progress, and when an individual upload is complete, respectively:
var file = new air.File.documentsDirectory. resolvePath( 'myImage.jpg' ); file.addEventListener( air.ProgressEvent.PROGRESS, doProgress ); file.addEventListener( air.Event.COMPLETE, doComplete );
ProgressEvent contains various properties that can help in reflecting upload progress in the user interface. The most notable of these properties are ProgressEvent.bytesLoaded and ProgressEvent.bytesTotal, which show how much of the file has been uploaded and the total size of the file. Event.COMPLETE is broadcast once the upload is complete.
To start the upload, you first need a valid File object that points to a resource on disk.
Once a valid file reference is established, developers will want to call the File.upload() method. The File.upload() method can take three arguments, the first of which is a URLRequest object that contains information about where the file should be sent. The URLRequest object can also contain additional data to be passed to the receiving server. This additional data manifests itself as HTML form fields might during a traditional multipart file upload:
var request = new air.URLRequest( 'http://www.mydomain.com/upload' ); file.upload( request, 'image', false );
The second argument provided to the File.upload() method call is the name of the form field that contains the file data.
The third argument is a Boolean value that tells the upload process whether it should try a test before sending the actual file. The test upload will POST approximately 10 KB of data to the endpoint to see if the endpoint responds. If the service monitoring capabilities of Adobe AIR are not being used, this is a good way to check for potential failure of the process.
NOTE
More than one great web application has been caught by this subtlety. If the server is expecting the file data outright, a test upload will almost assuredly cause an error. If you intend to use the test facility, be sure that your server code is prepared to handle the scenario.
function doProgress( event )
{
var pct = Math.ceil( ( event.bytesLoaded / event.
bytesTotal ) * 100 );
document.getElementById( 'progress' ).innerText =
pct + "%";
}
The Event.COMPLETE event is relatively straightforward in that it signals the completion of the upload process. This is a good place to perform any filesystem maintenance that the application might otherwise need to accomplish. An example would be removing the just-uploaded file from the local disk to free up space. Another task that might be accomplished in the Event.COMPLETE handler is to start the upload of subsequent files:
<html>
<head>
<title>Uploading a File in the Background</title>
<style type="text/css">
body {
font-family: Verdana, Helvetica, Arial, sans-serif;
font-size: 11px;
color: #0B333C;
}
</style>
<script type="text/javascript" src="airaliases.js"></script>
<script type="text/javascript">
var UPLOAD_URL = 'http://www.ketnerlake.com/work/watcher/
upload.cfm';
var file = null;
function doComplete( e )
{
document.getElementById( 'progress' ).style.visibility =
'hidden';
document.getElementById( 'progress' ).innerText =
'Uploading... 0%';
document.getElementById( 'upload' ).disabled = null;
}
function doLoad()
{
file = air.File.desktopDirectory;
file.addEventListener( air.Event.SELECT, doSelect );
file.addEventListener( air.ProgressEvent.
PROGRESS, doProgress );
file.addEventListener( air.Event.
COMPLETE, doComplete );
document.getElementById( 'upload' ).
addEventListener( 'click', doUpload );
}
function doProgress( e )
{
var loaded = e.bytesLoaded;
var total = e.bytesTotal;
var pct = Math.ceil( ( loaded / total ) * 100 );
document.getElementById( 'progress' ).innerText =
'Uploading... ' +
pct.toString() + '%';
}
function doSelect( e )
{
var request = new air.URLRequest( UPLOAD_URL );
request.contentType = 'multipart/form-data';
request.method = air.URLRequestMethod.POST;
document.getElementById( 'upload' ).disabled = 'disabled';
document.getElementById( 'progress' ).style.visibility =
'visible';
file.upload( request, 'image', false );
}
function doUpload()
{
file.browseForOpen( 'Select File' );
}
</script>
</head>
<body onLoad="doLoad();">
<input id="upload" type="button" value="Upload" />
<div id="progress" style="visibility: hidden">Uploading...
0%</div>
</body>
</html>