Tag Archives: AIR

ANE for iOS with Custom Framework – Using Custom Fonts

We’re developing a set of games for iOS, some objective-C and some using Adobe AIR, and we’re using an iOS custom framework to hold a bunch of storyboard-based screens that we want to use across all the apps.

On the AIR side, we’ve created an Adobe Native Extension and figured out how to include our framework in it. This may be a subject for another blog post, because it was quite complicated, but this post really helped us figure out how to get all the images, storyboards, and sound files (among other assets) to get included in the ANE, and thus into the final app. We also used it to include our custom font file that the storyboards made heavy use of.

However, this was not enough. Using this post, I was able to troubleshoot all the possible steps that could go wrong. I had to make sure that the .ttf file got included in the final output of the framework, but the real key was Step 4 – adding the font information to your app’s info.plist file. Since an ANE is NOT an app, these keys need to go in the info.plist of the final app the ANE gets included in. But AIR apps use an Application Descriptor File, not an info.plist file. The info.plist file of the completed .IPA is auto-generated when the app is built.

Not to worry, Adobe has provided a place in said app descriptor file where you can specify items to add to the auto-generated info.plist. Appropriately enough, it’s called the InfoAdditions element. The content of this element must be wrapped in CDATA tags, and anything inside it will be added to the info.plist of the final app. So, in an XCode sample app, I followed step 4 above and created the required key/value in XCode’s graphical plist editor, and then opened the generated file in a text editor and copy/pasted those values. Here’s what I got:

<key>UIAppFonts</key>
<array>
	<string>name-of-your-font.ttf</string>
</array>

And here’s what that looks like pasted into an InfoAdditions tag in the app descriptor:

<iPhone>
	<InfoAdditions><!&#91;CDATA&#91;
		<key>UIAppFonts</key>
		<array>
			<string>name-of-your-font.ttf</string>
		</array>
	&#93;&#93;></InfoAdditions>
</iPhone>

I’ve omitted lots of other things that are in my descriptor for brevity – keys specifying minimum iOS version, custom URL schemes, which devices the app targets – but you get the idea.

Once I had this all put together, it worked like a charm! Our storyboards look great as ever with their custom fonts!

Flash Builder 4.7 hangs loading workbench OSX

Today Flash Builder randomly started hanging while loading the workbench on startup.

I found a lot of places that said to delete the .snap directory located at [workspacelocation]/.metadata/.plugins/org.eclipse.core.resources but there was never a .snap file or folder.

Eventually I found a trick here that said the following:

remove all the <editor> elements in workspace\.metadata\.plugins\org.eclipse.ui.workbench\workbench.xml

I did that and at least got Flash Builder to start up.

You apparently can also delete all the files in the [workspacelocation]/.metadata/.plugins/org.eclipse.ui.workbench as well (this removes your custom window layouts), but I haven’t tried this method.

As a last-ditch effort, you could do one of the following:

  • delete your .metadata folder in your workspace folder. You will have to reimport ALL your projects after doing this.
  • close Flash Builder, rename your workspace folder (defaults to “Adobe Flash Builder 4.7”), and re-open Flash Builder. It will create a new, empty workspace. Then quit flash builder again, delete the empty workspace, and rename your old workspace to its old name. Hopefully when you start Flash Builder again, things will work better.
  • This post has the following workaround (copied here to protect against link-rot). This is for Flash Builder 4.5 but may work for 4.7.
    This happens because the Eclipse workspace gets corrupted. The easiest way I've found to recover from this is as follows:
     
    1. Use Windows Task Manager (Ctrl+Shift+Esc) to make sure FlashBuilder.exe isn't running as a process. End the process if it is.
    2. Navigate to your workspace folder (the default location is under your users folder in "Adobe Flash Builder 4.5", though you may have placed is elsewhere).
    Mine is c:\Users\grayson\Adobe Flash Builder 4.5
    3. There is a folder named .metadata (on Windows 7 there is an issue where it may appear as a nameless folder because Windows started truncating the "extension")
    move it to another location on your hard drive.
    4. Launch Flash Builder to make sure that this it has solved the issue.
    5. Close Flash Builder (this writes the default workspace settings to the .metadata folder in your workspace location)
    Inside the original copy of the .metadata folder you made, COPY the following folders to the same location in the newly created .metadata folder in your workspace folder, overwriting the files and folders that are there.
    .metadata\.plugins\org.eclipse.core.resources\
    .metadata\.plugins\org.eclipse.core.runtime\
    (as I mentioned before, Windows 7 can truncate the folder names to be without the last portion of the name, so you may see two folders that appear to be named "org.eclipse.core.runtime". Copying them will still work)
    6. This will restore the projects, workspace settings, and key bindings. (the dialog/window layout will be reset to the defaults and External Tool Configurations aren't copied. I looked but didn't find where those are stored)

AIR for iOS Runtime Error #1520: Mutex cannot be initialized.

Situation: I’m making an app for iOS and Android using Flash Builder 4.7 and AIR SDK 4.0. It includes the Lua 5.2 interpreter as compiled from C code into a SWC using CrossBridge (formerly FlasCC). I’m just using the lua.swc file from the crossbridge samples. However, apparently there’s some problem with the multithreading code or something (is multithreading even supported in AIR 4.0? I don’t remember), because I get the following run-time error when debugging on the device (not on Android or AIR simulator, just iOS):

Error #1520: Mutex cannot be initialized.

Solution: I don’t know why this works, but if you add the following compiler options:

--swf-version=17

It works. This probably means I’m targeting an older flash player and one day I will need to figure out how to get the Lua interpreter code.

Here’s a pretty picture of the box where you enter the code in Flash Builder 4.7:
version17

Supporting “the other landscape” in AIR for iOS

Most iOS games are either portrait-only or landscape-only. The AIR application descriptor file lets you easily specify this. All you have to do is add the following to your descriptor file, inside the initialWindow tag:

<aspectRatio>landscape</aspectRatio>
<autoOrients>false</autoOrients>

The above configuration will result in a landscape app that will be right-side up when the home button is on the right – known as “landscape right” – that doesn’t rotate to portrait when the device is turned. However, it will ALSO not rotate when the device is turned to “the other landscape orientation” – if you position your iDevice so that the home button is on the left, your app will be upside-down!

To have a truly industry-standard game, you’ll want your portrait games to support both “Default” and “Upside Down”, and your landscape games to support both “Landscape Left” and “Landscape Right”, as Apple calls them:
iphone_orientations

To accomplish this, we need to think about the concept of “stage orientation” as opposed to “device orientation”. Adobe’s StageOrientation class defines four orientations – DEFAULT, ROTATED_LEFT, ROTATED_RIGHT, and UPSIDE_DOWN. These orientations describe the orientation of the Flash stage relative to the physical device. DEFAULT simply means that the stage is oriented to match the physical orientation of the device. ROTATED_RIGHT and ROTATED_LEFT mean the stage is rotated either 90 degrees right or left. UPSIDE_DOWN means the stage is rotated 180 degrees.

For our game to work properly, we want to allow the stage to be in either the DEFAULT or UPSIDE_DOWN orientations, but NOT the ROTATED_LEFT or ROTATED_RIGHT orientations. Fortunately, Adobe has added some events that help us do just that. If your app descriptor has autoOrients set to true, the StageOrientationEvent.ORIENTATION_CHANGING event will be broadcast when the device’s accelerometer has detected the physical orientation has changed, and the Stage is about to rotate to follow suit. If you call Event.preventDefault(), you will prevent the Stage from rotating. So all we have to do is disallow rotating to the left or right, and allow rotating to the upside-down or default positions.

To accomplish this, add the following to your application descriptor file, to enable the Stage to rotate to follow the device’s physical orientation:

<autoOrients>true</autoOrients>

And add this to your app’s main class, to only allow a subset of those rotations to actually take place:

// we can control which orientations we want to allow with the following code
stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, onOrientationChanging );

function onOrientationChanging( event:StageOrientationEvent ):void
{
	// If the stage is about to move to an orientation we don't support, let's prevent it
	// from changing to that stage orientation.
	if(event.afterOrientation ==
		StageOrientation.ROTATED_LEFT || event.afterOrientation ==
		StageOrientation.ROTATED_RIGHT )
		event.preventDefault();
}

And voila! Your app now support both portrait orientations, or both landscape orientations!

Condensed from http://www.adobe.com/devnet/flash/articles/screen_orientation_apis.html

Also helpful: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html