Game Developer

Using the iPad retina display with Adobe Air

Posted on

Last Friday, the new iPad was launched by Apple, with its new retina display. I did a few tests to try to use the high-resolution retina screen at its maximum resolution from Adobe Air. Here are the results.

The simple option doesn't work

The first thing to note is that Apple deliberately limited the new retina resolution to Apps built with the iOS 5.1 SDK. This is to avoid incompatibility issues with Apps that were released before the new iPad was available. So apps built with earlier versions of the iOS SDK use pixel doubling and have an effective resolution of 1024x768 pixels, like the iPad 2.

By default, Adobe Air compiles with iOS 4.0. I don't know what's special about iOS 4.0 that Adobe can distribute this version with Air but not later versions, but that's the way it is. So, if you compile your Air app the normal way, you will not get retina resolution on the new iPad. Everything will still work fine, but it will use pixel doubling to get the same results as on the iPad 2.

Compiling with iOS 5.1

If you have a Mac, there is a solution. Adobe Air (since Air 3.1) includes a build setting to specify the version of the iOS SDK to use. The setting is the platformsdk and you can read more about it on this Adobe blog. If you read through the comments in that post you'll see that this is only supported when compiling on OSX, at the moment, but Adobe hope to bring it to Windows sometime in the future.

So, if you have a Mac, download and install XCode. In the new XCode, the SDK is inside the application package - the filepath is /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/. Now use the playformsdk setting to build against iOS 5.1.

The test

To test this I built a little app, with just a few lines of code -

package com.sticksports.test
{
  import flash.display.Sprite;
  import flash.display.StageAlign;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.system.Capabilities;
  import flash.text.TextField;

  public class RetinaTest extends Sprite
  {
    public function RetinaTest()
    {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
      addEventListener( Event.ENTER_FRAME, getStats );
    }
    
    private function getStats( event : Event ) : void
    {
      removeEventListener( Event.ENTER_FRAME, getStats );
      
      var textField : TextField = new TextField();
      textField.width = stage.stageWidth - 40;
      textField.height = stage.stageHeight - 40;
      textField.x = 20;
      textField.y = 20;
      textField.border = true;
      textField.multiline = true;
      addChild( textField );
      
      textField.appendText( "Capabilities.screenResolutionX : " + Capabilities.screenResolutionX + "\n" );
      textField.appendText( "Capabilities.screenResolutionY : " + Capabilities.screenResolutionY + "\n" );
      textField.appendText( "Capabilities.screenDPI : " + Capabilities.screenDPI + "\n" );
      textField.appendText( "stage.stageWidth : " + stage.stageWidth + "\n" );
      textField.appendText( "stage.stageHeight : " + stage.stageHeight + "\n" );
      textField.appendText( "stage.fullScreenWidth : " + stage.fullScreenWidth + "\n" );
      textField.appendText( "stage.fullScreenHeight : " + stage.fullScreenHeight + "\n" );    }
  }
}

I didn't use Flash Builder for my tests because I'm an FDT user, so the apps were built from Ant scripts. First I built the swf in the standard way.

<exec executable="${sdk.home}/bin/amxmlc" failonerror="true" dir="../package">
  <arg line='-source-path ../src'/>
  <arg line='-default-size=960,640'/>
  <arg line='-default-background-color 0xFFFFFF'/>
  <arg line='-default-frame-rate 60'/>
  <arg line='-debug=false'/>
  <arg line='-optimize=true'/>
  <arg line='-swf-version=13'/>
  <arg line='-output RetinaTest.swf'/>
  <arg line='../src/com/sticksports/test/RetinaTest.as'/>
</exec>

I gave the swf a default size to match the iPhone, just to see what Air gave me as the stage size as a result.

The application descriptor file requests the high resolution display, as for the iPhone retina screen.

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<application xmlns="http://ns.adobe.com/air/application/3.0">

  <id>com.sticksports.RetinaTest</id>
  <filename>RetinaTest</filename>
  <name>Retina Test</name>
  <versionNumber>0.0.1</versionNumber>
  <versionLabel>v0.0.1</versionLabel>
  <copyright>Stick Sports Ltd.</copyright>

  <initialWindow>
    <content>RetinaTest.swf</content>
    <aspectRatio>portrait</aspectRatio>
    <autoOrients>true</autoOrients>
    <fullScreen>true</fullScreen>
    <renderMode>cpu</renderMode>
    <softKeyboardBehavior>none</softKeyboardBehavior>
    </initialWindow>

  <icon>
    <image29x29>icons/icon_29.png</image29x29>
    <image57x57>icons/icon_57.png</image57x57> 
    <image72x72>icons/icon_72.png</image72x72> 
    <image114x114>icons/icon_114.png</image114x114> 
  </icon>
  
  <iPhone>
    <InfoAdditions>
      <![CDATA[
        <key>UIDeviceFamily</key>
        <array>
          <string>1</string>
          <string>2</string>
        </array>
        <key>UIStatusBarStyle</key>
        <string>UIStatusBarStyleBlackOpaque</string>
      ]]>
    </InfoAdditions>
    <requestedDisplayResolution>high</requestedDisplayResolution>
  </iPhone>

