I show a lot of demos on mobile devices. One of the best ways I have been able to demo applications at conferences with out having great wifi or device overhead projectors is to use a local network from my MacBook Pro. I use this for my P2P local multicast demos like PickQuick as well as other laptop to mobile interactions.
Here are the steps I use to make this work:
- Unplug laptop from any wired networks.
- Open up System Preferences -> Sharing and select Internet Sharing

- Select “FireWire” in the “Share your connection from:” combo box
- Check the “AirPort” checkbox in the “To computers using:” list.
- Click on AirPort Options…
- Configure the “Network Name” (basically the SSID) and WEP settings, this is the important step for using non-Apple devices with this setup. See the image below:

AirPort Options Notice Fine Print for non-Apple devices
- I use the 40-bit WEP key and a 5 character password to allow for non-Apple devices as mentioned in the fine print.
- Click OK in the AirPort Options dialog
- Now check the “Internet Sharing” checkbox on the left to turn on Internet Sharing
- Verify you have a shared wireless network by looking at the AirPort icon and checking out your IP with terminal and ifconfig.

Internet Sharing over AirPort
Thats it, now when you connect your devices use the AirPort Option’s Network Name and 5 character password you setup above. This setup works great for P2P local multicast demos like PickQuick, and if you want to try it out go grab PickQuick’s source here.
AIR 2.6 provides updates to the old Packager for iPhone (PFI). The packager binary is now part of the normal AIR packaged called adt. The new adt options are just like the old pfi packager options, see below:
adt -package -target ( ipa-test | ipa-debug | ipa-app-store | ipa-ad-hoc )
CONNECT_OPTIONS? SIGNING_OPTIONS <output-package> ( FILE_OPTIONS | <input-package> )
Screen Resolution and Pixels Per Inch (ppi)
When developing you applications for retina and non-retina iOS screens, for example a iPhone 3GS and a iPhone 4G, you need to take in account the large differences in resolutions. The retina enabled devices have have a 960×640 resolution 3.5in physical screen which comes out to 324ppi . For the non-retina displays the screen is a 480×320 resolution 3.5in physical screen which comes out to 162ppi. AIR 2.6 allows for developers to set a mode in the application descriptor file which allows application to use the retina display if present on the device. This means an application needs to be able to render to both retina and non-retina displays. How do we do this?
View the whole post »
A question came up from a developer that was creating a Flex Hero (the 4+ Flex SDK geared towards mobile) mobile application about tapping into the PlayBook's bezel swipe down event, but also be able to use the SWF on other platforms. PlayBook is a great platform that QNX, a subsidary of RIM, has created PlayBook specific AIR apis and classes.
One of the PlayBook specific API's is the ability to tap into the bezel event when the user swipes from the top bezel into the tablet screen. As a developer you catch this specific PlayBook event with the following code:
ACTIONSCRIPT:
QNXApplication.qnxApplication.addEventListener(QNXApplicationEvent.SWIPE_DOWN, myFunction);
The problem on non-PlayBook platforms is they do not implement the classes that talk from QNXApplication to the OS to handle this PlayBook specific event. If you run this code on a non-PlayBook platform you will have a VerifyError that talks about not implementing qnx.pps.PPSChannel, i have a blog post about how to workaround this for UI testing while on the desktop.
In the use case of this blog post we actually want the functionality of handling the swipe down event to work on the PlayBook and then not throw a runtime VerifyError on non-PlayBook platforms, basically one SWF that will work across platforms.
Using QNX UI components in a Flex application requires some specialized classes, read more on that topic here. The QNXApplication class and listening for the swipe down event is not trying to mix UI components but just listening for an event. This becomes much easier to integrate this functionality into the Flex application. The example below is in ActionScript but you can just put this in the respective script area of your Flex application.
ACTIONSCRIPT:
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.utils.getDefinitionByName;
import qnx.system.QNXApplication;
public class TestCC extends Sprite
{
public function TestCC()
{
super();
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
try
{
var c:Class = flash.utils.getDefinitionByName("qnx.system.QNXApplication") as Class;
var q:QNXApplication;
c.qnxApplication.addEventListener("swipeDown", swipeDown);
}
catch(error:Error)
{
graphics.beginFill(0xFF3333, 1);
graphics.drawRect(50, 50, 200, 200);
graphics.endFill();
}
}
protected function swipeDown(event:Event):void
{
graphics.beginFill(0x3333FF, 1);
graphics.drawRect(50, 50, 200, 200);
graphics.endFill();
}
}
}
What the code is doing is checking if the QNXApplication class is available and then if it is not available goes to the catch code block and does not try and call QNXApplication.qnxApplication singleton, which throws the VerifyError. You will notice the instance declaration, but no instantiation, of var q:QNXApplication;, this is needed to make sure a class reference is compiled into the SWF to test for at runtime. When PlayBook is present the class comes back fine because the qnx-air.swc (extended AIR apis) is present, but on non-PlayBook platforms the classes in qnx-air.swc that QNXApplication (which we compiled into the SWF) are not present so it throws an error on the getDefinitionByName() call.
Give it a try and let me know if it works for you.
The other option is to use conditional compile config statements. Some people don't prefer this way because it complicates building different SWFs for each platform, but its a very viable option.
I had previously posted on the subtleties of screen PPI on devices here. Since then the AIR runtime is making changes to help where the OS provides the wrong PPI. Its not perfect but its a work in progress, which means if you have devices and wrong PPI's please let us know.
| Device |
Capabilities.screenDPI |
Capabilities.serverString's &DP |
Actual PPI |
Android Nexus 1 (OS 2.3.3) |
254 |
254 |
254 |
| Droid Incredible |
254 |
254 |
254 |
Droid X (OS 2.2.1) |
221 (old 240) |
221 (old 144) |
228 |
Droid 2 (OS 2.2) |
221 (old 240) |
144 |
265 |
Samsung Galaxy Tab (OS 2.2) |
168 (old 240) |
168 |
168 |
| iPhone 3GS |
163 |
72 |
163 |
| iPad |
132 |
72 |
132 |
NOTE: For iOS devices the latest Packager for iPhone is not available so they have not been updated. The rest use the latest AIR 2.6 release.
Here is the Flex blank mobile application code that I am using to test for the values:
XML:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
applicationComplete="getDPI()"
width="100%" height="100%">
<s:layout>
<s:VerticalLayout />
</s:layout>
<fx:Script>
<![CDATA[
protected function getDPI():void
{
lblDPI.text = "screenDPI = " + Capabilities.screenDPI;
var value:String = unescape(Capabilities.serverString);
lblServerStringDP.text = "serverStringDP = " + value.split("&DP=", 2)[1];
}
]]>
</fx:Script>
<s:Label id="lblDPI" width="100%" />
<s:Label id="lblServerStringDP" width="100%" />
</s:Application>
So this is a little tip that has been coming up more and more often because of the need to export applications to the various package types (.bar, .apk, .ipa) and tooling not quite being there (or plugin support out of sync etc...).
The proper way to create a non-debug version of a specific package is to use the Flash Builder's Export dialog. For example you will need to create a release version (non-debug) of your application to submit an PlayBook application (.bar) to BlackBerry's AppWorld. With the Plugin install in Flash Builder Burrito you would right click on your project and select the Export..., then follow the dialog UI to create the .bar file.
For various reasons, you might be using other methods of packaging your applications or trying to package SWFs not supported in the tooling workflows at the current time, but still need a release version of the SWF. The easiest way to do this in Flash Builder regardless of AIR or web project, or if the Export is available or not is to add an argument to the compiler options. To do this go to: Project -> Properties -> Flex Compiler and then in the "Additional compiler arguments" add "-debug=false". The figure below shows what I am talking about:

