[Tutorial] Creating a simple Game Maker Studio native Android extension for implementing Batch unlocking system

Hello there!
I’m creating this tutorial because in the last days I needed to implement the Batch automatic unlocking system (see https://batch.com/) into my last Android game made with Game Maker: Alpaca Jump, available on Google Play for free, here: https://play.google.com/store/apps/details?id=com.mattiafortunati.alpacajump.free

If you don’t know it, Batch is a great tool for scheduling and managing automatic offers, bonuses, push campaigns, statistics, and many other things within your game. And it’s totally free.
It’s really good for running 24h promotion if, for example, your app is going to be featured within services like AppGratis.

Well, I couldn’t find anything around the web explaining how to implement Batch into a Game Maker game, or similar, and the Bath team was pretty busy at the moment, because their product is growing really fast!
So I’ve had to do it by myself, and I’ve decided to create this simple tutorial to help future Game Maker + Batch users.

I will show you how to create a simple extension for handling the Batch unlocking feature.
It’s really a basic extension, since it can only handle one offer at time (see below for more info), but I hope that this guide can be handy if you want to implement a more complex interface for all the Batch functionalities you need.

NOTE: I’ve published this extension in the Game Maker Marketplace, for free, under the name of batchSimpleFeatureEx: https://marketplace.yoyogames.com/assets/1077/batch-sdk-simple-feature

WARNING:

Since the Batch.com team closed their Unlock service, part of this extension won’t work anymore. However you can still use this extension for the basico login into the batch.com service.

Also, the information below will always work as a tutorial for creating a Game Maker Extension.

More information here: http://www.mattiafortunati.com/goodbye-appgratis-and-unlock-by-batch/

First of all, you should know how to create a basic Game Maker Extension, so check this link
http://help.yoyogames.com/entries/30690273-Creating-A-Native-Extension-For-Android-GMS-v1-3-
and try to create a simple extension as explained there. Please focus on the Social Async Event.

Second, check the Batch documentation, and API reference, here: https://dashboard.batch.com/doc/getting_started/android.html
And check how to implement Batch within an Android game. It’s pretty simple.
And you’ll need to have a Batch account and download the batch.jar library, which is found within the Batch Android distribution.

Obviouysly, you’ll need Game Maker Studio Pro v1.3+, and a text editor for handling some Java code.
And you’ll need to have an idea on how Android SDK works. So check this, too: http://developer.android.com/reference/android/package-summary.html
For any Android reference.

What are we going to do?

We are going to implement the Batch automatic unlocking system, for handling the so called “feature” and “resource” offers in an “automatic” way.

And here’s the great problem that I encountered: Game Maker Studio does not allow us to modify its main application and activity, called RunnerApplication and RunnerActivity, so we cannot add some calls to their onCreate, onStart etc, as required for the Android Batch setup for automatically handling the unlock through a listener.

I couldn’t find a good solution for making Batch working automatically, my solution needs a button to be clicked and a popup that will be opened.
However, it can be a start, a possibility, for me, and for the Game Maker users, to implement and start using Batch.
Maybe it’s tricky, and It’s quite naive and incomplete, a “better than nothing” implementation, but it seems to work well for my actual, simple, needs.
If you find a better solution, please let me and the Game Maker community know about it 🙂

And here it is:

alpaca_jump_batch_screen_2

My solution for my Alpaca Jump, as you can see from the screenshots above, is to:

  • configure Batch as soon as the game starts, with the right API_KEY
  • add a button to the game, in my case a top-left yellow button with a gift icon (sceen1)
  • when the button is pressed, a new dialog activity is created, and shown as a popup. (screen2) This popup will listen for an offer. When an offer is found it will close and call a function within our game, else the user can return to the game with the close button, with the device’s back button or by clicking anywhere around it.
  • handle the unlock when the offer is received by checking the reference id, unlocking the game and showing a notification to the user (screen3).

So I’m using a popup, a dialog, as a listening activity for Batch offers, which can be received only while the popup is shown.

For doing this, my extension needs these functionalities to be called from Game Maker:

  • Batch API_KEY Configuration. To be called as soon as the game starts.
  • Popup Open function. To start the activity and configure global variables for texts.

Then, silently the extension will:

  • Show the configured popup. With right texts and the possibility to be closed by the user.
  • Handle onStart, onStop, onDestroy and onNewIntent.
  • Start a listener, by implementing BatchUnlockListener and starting it.
  • Receive the offer, by overriding the onRedeemAutomaticOffer.
  • Call Game Maker, through a Social Async Event.
  • Close itself.

Following the Batch setup documentation for Android and the Game Maker tutorial linked above, it’s really easy to create an activity that handles all the Batch functions and calls for a Social Async Event.
You can find the full code, fully commented, on gitHub here:

https://github.com/MattiaFortunati/Batch-SDK-Simple-Feature

Let’s take a look at the java code:

/****************************************************************************************************************************
*
* batchSimpleFeatureEx
*
* batchSimpleFeatureEx handles some basic functionalities for implementing Batch Automatic unlocking system
* into your Game Maker Pro game.
*
* With batchSimpleFeatureEx you can:
* – configure Batch with your API_KEY
* – open a popup which listens for any offer and callbacks to a Game Maker Studio Async Social event whenever
* an offer is found.
* Both feature and resources types of offers are supported,
* and their reference and value (or quantity) are both passed to Game Maker.
*
* NOTE: for resource offers, quantity is passed to Game Maker as String.
* Into the Async Social “batchFeature” or “batchResource” are passed as “type”, references are
* passed as “reference” while value and quantity are passed both as “value”.
*
* batchSimpleFeatureEx is intended as extension for Game Maker Studio Pro v1.3+
* to be used into your Android project.
* This is just the Java file, to make this work into your Game Maker game, you need to properly setup your
* project, and you need to have batch.jar into the extension lib folder.
*
* For information about batchSimpleFeatureEx usage, check the code comments
* and Batch documentation and API references.
*
* IMPORTANT NOTE: this is just a simple implementation of the Batch unlock feature, in fact, batchSimpleFeatureEx
* can handle only one offer at time, because after any offer is found the Game Maker Studio Async Social event is
* called and the waiting popup is closed automatically.
*
* ADDITIONAL NOTE:
* The popup will close automatically even if the received offer is not handled by your Game Maker code,
* it will simply close, without notifying anything to the user, whenever any offer is redeemed.
* Also. remember that, at the moment of the Game Maker Async Social event call, the offer is considered
* as already redeem by the user, so it cannot be redeemed anymore by the same user again.
* So, be sure that you handle all the offers that can be received, and properly notify the user
* about the offer just redeemed.
*
* I hope this implementation can help you, even if you need to implement more complex Batch functionalities.
*
*
* Author: Mattia Fortunati
* Contact: mattia@mattiafortunati.com
* Website: http://www.mattiafortunati.com
*
****************************************************************************************************************************/

package ${YYAndroidPackageName};

//Basic imports
import android.util.Log;
import java.lang.String;
//
import android.app.Activity;
import android.content.Intent;

//Import Batch
import com.batch.android.*;

//Import Game Maker classes
import ${YYAndroidPackageName}.R;
import com.yoyogames.runner.RunnerJNILib;
import ${YYAndroidPackageName}.RunnerActivity;

//Other imports for implementing buttons and texts
import android.view.View;
import android.widget.TextView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.Button;
import android.view.View.OnClickListener;
import android.view.Gravity;

public class batchSimpleFeatureEx extends Activity implements BatchUnlockListener
{

//var declarations
private static TextView msg;
private static String titleStr;
private static String messageStr;
private static String btnStr;
private static final int EVENT_OTHER_SOCIAL = 70;

//Public methods, to be called from Game Maker Studio.

//Call batchSetup at the very beginning of your game.
//Use your Batch API_KEY
public void batchSetup(String API_KEY) {
Batch.setConfig(new Config(API_KEY));
Log.i(“yoyo”,”*****BATCH CONFIGURED WITH API KEY: “+ API_KEY);
}

//Call batchOpen whenever you want to open the popup and start listening for offers.
//titleString is the title of the popup, the header.
//messageString is the message to show, while listening.
//buttonString is the close button text.
public void batchOpen(String titleString, String messageString, String buttonString) {
Intent intent = new Intent(RunnerActivity.CurrentActivity, batchSimpleFeatureEx.class);
RunnerActivity.CurrentActivity.startActivity(intent);
titleStr = titleString;
messageStr = messageString;
btnStr = buttonString;
Log.i(“yoyo”,”*****BATCH OPENED”);
}

//Overrides
@Override
protected void onStart()
{
super.onStart();

//set batch unlock listener passing this, because BatchUnlockListener is implemented
Batch.Unlock.setUnlockListener(this);
Log.i(“yoyo”,”*****BATCH LISTENER SET”);

//start batch
Batch.onStart(this);
Log.i(“yoyo”,”*****BATCH STARTED”);

//create some linear layouts for handling text and button
LinearLayout lLayout = new LinearLayout(this);
lLayout.setOrientation(LinearLayout.VERTICAL);
LayoutParams lLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
LayoutParams lLayoutParams2 = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lLayoutParams2.gravity = Gravity.CENTER;
LayoutParams lLayoutParams3 = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lLayoutParams3.gravity = Gravity.RIGHT;
setContentView(lLayout , lLayoutParams);

//set activity title, header.
this.setTitle(titleStr);

//create text and set message
msg = new TextView(this);
msg.setText(messageStr);
msg.setLayoutParams(lLayoutParams2);
msg.setTextSize(20);
lLayout.addView(msg);

//create button and set text
Button btn = new Button(this);
btn.setText(btnStr);
lLayout.addView(btn,lLayoutParams3);

//button listener
btn.setOnClickListener( new OnClickListener() {

@Override
public void onClick(View v) {
finish();
}
});

}

@Override
protected void onStop()
{
//stop batch
Batch.onStop(this);
Log.i(“yoyo”,”*****BATCH STOPPED”);
super.onStop();
}

@Override
protected void onDestroy()
{
//destroy batch
Batch.onDestroy(this);
Log.i(“yoyo”,”*****BATCH DESTROYED”);
super.onDestroy();
}

@Override
protected void onNewIntent(Intent intent)
{
//
Batch.onNewIntent(this, intent);
Log.i(“yoyo”,”*****BATCH NEW INTENT”);
super.onNewIntent(intent);
}

@Override
//remember that this will handle just one offer at time, since as soon as
//an offer is found, Game Maker Social Async event is called and finish() is called
//Note that at this point, the offer has already been redeemed by the user,
//and cannot be redeemed anymore by the same user again.
public void onRedeemAutomaticOffer(Offer offer)
{
Log.i(“yoyo”,”*****BATCH OFFER RECEIVED”);

//check for feature offer
for(Feature feature : offer.getFeatures())
{
//get reference and value
String featureRef = feature.getReference();
String value = feature.getValue();
Log.i(“yoyo”,”*****BATCH OFFER FEATURE REDEEMED”);
Log.i(“yoyo”,”*****BATCH OFFER FEATURE REF:”);
Log.i(“yoyo”,featureRef);
//make sure value is not null or empty
if (value != null && !value.isEmpty()){
Log.i(“yoyo”,”*****BATCH OFFER VALUE:”);
Log.i(“yoyo”,value);
}else{
value = “”;
}
//call Game Maker Social Async event
//passing it reference and value
ReturnAsync(“batchFeature”,featureRef,value);

}

//check for resource offer
for(Resource resource : offer.getResources() )
{
//get reference and quantity
String resourceRef = resource.getReference();
int quantity = resource.getQuantity();
Log.i(“yoyo”,”*****BATCH OFFER RESOURCE REDEEMED”);
Log.i(“yoyo”,”*****BATCH OFFER RESOURCE REF:”);
Log.i(“yoyo”,resourceRef);
Log.i(“yoyo”,”*****BATCH OFFER QUANTITY:”);
Log.i(“yoyo”,String.valueOf(quantity));
//call Game Maker Social Async event
//passing it reference and quantity (as string)
ReturnAsync(“batchResource”,resourceRef,String.valueOf(quantity));
}

finish();

}

//ReturnAsync is called whenever an offer is found
//it will call the Game Maker Social Async event
//passing “batchFeature” or “batchResource” as type
//references as “reference”
//and value or quantity as “value”
public void ReturnAsync(String tp, String ref, String val)
{
int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null);
RunnerJNILib.DsMapAddString( dsMapIndex, “type”, tp );
RunnerJNILib.DsMapAddString( dsMapIndex, “reference”, ref);
RunnerJNILib.DsMapAddString( dsMapIndex, “value”, val);
RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL);
}

}

