Adobe Native Extension for iOS Game Center – Part 1

Adobe AIR Native Extensions + Apple Game Center = :)

With the advent of Adobe Native Extensions (ANE’s) Flash platform developers have been fully unleashed upon the mobile OS scene. Your Flash apps now have full access to all native features through ANEs. This two part series will get you ready to integrate your own Flash games with Apple’s Game Center so you can start concentrating on making your fortune.

For brevity, this post is only going to show you how to do three things with Game Center, authenticate the user, show leaderboards and show achievements. I noticed during my Google sessions, there are many other people looking for the same integration with Game Center ANEs for Flash mobile games, so this will show you the bridge to achieve that goal, and the rest of the implementation is up to you. By the end of this post, you’ll understand how to submit achievements or scores, etc, all the things we’re not doing in this post.

Because I can’t say this enough, I’ll post it in bold: IMPORTANT - You need a decent understanding of ANE creation in general and setting up apps with iOS Developer Portal and iTunes Connect for Game Center. Without those prerequisites, you won’t get much from this post.

Whatever, just show me the code!

Github code repository for the entire project.

For starters, I’m assuming you’re familiar with the lengthy process of signing up with the Apple iOS Developer Program and setting up your Leaderboard and Achievements in iTunes Connect, so I’m going right for the meat of the code as you can find all the other setup information floating around the internets very easily. If you’re unfamiliar with the process or ANE creation altogether, you can start by reading the posts below from other blogs and documentation to gain a better understanding of what’s involved. If you have experience with ANEs for iOS and iTunes Connect/Game Center portal, you can skip the other links, just set up the game and your leaderboard and achievements.

Create the Actionscript 3 library project

Dr Sheldon Cooper - The Big Bang Theory

Dr Sheldon Cooper – The Big Bang Theory

At this point, you should have your game set up with iTunes Connect and ready for Game Center integration. I used XCode 4.2 to create the native side for the ANE, and Flash Builder 4.6 to create the library project. In honor of Dr Sheldon Cooper from the Big Bang Theory, I called my fake game Bazinga, set up a BazingaTest leaderboard with an ID of 200, and three achievements called A1, A2, and A3. You need to set up everything in iTunes Connect first before anything else.

The next step is to create a new AS3 library project. Open Flash Builder and choose File -> New -> Library Project and give it a name, I called mine BazingaANE. Right click on the src folder and click New -> Package and use your reverse domain name (mine is com.pxldesigns.bazinga). Right click on your newly created package and choose New -> ActionScript Interface and give it a name, I called mine iBazingaANE. Now we can start stubbing out the public API methods for the library so we can use the ANE from Flash. Here’s what the interface looks like:

package com.pxldesigns.bazinga
{
public interface iBazingaANE
{
function loginUser():void;
function showAchievements():void;
function showLeader():void;
}
}

Right click again on the package and choose New -> ActionScript Class. This will be the implementation of the interface in the previous step. In my case, I called the class BazingaANE and it looks like this:

package com.pxldesigns.bazinga
{
	import flash.external.ExtensionContext;

	public class BazingaANE implements iBazingaANE
	{
		protected static const EXTENSION_ID : String = "com.pxldesigns.bazinga.BazingaANE";

		protected var context:ExtensionContext;

		public function BazingaANE()
		{
			context = ExtensionContext.createExtensionContext( EXTENSION_ID, null );
		}

		public function loginUser():void
		{
			context.call("loginUser");
		}

		public function showAchievements():void
		{
			context.call("showAchievements");
		}

		public function showLeader():void
		{
			context.call("showLeader");
		}
	}
}

If you take a look at the livedocs, you’ll see the basic structure for the descriptor XML file needed for the ANE creation. Along with the descriptor file, we’ll create another XML file to list the platform and linker options since we need to include the Apple GameKit framework. AIR 3.1 includes new functionality like pointing to an external SDK rather than the captive AIR SDK, and adding link options, you can read more here. Note: there are many ANT scripts floating around the web may make things easier and faster in building ANEs, but just to illustrate the bare essentials I’m sticking with the low tech method for now, see the Github repository for both XML files.

When you save and build your AS3 library project, you’ll see the BazingaANE.swc was created in the bin folder. We need the library.swf inisde the swc and Adobe left us just one hacky way to get it. Change the extension on the swc to .zip, then uncompress it. Inside the uncompressed folder is the library.swf we’ll use later to create the actual ANE, let it rest there for now. It’s been through a lot, and so have you thus far.

Creating the native code for the ANE

On to the native side next, in XCode 4.2, create a new project with File -> New -> New Project, then iOS -> Framework & Library -> Cocoa Touch Static Library. I called my project BazingaANE and I’m storing it under a Developer/XCode_Workspace folder. To try and shorten this post up, I’m going to explain the important parts I ran into without delving into the details since you can read about from the other blogs and livedocs.

Right click on your project and choose Add Files to BazingaANE (or whatever your project’s name is). Browse for the FlashRuntimeExtensions.h located in /Applications/Adobe Flash Builder 4.6/sdks/4.6.0/include/ and make sure the Destination checkbox is checked (copy items into dest…)

Before getting into the code, it’s a good time to make sure your Build Settings are correct. You definitely want to read this info from liquid-photo.com for Build Settings I ran into a few crazy errors when finally trying to run the end product in Flash Builder, the same as many other people here but thanks to liquid-photo.com’s tips, I was able to resolve them. If you run into any issues with the final app crashing, the first thing I’d check is your build settings in XCode.

Again for brevity, I added the AppSpecificValues.h, and GameCenterManager.h/m from Apple’s GKTapper sample Game Center application, this seems to be the de facto implementation for all the other GC blog posts I’ve found so who am I to disagree?

Now the only thing still needed is a a fancy delegate to handle all the calls to methods of the GameCenterManager class. The GC leaderboard and achievements pop up as a modal view over the game, we don’t have a nib file since it’s not purely a native iOS app, so we’ll just use an instance of the delegate to handle events for us.

Right click on the project and choose New File -> Objective C class and hit next. I called mine MyDelegate for giggles and just hit next until both the header file and implementation were created.

Under your Build Phases -> Link Binary with Libraries, hit the plus (+) sign, and start typing “game”. You need to include the GameKit framework with the project – duh.

The full code is available here on GitHub. The important class to start with is the BazingaANE.m. FlashRuntimeExtension.h is included instead of imported and this class should reflect the AS3 interface with all its methods.

//
//
//  Created by David Flatley on 1/28/12

#include "FlashRuntimeExtensions.h"
#import "MyDelegate.h"

MyDelegate *myDelegate = nil;

FREObject loginUser(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
    if (myDelegate)
    {

    }
    else {
        myDelegate = [[MyDelegate alloc] init];
    }

    [myDelegate loginUser];

    return NULL;
}

FREObject showAchievements(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
    [myDelegate showAchievements];
    return NULL;
}

FREObject showLeader(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
    [myDelegate showLeaderboard];

    return NULL;
}

// required methods, list your custom functions here
void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
{

	*numFunctionsToTest = 3;

	FRENamedFunction* func = (FRENamedFunction*)malloc(sizeof(FRENamedFunction)*3);
	func[0].name = (const uint8_t*)"showAchievements";
	func[0].functionData = NULL;
	func[0].function = &showAchievements;

    func[1].name = (const uint8_t*)"showLeader";
	func[1].functionData = NULL;
	func[1].function = &showLeader;

    func[2].name = (const uint8_t*)"loginUser";
	func[2].functionData = NULL;
	func[2].function = &loginUser;

	*functionsToSet = func;

}

void ContextFinalizer(FREContext ctx)
{
    [myDelegate release];
    myDelegate = nil;
   	return;
}

void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet) {
	*extDataToSet = NULL;
	*ctxInitializerToSet = &ContextInitializer;
	*ctxFinalizerToSet = &ContextFinalizer;
}

void ExtFinalizer(void* extData) {
	return;
}

This class represents the native side of the AS3 interface we created earlier. The loginUser, showLeader, and showAchievements methods are specific to our implementation of GC and the rest are mandatory for the ANE. Here, we’re handing off the work to the delegate once a call is received from Flash. The test app we create in part two of this series will attempt to login automatically, so we should have our MyDelegate instance ready by the time we hit some buttons to show the leaderboard and acheivements. The code to actually invoke Game Center functionality is in in the MyDelegate class, it’s the the same as the GKTapper app.

When you have the full project running and then build it, you’ll end up with the libBazingaANE.a library file located wherever you specified the output in the build settings (Per Configuration Build Products Path). I set mine to a folder called debug so I have a place to perform surgery on my ANE. It’s quite a hacky process as you’ll see next.

Creating the ANE

You’ll remember the library.swf you extracted before. Grab a copy of the library.swf, and both XML files (extension.xml and other.xml in this case) and place it in your debug folder along with the libBazingaANE.a and BazingaANE.swc. Crank up the terminal next, and enter:

/Applications/Adobe\ Flash\ Builder\ 4.6/sdks/4.6.0/bin/adt -package -target ane BazingaANE.ane extension.xml -swc BazingaANE.swc -platform iPhone-ARM libBazinga.a  library.swf -platformoptions other.xml

If all goes well, you just created your BazingaANE.ane and it’s ready to use in your app. In part two, I’ll show you how to test it out with a sample Flash game. I’ll be continuously updating these blog posts because there’s a lot of different variables to keep track of and it’s tough enough to build ANEs let alone blog about them :)

2 Comments

  1. Pingback: Adobe Native Extension for iOS Game Center – Part 2 « David Flatley

  2. Pingback: Adobe Native Extension for iOS Game Center – Part 1 « David Flatley | BLUEMARKER

Leave a Comment

Your email address will not be published.


× 5 = five

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>