setting SWF to non-debug
And for another option (thanks to Josh Tynjala):
If you still want to be able to use the bin-debug SWF for debugging on the desktop, there’s another way too. Export a release build of the AIR package, but at the step where it asks you for your signing key, just cancel. You’ll be able to grab your unpackaged SWF out of the bin-release folder.
I recently participated in the BlackBerry Developer Day co-presenting the BlackBerry PlayBook Tablet Bootcamp: Adobe AIR sessions. We led developers through the process of installing all the tools (Flash Builder Burrito, VMWare, BlackBerry Tablet OS SDK and Simulator) and getting up and running to build their first application. As part of this presentation I wanted to build a more in depth application then the basic hello world app. Also wanted to show some of the optimizations with QNX components around Lists, image caching with ImageCache, QNXApplication SWIPE_DOWN, and object pooling. To that end here is a screen shot of the application called DataExampleApp:

MWC BlackBerry Developer Day AIR PlayBook example app
The full source code for this application is located on my github here.
First thing is to note this is a workaround and might not work in the future or might not cover all the errors you might see. Take the simple use case of creating an AIR application for PlayBook and with a qnx.ui.text.TextInput component in the display list. Because the qnx.ui.text.TextInput class allows you to define which PlayBook KeyboardType is shown on the device it must call out to a PlayBook specific AIR API. If you try and run this application on the desktop you will see this error:

qnx.pps.PPSChannel Error Message
This error is because the AIR runtime on the desktop does not have a qnx.pps.PPSChannel class, this class is specific to the PlayBook version of the AIR runtime that RIM has extended in their BlackBerry Tablet OS.
Ok, so what if you still want to run it on the desktop to work on UI layout an not necessarily full functionality?
View the whole post »
I continue to play with different ideas around using QNX (ActionScript 3 only classes) with MXML (non-Flex MXML) in a project called QMXML. My co-worker, Piotr Walczyszyn, at Adobe posted some classes to that provide view based navigation in ActionScript 3. I decided to extend his classes and make them work with QMXML. The source code for the examples below is on https://github.com/renaun/QNXUIExamples/ViewNavigator.
View based navigation allows you to push new views on to a stack and then navigate the views by popping or pushing views on or off. Also allows for navigating directly back to the first view. Its a lot like breadcrumbs. In the case of QMXML I create 2 new classes, QView that extends QContainer but implements IView. I decided on another class so if you don't want to do view based navigation you can just use QContainer as is. The IView interface provides QView with the navigator property that you can use inside that view to pop or push views. The QViewNavigator extends Piotr's original ViewNavigator but provides some extra properties to easily set the application (DisplayObject that will have a reference to stage) and the firstView in MXML. Continue below to see it in action in the video and some of the code.
View the whole post »
I wanted to show how to use another QNX AIR API, specifically the class AudioManager. It provides a singleton instance of the AudioManager which gives access to the available inputs and outputs on the device. You can then set the levels and mute state of both input and output. In the example code project QNXAudioManager it plays a local mp3 that is bundled with the application. It also displays the different event messages that are fired while making changes to the input or output. And it provides a QNX VolumeSlider to set the output level while playing the mp3.
Here is the main chunk of code that setups and uses the singleton instance of AudioManager.
ACTIONSCRIPT:
audioManager = AudioManager.audioManager;
log("AvailableInputs: " + audioManager.availableInputs.length);
for (var i:int = 0; i <audioManager.availableInputs.length; i++)
{
log(i + " - " + audioManager.availableInputs[i]);
}
log("AvailableOutputs: " + audioManager.availableOutputs.length);
for (var j:int = 0; j <audioManager.availableOutputs.length; j++)
{
log(j + " - " + audioManager.availableOutputs[j]);
}
audioManager.addEventListener(AudioManagerEvent.AVAILABLE_INPUTS_CHANGED, eventHandler);
audioManager.addEventListener(AudioManagerEvent.AVAILABLE_OUTPUTS_CHANGED, eventHandler);
audioManager.addEventListener(AudioManagerEvent.CONNECTED_INPUT_CHANGED, eventHandler);
audioManager.addEventListener(AudioManagerEvent.CONNECTED_OUTPUT_CHANGED, eventHandler);
audioManager.addEventListener(AudioManagerEvent.INPUT_LEVEL_CHANGED, eventHandler);
audioManager.addEventListener(AudioManagerEvent.INPUT_MUTE_CHANGED, eventHandler);
audioManager.addEventListener(AudioManagerEvent.OUTPUT_LEVEL_CHANGED, eventHandler);
audioManager.addEventListener(AudioManagerEvent.OUTPUT_MUTE_CHANGED, eventHandler);
log("connectedInput: " + audioManager.connectedInput);
log("connectedInput: " + audioManager.connectedOutput);
audioManager.setInputMute(true);
audioManager.setInputMute(false);
There is only seems to be one input for the PlayBook; found at qnx.system.AudioInput.INPUT. But there are four different audio output types: qnx.system.AudioOutput.BLUETOOTH, qnx.system.AudioOutput.HDMI, qnx.system.AudioOutput.HEADPHONES, and qnx.system.AudioOutput.SPEAKERS. You can check the audioManager.connectedInput and audioManager.connectedOutput values against the constants above.
Then the slider changes the output level on slider_move event:
ACTIONSCRIPT:
protected function slider_slider_moveHandler(event:SliderEvent):void
{
audioManager.setOutputLevel(event.value);
}
Here is what the app looks like on the simulator, nothing fancy but a way to check out the event firing off the AudioManager instance.

QNX AudioManager Example App
All the source code for this example is on github here.
UPDATE: RIM has provide documentation on the blackberry-tablet.xml located here.
With the release of the BlackBerry Tablet OS SDK for Adobe AIR Beta 3 (0.9.2) developers have access to a new PlayBook application descriptor file called "blackberry-tablet.xml". This file has to be named exactly "blackberry-tablet.xml" and be placed in the root of the application structure, basically along side the AIR typical Xxxx-app.xml descriptor file.
I created a simple example application (BlackBerryTabletXMLOptions) that displays a smiley face image to the screen to talk about a couple of the attributes in the blackberry-tablet.xml file.
Here is what the application looks like:

Smiley Face App
You might be wondering how I got an application to show up over the main interface of the PlayBook. Well lets take a look at the blackberry-tablet.xml:
XML:
<qnx>
<initialWindow>
<systemChrome>none</systemChrome>
<transparent>true</transparent>
</initialWindow>
<publisher>Renaun Erickson</publisher>
<category>core.media</category>
<icon>
<image>renaun-icon.png</image>
</icon>
<splashscreen>renaun_com_splash.png</splashscreen>
</qnx>
What makes this work is the "transparent" attribute set to true. This allows your application to render transparently over the main interface of the playbook. The other attributes in the xml file to call out are "category", "icon.image", and "splashscreen". First the category allows you to set the values: core.media, core.internet, core.games, and core.utils. This category value is used to place the application and its custom icon defined in the xml above in the application categories that show up on the main screen of the PlayBook. See below that the BBTabletXMLOptions application is installed in the Media category area.

Application in Media Category
The splashscreen is the last attribute that is in this application. It takes a 1024x600 image that is shown before the application is activated.