Let me write it once again: this is just a simple implementation of the Batch unlock feature, in fact, batchSimpleFeatureEx can handle only one offer at time, with just one item at time, because after an offer is found the Game Maker Studio Async Social event is called and the waiting popup is closed automatically.

Now that we have our Java code, we need to do some setups:

  • create and extension with the extension wizard (right click the extension section within Game Maker)
  • call it batchSimpleFeatureEx
  • set it available on Android platform
  • put the Java file, named batchSimpleFeatureEx.java within AndroidSource > Java. Right click and select show in explorer, after having saved the project.
  • put the batch.jar file under AndroidSource > libs. Create a libs folder if it’s not there

Don’t forget to declare and set up the extension activity into the manifest!
Double click the extension and in the android manifest injection section, put this:

<activity android:name=”${YYAndroidPackageName}.batchSimpleFeatureEx” android:theme=”@android:style/Theme.Holo.Dialog” />

Now, as for the Game Maker extension tutorial we’ll have to set our functions to be called from our Game Maker code.
So add a placeholder to the extension, add two functions and set them like this:

function / external name: batchSetup
help: batchSetup(String API_KEY)
argument0: string
return type: string

function / external name: batchOpen
help: batchOpen(String titleString, String messageString, String buttonString)
argument0: string
argument1: string
argument2: string
return type: string