</application>

I built the ipa twice, using the Air 3.2 release candidate from Adobe Labs. I built it once using the default version of the iPhone SDK (version 4.0) that is bundled with Air.

<exec executable="${sdk.home}/bin/adt" failonerror="true" dir="../package">
  <arg value="-package"/>
  <arg value="-target"/>
  <arg value="ipa-ad-hoc"/>
  <arg value="-provisioning-profile"/>
  <arg value="${ios.provisioning.profile}"/>
  <arg value="-storetype"/>
  <arg value="pkcs12"/>
  <arg value="-keystore"/>
  <arg value="${ios.keystore.file}"/>
  <arg value="-storepass"/>
  <arg value="${ios.keystore.password}"/>
  <arg value="../publish/default/RetinaTest.ipa"/>
  <arg value="../build/RetinaTest-app.xml"/>
  <arg value="RetinaTest.swf"/>
  <arg value="Default.png"/>
  <arg value="icons"/>
</exec>

And once with the iOS 5.1 SDK

<exec executable="${sdk.home}/bin/adt" failonerror="true" dir="../package">
  <arg value="-package"/>
  <arg value="-target"/>
  <arg value="ipa-ad-hoc"/>
  <arg value="-provisioning-profile"/>
  <arg value="${ios.provisioning.profile}"/>
  <arg value="-storetype"/>
  <arg value="pkcs12"/>
  <arg value="-keystore"/>
  <arg value="${ios.keystore.file}"/>
  <arg value="-storepass"/>
  <arg value="${ios.keystore.password}"/>
  <arg value="../publish/5.1/RetinaTest.ipa"/>
  <arg value="../build/RetinaTest-app.xml"/>
  <arg value="RetinaTest.swf"/>
  <arg value="Default.png"/>
  <arg value="icons"/>
  <arg line="-platformsdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/"/>
</exec>

The equivalent command-line script is

adt -package -target ipa-ad-hoc -provisioning-profile YOUR_PROVISIONING_PROFILE -storetype pkcs12 -keystore YOUR_KEYSTORE_FILE -storepass YOUR_KEYSTORE_PASSWORD RetinaTest.ipa RetinaTest-app.xml RetinaTest.swf Default.png icons -platformsdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/

The results

With the default SDK the results are

Capabilities.screenResolutionX : 768
Capabilities.screenResolutionY : 1024
Capabilities.screenDPI : 132
stage.stageWidth : 960
stage.stageHeight : 640
stage.fullScreenWidth : 768
stage.fullScreenHeight : 1024

I was surprised the stageWidth and stageHeight don't match the screenResolutionX and screenResolutionY, which is why I use the latter in my projects. As Florian mentioned in the comments, you can also use fullScreenWidth and fullScreenHeight, which I added after reading his comment. Aside from that, there's no surprises here. The results are the same as on the iPad2.

With iOS 5.1 SDK, the results are

Capabilities.screenResolutionX : 1536
Capabilities.screenResolutionY : 2048
Capabilities.screenDPI : 132
stage.stageWidth : 1536
stage.stageHeight : 2048
stage.fullScreenWidth : 1536
stage.fullScreenHeight : 2048

This version uses the full resolution of the retina screen. The text is half the size on screen because the pixel resolution is doubled and the screenResolutionX and screenResolutionY and fullScreenWidth and fullScreenHeight are the correct size for the retina display. This time, surprisingly, the stageWidth and stageHeight did match the screen resolution - all the more reason not to trust them. Also, the screenDPI is incorrect, showing the same value as the iPad 2.

But, most importantly, the project has access to the full retina screen resolution. Hurrah!

Building with Air 3.1

As I said above, I initially used the public beta of Air 3.2 for this test. I reran the test using Air 3.1 and the results were the same, except building with Air 3.1 and iOS 5.1 gave the stageWidth as 1920px and stageHeight as 1280px. All other results were the same as for Air 3.2.

Share this post or a comment online -


Also in the collection Adobe Air