NOTE: This guide is now deprecated; its contents have been merged into the manual (starting from v2.3.4) and can be found here. |
Now that you have followed Introduction to Creating Extensions in GameMaker you understand how to use the extension editor and make simple GML Code-based extensions.
In this guide we will now extend that knowledge to show how you can create a simple extension for the Android and iOS target platforms.
Important note: This guide assumes a little knowledge of programming in Objective C and Java. It is not a tutorial for either of these two languages.
Create Your GameMaker Project
Before going any further, you should first create a new project and call it "GenericTest", then add an object and a sprite to the asset browser.
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 native extension functions.
Create Your 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 Create Extension window.
Name your extension and give it a version number, then check the Android and/or iOS export checkboxes from the platform list to show that we are creating an extension for those platforms, and also uncheck all the "Copies to" options except Android and/or iOS, so your extension looks like this:
(Note that if making an Android extension, this will be compatible with Amazon Fire devices too.)
To start with, we'll look at the iOS window. Here you can give various different bits of information that will govern how your extension works and what it includes. The available sections are:
- Compiler Flags / Linker Flags: Some frameworks and third party SDKs require the addition of extra linker flags and compiler flags to work. These can be specefied here (see the documentation that accompanies the SDK or framework you are using for more details).
- ClassName: Your extension can have multiple classes, with each class having its own list of functions and constants, so you should give it a name that reflects its purpose.
- Inject to Info.plist: Here you can add any code to be a injected into the info.plist file.
- System Frameworks: Here you can add in any iOS system frameworks to your extension.
- 3rd Party Frameworks + Bundles: This section is for adding third party frameworks and SDK bundles.
For our simple extension you only need to give the class name "GenericTest" and you can leave the other options blank.
However, below is an example of how the tab might look when using a third-party SDK:
You can see the two sections at the bottom of this window are provided so that you can add any iOS system frameworks or third party frameworks to your extension (see the documentation that came with your chosen SDK for info on the framework name). To add framework/SDK information here you must first click the (+) button to create a "placeholder". You can then slow left-click on this and rename it to the correct name for your framework, and if the framework requires weak-linking then you can click the checkbox next to the framework name. With that done, you need to add the files to the extension, either from a Mac or from a PC, using the framework path or Add Source button at the bottom of the window.
In the Android window, like with iOS, you need to add in the information that Java or the SDK requires. This information is comprised of the following:
- ClassName: Your extension can have multiple classes, with each class having its own functions and constants, so you should give it a name that reflects its purpose.
- Android Permissions: Here you can add in any extra permissions that your extension requires. 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. To add a new permission you need to click the button to add a placeholder permission, and then do a slow click on that to edit it to what is required. You can remove permissions using the button.
- Inject To Gradle Dependencies: Here you can add any extra code that needs to be injected (added) into the Gradle build dependencies.
- Inject to AndroidManifest.xml Manifest: Here you 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 store, as incorrect settings will cause your game to be failed for submission.
- Inject to AndroidManifest.xml Application: Here you set any extra code to be injected (added) to the Android Manifest XML file under the Application heading 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 store, as incorrect settings will cause your game to be failed for submission.
- Inject to AndroidManifest.xml RunnerActivity: Here you set any extra code to be injected (added) to the Android Manifest XML file under the RunnerActivity heading 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 store, as incorrect settings will cause your game to be failed for submission.
Again, for our simple extension you only need to give the class name "GenericTest" and you can leave the other options blank.
However, below is an example of how the tab might look when using a third-party SDK:
Add Your Native Source Code
Once you have created the extension you will need to add the required files for it to work. So let's create some files with our source code to add for both platforms.
Our extension will do the following:
- 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
Rather than post the various sections of code here and make this guide very long, we have made the files available for download here (and also at the very foot of this page).
- For iOS you require a pair of files which work together: GenericTest.mm GenericTest.h
- For Android it's just the one file: GenericTest.Java
Once you have downloaded these files to a location on your hard disk you can go back to GameMaker to add them to the extension. To do this you need to do the following for the different platforms:
- For iOS - You will want to use either the Enter framework path (+) or the Add Source section of the iOS window (depending on whether the downloaded source files are on Mac or PC), and then browse to the folder containing the .mm and .h files.
- For Android - Click the Add Source button and browse to the folder where you downloaded the .java file.
Once you have done this, you won't see any obvious changes to the GameMaker windows, but the files will have been added to your extension. You can check this easily by right-clicking the extension in the resource tray and selecting Open In Explorer / Open in Finder. When the file browser window opens, you should see folders for each of the added files, called AndroidSource and iOSSource:
(Here we show Windows Explorer, but macOS Finder would look very similar.)
If you then open those folders, you should find the files you downloaded for the extension. All files added to an extension will go in one of these folders, based on the OS the extension is for.
Create Your Extension's Functions
Next you need to add the function declarations to the extension so that your code can use it in your games. To do this, first close the iOS and Android extension properties and then in the main extension editor click the Files selector and add a placeholder file:
The "placeholder" is simply the top level folder of the functions and constants. If you double-click on the name, then you will get the placeholder Properties window, which is where we'll be defining the functions for the extension:
To add the functions, simply go to the Functions section of the window and click the menu bar then select Add Function:
This will open the function properties window where we can start to define the functions for the extension. Note that both of the platforms (iOS and Android) will be using the same functions and if you study the downloaded files using any simple text editor you will see that the source files share the same function names for everything.
The functions we will be adding are as follows:
function / external name: AddTwoNumbers
help: AddTwoNumbers(value1 , value2)
arguments: double, double
return type: double
function / external name: HowManyObjects
help: HowManyObjects(value1, value2, string)
arguments: double, double, string
return type: string
function / external name: BuildAString;
help: BuildAString(string1, string2)
arguments: string, string
return type: string
function / external name: ReturnAsync
help: ReturnAsync(value1, value2)
arguments: double, double
return type: double
Please create all of these functions just now.
Here is an example image of how one of the functions should look with the details filled in:
When you've added all the functions given above, we can start to program our test game to use them.
Use Your New Extension In Your Game Code
Our new extension functions can now be used just as you would any of the regular GML Code 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 add a Create Event to our object we made earlier in order 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));
The ReturnAsync() function will require that you add a Social Asynchronous Event to the object, as it will be triggered by the function. This is a useful way to return information as it will permit the game to continue running and other things to happen while the extension is processing or retrieving data. In this event 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 also add a Draw Event to show the result variables on the screen so that you can see whether the extension has worked, with code something like:
draw_self();
draw_text(32, 32, result1);
draw_text(32, 48, result2);
draw_text(32, 64, result3);
draw_text(32, 96, result4);
Testing
You can now test your project on an Android and/or iOS device and see that the extension functions are working correctly.