Alright. Now we need call these from Game Maker.

At the very beginning of you game, call:
batchSetup(“API_KEY”)
where API_KEY is you Batch API key.

Instead, in the left release event of your button (or wherever you want) call this:
batchOpen(“Promotion”, “Searching for an offer …”, “Close”)
to open the popup.

Fine! Now your Batch is set up, and your game can succesfully set your API key and listen for offers.
So, now, we need to receive the Social Async Event from Game Maker!

In your desired object, create a Social event.
This event will be called with any social callback so we need to check whether the call is from Batch.
“type”, “reference” and “value” will be received.
“type” depends on the offer, and it can be “feature” or “resource”.
“reference” is the id of the feature or the offer.
“value” is the feature value, or the quantity if it is a resource.

So let’s get this value like this, as strings:

var type = string(async_load[? “type”];)
var reference = string(async_load[? “reference”];)
var value = string(async_load[? “value”];)

And now we can easily make our checks to unlock something to the user!

if (type == “batchFeature”){
//feature offer received
if (reference == “FREE_VERSION”){
//unlock the free version
}
var message_to_user = value
//prompt custom message to the user
}

if (type == “batchResource”){
//resource offer received
if (reference == “FREE_GOLD”){
//unlock some gold to the user
var gold_to_unlock = value
//give the user gold_to_unlock golds
}
}

