Creating A Native Extension For Android (GMS v1.3+)

With the GameMaker: Studio update to version 1.3, the extension system was re-vamped to permit native extensions on different platforms, one of which was Android. This simple tutorial takes you through the basic steps necessary to create an Android extension and call a function using device native code. Note that this tutorial assumes you have a good working knowledge of Java as well as GameMaker.

Note: For an overview of how basic Windows extensions work, please see the article Creating An Extension For Mac, Windows, And JS Targets. If you are new to extensions it is recommended that you read this article too.

A Simple Example

The following is a very simple example of adding a set of new functions to GameMaker: Studio that will use a custom Java file to return information to GameMaker: Studio..

The Basics

Before going any further, you should first create a new room, a new object and a new sprite. We are keeping this simple, so all we want is a button sprite which can be assigned to the object, and the object should be placed in the room. This "button" will call our new Android native function.

Create The Extension

We now need to create our extension. This is done by first right clicking on the Extensions folder in the resource tree and selecting "Create Extension", which will bring up the "Extension Wizard" window and here to start with you only need to name your extension and give it a version number, then check the Android check-box. Once you have done that you should click the Next button.

Extension_properties.png

Add ClassName, Permissions and Manifest

After clicking Next you will be taken to another tab where you can give the Class Name and add in information that your Java or SDK requires. For our simple extension you only need to give the class name "GenericTest".

Extension_properties_android.png

You can also add in any extra permissions that your extension requires from this page. What these permissions are will depend entirely on the use that the extension has, and so you should check the documentation supplied by Google for the Android platform, or, if you are using a third party SDK, the documentation that comes with the SDK.

You can set any extra code to be injected (added) to the Android Manifest XML file when your game is built for testing or final release. Make sure to revise this (and your permissions) carefully before submitting any games to the Google Play store, as incorrect settings will cause your game to be failed for submission.

However, for our example you can leave these blank, and click the Create button at the bottom to create our base extension.

Adding The Native Source Code

Once you have set this up correctly, you will need to add the required files for your extension package to work. So, let's create a Java file with our source code to add, and for this you will need a text editor (like Notepad++ for example). Our extension will do several things:

  • It will return two numbers added together.
  • It will return a string made up of an input string and an input value.
  • It will return a string made up from two input strings
  • It will return values to the Social Asynchronous Event

For this example we will create a file called "GenericTest.java", remembering to include the following line at the top of your Java file code otherwise it will not work (this is essential for all Android extensions):

package ${YYAndroidPackageName};

You will also need to have the following imports in your Jave file:

import ${YYAndroidPackageName}.R;
import com.yoyogames.runner.RunnerJNILib;

You can now create your class definition that includes the function that we desire to call. In our example we will create a class called "GenericTest" with a number of member functions to do what we require. The final Java should look something like this:

package ${YYAndroidPackageName};

import android.util.Log;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.String;

import ${YYAndroidPackageName}.R;
import com.yoyogames.runner.RunnerJNILib;


public class GenericTest
{

public double AddTwoNumbers(double arg0, double arg1)
{
double value = arg0 + arg1;
Log.i("yoyo", arg0 + "+" + arg1 + " = " + value);
return value;
}


public String BuildAString(String arg0, String arg1)
{
String myString = arg0 + " " + arg1;
Log.i("yoyo", myString);
return myString;
}


public String HowManyObjects(double arg0, double arg1, String arg2)
{
double value = arg0 + arg1;
Log.i("yoyo", arg0 + "+" + arg1 + " = " + value);
String myString = String.valueOf(value) + " " + arg2;
Log.i("yoyo", myString);
return myString;
}

private static final int EVENT_OTHER_SOCIAL = 70;
public void ReturnAsync(double arg0, double arg1)
{
int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null);
RunnerJNILib.DsMapAddString( dsMapIndex, "type", "finished" );
RunnerJNILib.DsMapAddDouble( dsMapIndex, "argument0", arg0);
RunnerJNILib.DsMapAddDouble( dsMapIndex, "argument1", arg1);
RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL);
}

}

Once you have created your Java file, save it to a location on your hard disk, and then go back to GameMaker: Studio to add it to the extension. To do this you need to right click on the extension and select either Add Android SDK or Add Android Source and then browse to the directory with the files you wish to add. In this case we want to choose Add Android Source and browse to where we saved our Java file. Added files will be stored in the AndroidSource directory along with your extension and can be edited directly there with any changes being detected automatically by Gamemaker: Studio. You can open this location at any time by right clicking on the extension and selecting Open Extension Directory

You can download a copy of the Java code given above here: GenericTest.Java

Creating the GML Functions

Next you need to add the function declarations to our extension in GameMaker: Studio so that your code can call your new Java extension. To do this, right click on the group file "GenericTest.ext" that we added earlier, and select Add Function. This will open a new window where you can add your function and assign its arguments and properties.

To match the Java you created earlier, you should give the function names and details the same as those listed below:

function / external name: AddTwoNumbers
help: AddTwoNumbers(value1 , value2);
argument0: double
argument1: double
return type: double

function / external nameHowManyObjects
help: HowManyObjects(value1, value2, string);
argument0: double
argument1: double
argument2: string
return type: double

function / external nameBuildAString
help: BuildAString(string1, string2);
argument0: string
argument1: string
return type: double

function / external name: ReturnAsync
help
: ReturnAsync(value1, value2);
argument0: double
argument1: double
return type: double

With that finished, we can start to program our test game to use these functions.

Calling The New Extension Functions

Our new extension functions can now be used just as you would any of the built in GameMaker: Studio functions, and if you have added the "help" string then your function will also appear in the auto-complete and syntax checker. To call our functions we need to create an object and assign it a sprite, then add a Create Event to initialise the variables required:

result1 = "!! Not run !!";
result2 = "!! Not run !!";
result3 = "!! Not run !!";
result4 = "!! Not run !!";

You can now add in a Mouse Left Pressed Event with the following code:

result1 = string(AddTwoNumbers(irandom(100), 50));
result2 = BuildAString("Hello", "World");
result3 = HowManyObjects(irandom(1000), irandom(1000), "Targets");
ReturnAsync(irandom(1000), irandom(1000));

You should also add a Draw Event to show the result variables on the screen so that you can see whether the extension has worked.

The ReturnAsync() function will require that you add a Social Asynchronous Event to the object, as it will be triggered by the function. In this we can have the following code:

var type = async_load[? "type"];
if type == "finished"
    {
    result4 = "value1: " + string(async_load[? "argument0"]) + ", ";
    result4 += "value2: " + string(async_load[? "argument1"]);
    }

You should now be able to test your game on an Android device and see that the extension functions are working correctly. Note that testing extensions on Android requires that you build a final APK, as just using the Test Play and Debug options form GameMaker: Studio will not work as the extension will not be compiled correctly.

Things To Note

You should also set the export options for the extensions that you make. This ensures that your files will only be exported with the final executable for the appropriate target platform. To set this, you need to right-click on the GenericTest.ext file in the resource tree and select Properties. un-check everything except Android.

FileProperties.png

Constant Substitution

As an additional note, with Android extensions, substitutions can be made for constants in Java code and when injecting code into the androidmanifest.xml. Enclosing the constant name in ${YourConstantName} will substitute in the value of the constant at compile time. So, for example, we would have something like this in our Java:

String AppID = RunnerActivity.mYYPrefs.getString("AndroidId");

However, with the constant substitution we could instead use:

String AppID = "${AndroidId}";

Where AndroidId would be the constant that you have defined for your extension package within GameMaker: Studio.

Have more questions? Submit a request

0 Comments

Article is closed for comments.