Create the native code

A native extension is a C/C++ shared object that contains certain functions that act as entry points to the interface used by the ActionScript code. Your first step is to create the native portion of the extension using the BlackBerry 10 Native SDK.

For more information on setting up the BlackBerry 10 Native SDK development environment, see the Getting started guide.

Set up a native SDK project

Create a shared object and set some project-specific properties using the QNX Momentics IDE.

  1. Open the BlackBerry 10 Native SDK.
  2. On the File menu, click New > BlackBerry C/C++ Project.
  3. In the Project name field, type NativeCode.
  4. Click Next.
  5. In the Project type section, expand Air Native Extension, select Hello AIR Native Extension.
  6. Click Finish.

The NativeCode project has been created, it should appear in the Project Explorer window.

This project template contains the barebones of a native extension. sayHello is the native function you will base your native extension on. The Hello AIR Native Extension project template contains the source code in the main.c file. For a copy of this source code, see CS Hello AIR Native Extension.

The initialize and finalizer functions shown in the code sample are part of the native extensions interface between the ActionScript code and the native code. They are mandatory in any ANE you create.

FlashRuntimeExtensions.h is provided by Adobe, but it is already available in the BlackBerry 10 Native SDK for you to use.

Build the native SDK project

To build the binaries for both the BlackBerry device and simulator at the same time, perform the following steps:

  1. In the Project Explorer window, right-click the NativeCode project and click Build Configurations > Build Selected.
  2. Select the Device-Debug and Simulator-Debug configurations.

  3. Click OK.

After the build process is complete, you'll see both binaries in the Binaries folder in the project. Next, create the ActionScript library to communicate with the native code.

When you are ready to release your application, you must select Device-Release when you rebuild binaries.

CS Hello AIR Native Extension

The following code is automatically added to your project when you select the Hello AIR Native Extension template.

/*
 * Copyright (c) 2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "FlashRuntimeExtensions.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void ExtensionInitializer(void** extDataToSet,
		FREContextInitializer* ctxInitializerToSet,
		FREContextFinalizer* ctxFinalizerToSet);
void ExtensionFinalizer();

void ContextInitializer(void* extData, const uint8_t* ctxType, 
		FREContext ctx, uint32_t* numFunctionsToSet, 
		const FRENamedFunction** functionsToSet);
void ContextFinalizer(FREContext ctx);

FREObject sayHello(FREContext ctx, void* functionData, uint32_t argc,
		FREObject argv[]);


FREObject sayHello(FREContext ctx, void* functionData, uint32_t argc,
		FREObject argv[]) 
	{
		const char *out = "Hello from the native code!";
		FREObject result;
		FRENewObjectFromUTF8((uint32_t)(strlen(out) + 1), (uint8_t*) out, &result);
		return result;
	}

/**
 * The runtime calls this method once when it loads an ActionScript
 * extension. Implement this function to do any initializations 
 * that your extension requires.
 * Then set the output parameters.
 *
 * @param extDataToSet
 *             A pointer to a pointer to the extension data of the
 *             ActionScript extension. Create a data structure to 
 *             hold extension-specific data. For example, allocate
 *             the data from the heap, or provide global data. Set
 *             extDataToSet to a pointer to the allocated data.
 *
 * @param ctxInitializerToSet
 *             A pointer to the pointer to the FREContextInitializer()
 *             function. Set ctxInitializerToSet to the 
 *             FREContextInitializer() function you defined.
 *
 * @param ctxFinalizerToSet
 *             A pointer to the pointer to the FREContextFinalizer()
 *             function. Set ctxFinalizerToSet to the FREContextFinalizer()
 *             function you defined. You can set this pointer to NULL.
 */
void ExtensionInitializer(void** extDataToSet,
		FREContextInitializer* ctxInitializerToSet,
		FREContextFinalizer* ctxFinalizerToSet) {
	*extDataToSet = NULL;
	*ctxInitializerToSet = &ContextInitializer;
	*ctxFinalizerToSet = &ContextFinalizer;
}

/**
 * The runtime calls this function when it disposes of the 
 * ExtensionContext instance for this extension context.
 */
void ExtensionFinalizer() {
}

/**
 * The runtime calls this method when the ActionScript side
 * calls ExtensionContext.createExtensionContext().
 *
 * @param extData
 *             A pointer to the extension data of the 
 *             ActionScript extension.
 *
 * @param ctxType
 *             A string identifying the type of the context.
 *             You define this string as required by your 
 *             extension. The context type can indicate any
 *             agreed-to meaning between the ActionScript 
 *             side and native side of the extension. If your
 *             extension has no use for context types, this 
 *             value can be Null. This value is a UTF-8
 *             encoded string, terminated with the null character.
 *
 * @param ctx
 *             An FREContext variable. The runtime creates 
 *             this value and passes it to FREContextInitializer().
 *
 * @param numFunctionsToSet
 *             A pointer to a unint32_t. Set numFunctionsToSet
 *             to a unint32_t variable containing the number
 *             of functions in the functionsToSet parameter.
 *
 * @param functionsToSet
 *             A pointer to an array of FRNamedFunction elements.
 *             Each element contains a pointer to a native function,
 *             and the string the ActionScript side uses in the
 *             ExtensionContext instance's call() method.
 */
void ContextInitializer(void* extData, const uint8_t* ctxType, 
		FREContext ctx, uint32_t* numFunctionsToSet, const 
		FRENamedFunction** functionsToSet) 
	{
		char *temp = NULL;
		int i;

		// define an array of functions
		const char *functionNames[] = { "sayHello", NULL };
		FREFunction functionPtrs[] = { sayHello, NULL };

		// count number of functions
		*numFunctionsToSet = 0;
		while (functionPtrs[*numFunctionsToSet] != NULL) 
		{
			(*numFunctionsToSet)++;
		}

		FRENamedFunction *functionSet = calloc(*numFunctionsToSet,
				sizeof(FRENamedFunction));

		for (i = 0; i < *numFunctionsToSet; i++) 
		{
			int bufferSize = sizeof(char) * 
					(strlen(functionNames[i]) + 1);
			temp = (char*) malloc(bufferSize);
			strncpy(temp, functionNames[i], bufferSize);
			temp[strlen(functionNames[i])] = '\0';
			functionSet[i].name = (uint8_t*) temp;
			functionSet[i].functionData = NULL;
			functionSet[i].function = functionPtrs[i];
		}

		*functionsToSet = functionSet;
	}

/**
 * The runtime calls this function when it disposes of the 
 * ExtensionContext instance for this extension context.
 *
 * @param ctx
 *             The FREContext variable that represents this 
 *             extension context.
 */
void ContextFinalizer(FREContext ctx) 
	{
	}