Aaaaand … we are done!

Some Tips for the Batch dashboard:
if you are using a DEV API KEY, just set the offer as “DEV” and leave the “LIVE” option off.
if you want to reset dev redeemed offers use edit > reset redeemed dev codes. And Save offer.
if you click edit > reset and the edit again to go into other options, the reset WON’T BE SAVED.
The required bundled id is a list of app packages name that needs to be installed on the user’s device or the offer won’t be received.
Finally, don’t forget to put the “LIVE” option ON!

Batch is really young, and these are just some strange issues that I bumped in while playing with it at its early stage.
I won’t be surprised if they have already been fixed or changed 🙂

Well, I hope that this guide can help you, in creating your own extension for Batch, or just as guide to make your own extension of any kind.

I’m offering this guide, the java source code and the extension TOTALLY FOR FREE!
So, If you found this guide useful, please share it, and leave a comment!
If you find any errors or bugs, have any suggestions to improve the code, or a better way for implementing Batch, maybe automatically, feel free to leave a tip, too!

Also, try out Alpaca Jump to see Batch popup listener popup in action!
Alpaca Jump in Google Play: https://play.google.com/store/apps/details?id=com.mattiafortunati.alpacajump.free

Well, let me know!
Happy coding!

Mattia

Comments

  • Hello,

    I am a young developper and I have now the opportunity to make my game grow by being promoted in
    AppGratis. However they really need that I integrate the Batch SDK but i really don’t have any idea.
    Also, I have problems downloading on the Marketplace so would you be able to send it into my mail?
    My email is: igna92bcn@gmail.com

    Thank you very much,

    Ignasi

    IgnasiFebruary 18, 2016
    • Hi Ignasi,
      you are right, it is a really great opportunity for you! 🙂
      You can use my extension for sure, I’ve just sent an email to you.
      Good luck, and have a nice day!

      Mattia FortunatiFebruary 19, 2016
  • Thank you very much! this is very useful.
    I don’t know a thing about Java or Android but I want to get some sensors from the Phone, I have been reading everywhere and i noticed that this is not a common topic!

    Thanks for sharing this, I would like to ask you how to get information from the cellphone’s gyroscope and Accelerometer.

    Esteban Devia BedoyaSeptember 19, 2016
  • Hi Mattia, thank you for the tutorial. I am planning to give AppGratis a try too. Your tutorial is the only source of help i can get so far. Shamefully, i can’t seem to understand fully how the extension is built due to my extremely low knowledge on programming.

    I downloaded the extension. However i had an error while compiling into apk:
    —————
    > Lint found errors in the project; aborting build.

    Fix the issues identified by lint, or add the following to your build script to proceed with errors:

    android {
    lintOptions {
    abortOnError false
    }
    }

    ——————-
    I am using 1.4.1760. this is my android export setting :http://lekchan.com/wp-content/uploads/2016/09/global_game_setting.jpg

    When i compile without the batchSimpleFeatureEx extension, the apk built without prob.

    Hope you can help me with this. I would really like to give Appgratis a try.
    Thank you.

    lekNovember 25, 2016
  • Hi Mattia, just to add on, after reading your other post about lint error. I checked on the lint_debug.html and found the error shown like such : https://postimg.org/image/tq5synx0n/

    but the weird thing is, my min SDK is already set to 9. (as shown in http://lekchan.com/wp-content/uploads/2016/09/global_game_setting.jpg)

    lekNovember 25, 2016
    • Hi Lek, yes, I made a separated post about how to fix lint errors, thanks for checking it 🙂
      Just as a reference for other developers, the post we are talking about is here:
      http://www.mattiafortunati.com/game-maker-studio-tutorial-how-to-fix-lint-errors-while-building-for-android/

      About your issue, I cannot see the first image you posted but I can imagine it says something like “requires API level 11 (current min is 9)” because I’m pretty sure that my extension requires API level 11.

      Simply try to set “Min SDK” to “11” instead of “9” and it should work properly.

      Also please, let me add a note for you: this AppGratis extension is pretty old and I’m not keeping it updated with the newer Game Maker Studio versions.
      It still works perfectly for a lot of developers, and it is open-source, so I left it there on the store. It should work fine for you too, but, just in case, if it does not, feel free to change and fix its Java source code as you please.

      Cheers!

      Mattia FortunatiNovember 26, 2016
  • Noted, I will check on that.
    Thank you so much for your effort.
    Hope you will create more tutorial on building native extension for GM:S. There are hardly any tutorial for this at the moment.

    lekNovember 26, 2016
  • I have the opportunity to get my game featured on Appgratis! I’m so excited, but they want me to implement Batch in it. I found your extension, but it isn’t working for me. I know it may just simply not work anymore, which would be terrible, as I have zero knowledge of Java and couldn’t fix it. I have a feeling, though, that I may just be doing it wrong.

    I’ve put all the code where your extension says to put it and set up Batch online as Appgratis said to, but when I hit my gift button in my game, it shows the popup (searching for an offer…), and it doesn’t do anything. The Batch console doesn’t report any connection with the device, and the game doesn’t find the offer.

    Please help, this Appgratis feature will be huge for me if I can only get it to work.

    Casey RobertsonJanuary 3, 2017
    • Hi Casey,
      don’t worry.
      I’ve just made a test with my Alpaca Jump and it seems that the extension is already working correctly with batch.com offers 🙂
      So, let’s try to understand why it is not working for you.
      So, if the popup appears it means that the first setup is ok, so you may have missed something within the callback code, or on batch.com dashboard.

      Let’s see if I can help you:
      1) Be sure that you are using a Social Async Event and that there actually is an instance of the object waiting for it on the game room when the popup opens.

      2) Understand this code:
      var type = string(async_load[? “type”];) //this will always be "batchFeature" in this case var reference = string(async_load[? “reference”];) //this will be the the REFERENCE set for the ITEM of the CAMPAIGN set within the batch dashboard. You can edit/add items from settings > unlock on your batch dashboard. In this case I've set the REFERENCE of the items as "FREE_VERSION" on my batch dashboard. if (type == “batchFeature”){ //check if the Async event is actually called by my Java extension //feature offer received if (reference == “FREE_VERSION”){ //check if the REFERENCE matches. //unlock the free version //put your unlocking code here }

      3) Let’s review the process on your Batch.com dashboard.
      First of all, please use the LIVE API KEY of your app when calling batchSetup(“API_KEY”). It’s easier. You can find it on settings > integration on your dashboard.
      Now do this: unlock > new unlock campaign > run a 24h promo (name does not matter)
      So when it asks “What is your campaign going to unlock?” select the item you want with the correct REFERENCE (name does not matter). Again you can set items from settings > unlock.
      “What day is your campaign going to run?” Select a date (today for testing) and “Add a +/- 12 hours margin”.
      Now, “Target all users” or “Target new users”? For testing purpose use the first one, or if you prefere use “Target new users” but so you’ll have to uninstall and re-install your app every time you want to make a test.
      Choose “Automatic”.
      “Do you want to display a message on unlock?” NO. This will be up to your GM code.
      Save.
      Activate the PROD switch. It will become green.
      Alright, this way it should be set properly. I’ve tested it two times this morning 🙂

      4) Please keep in mind that you can unlock the offer JUST ONE TIME on a specific device. So, if you are making tests, you will have to CREATE A NEW CAMPAING for each test!

      5) Also, it’s written above but I’ll write it again, don’t forget these things:
      if you are using a DEV API KEY, just set the offer as “DEV” and leave the “LIVE” option off.
      if you want to reset dev redeemed offers use edit > reset redeemed dev codes. And Save offer.
      if you click edit > reset and the edit again to go into other options, the reset WON’T BE SAVED.
      The required bundled id is a list of app packages name that needs to be installed on the user’s device or the offer won’t be received.
      Finally, don’t forget to put the “LIVE” option ON!

      6) As a last but very important thing, when you don’t understand what’s wrong with your code, it is VERY BAD.
      It applies always for any code and it might happen sometimes when you are working with other people code!
      So, the best thing you can do, ALWAYS, is to LOG, LOG any value, variable or anything that may be important to understand what’s wrong. In this case LOG to see what you receive, when, how, what’s written on the vars, so you can understand what you are missing.
      It’s a simple and basic things but often people forget the importance of LOGS.
      So, since logging things with Game Maker + Android can be really painful (since you don’t have an actual function for logging on Android with Game Maker), I’ve created a simple and easy extesion for this purpose, too!
      You can find it here: http://www.mattiafortunati.com/game-maker-studio-android-native-extension-log-to-console/
      It’s totally FREE and really easy to use, and it will log directly into the Android console which is opening when testing.

      And … that’s all!
      Review your code and Batch dashboard setup and log a lot to know what’s wrong 🙂

      I hope this can help you!
      Cheeeers! 😀

      Mattia FortunatiJanuary 4, 2017
  • May 21, 2017

    […] even if the extension won’t work anynore, the tutorial page http://www.mattiafortunati.com/tutorial-creating-a-simple-game-maker-studio-native-android-extension&#8230; and the source code will always work as a cool tutorial for creating your own Game Maker […]

Leave a Reply to Casey Robertson Cancel reply

%d bloggers like this: