How to setup Google Play Game Services in LibGDX using Android Studio

Hands down, one of the most nerve wracking API integration I’ve ever done! Mostly due to the jargon-filled Google documentation and the lack of  libGDX-specific tutorials. Hopefully, this post would give you more clarity to implement the same.

1) Create a new Game Service

Head over to your dashboard and select Game services

Note: You don’t need to have your game added under All applications in order to test Play Services.

Click on Add new game. Choose I don’t use any Google APIs in my game yet tab and Fill out your game name and category.

  • Game details: Make sure to fill in all mandatory fields like description, graphic assets etc.
  • Linked apps: Choose Android, fill in the package name ( This package name should match with the one in your AndroidManifest file ) To properly authorize your app, follow my guide
  • Events: This is not mandatory, leave it for now.
  • Achievements: It is mandatory that you have at least 5 achievements in your game. If you don’t plan on having them just leave them unimplemented in your game but make sure to fill these up and obtain the tick mark.
  • Leaderboards: You can add as many leaderboards as you want depending upon your game.
  • Testing: Make sure you have filled in all the necessary fields and the game service is ready to be tested. Add testers: Only the users you specify will be able to use the game service when it is unpublished, make sure to add an account other than your dev account as the dev account may not work sometimes.
  • Publishing: It’s better to publish it with the whole game when it’s ready. You can still test all the features with the test accounts.

 

2) Install Play Services packages

Untitled-9

Open up SDK Manager in Android Studio, ( Click the button next to the AVD manager in the top toolbar ) click Launch Standalone SDK Manager

Scroll down to the Extras section and make sure these 2 packages are installed and updated to the latest :

  • Google Play services
  • Google Repository

 

3) Add BaseGameUtils Library

Didn’t we just add the Play services packages, what is this for?

This repository contains a lot of sample projects including libraries, each one implementing a different play service. So that means they’ve written all the code  for you! You don’t have to talk to the API and handle all those lousy exceptions, you just have to add it as a library module for your project and call the necessary methods. Good job Google 😀

Here’s the repository, Clone it or Download it as ZIP.

Extract it inside your project folder. Inside the extracted folder, open the  BasicSamples folder and you’d find all the sample projects. These are only for reference, you essentially need the libraries folder.

Open Android Studio, goto File > New > Import Module

Point the Source directory to BasicSamples\libraries\BaseGameUtils

 

4) Add dependencies

Now that we’ve added all the necessary packages and libraries, we need to explicitly tell our build system ( Gradle ) to compile them. In the project tree on the left, under Gradle Scripts,

Open the build.grade(Project: <Project name>) file, add these 2 lines

project(":android") {
    ...
    dependencies {
        ...
        compile 'com.google.android.gms:play-services-games:8.4.0'
        // 8.4 is the latest as of now, keep it updated
        compile project(':BaseGameUtils')
        ...
    }
    ...
}

If you are using other play-services APIs, add them in the dependencies list. But if the number of method references in your app exceeds the 65K limit, your app may fail to compile, in that case you need to enable multidex support.

Open the build.gradle(Module: android) file, add these 2 lines

android {
    defaultConfig {
        ...
        multiDexEnabled true
        ...
    }
}

dependencies {
  ...
  compile 'com.android.support:multidex:1.0.0'
  ...
}

Let Gradle sync the project.

 

5) Update Android Manifest

We’ve linked our project with the play services api, but our game still doesn’t know which game service to connect to and obviously the game would have to access the google play game servers over the internet. For that, in the Android Manifest file, we need to pass in the details of our game service and obtain permission to access the internet.

Go back to your dashboard. Open up Game services > Leaderboards and click on Get resources. This will pop-up a window with XML content, copy  it. Inside your android Project, go to res > values and create a new Values XML File, name it ids and paste the contents inside it. It’ll look something like this.

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="app_id">767948611622</string>
  <string name="achievement_dum_dum">CgkIpsC36qwWEAIQAw</string>
  <string name="leaderboard_highest">CgkIpsC36qwWEAIQAA</string>
</resources>

Open up AndroidManifest.xml and add these 4 lines

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    ...
    <application>
        ...
        <meta-data android:name="com.google.android.gms.games.APP_ID" android:value="@string/app_id" />
        <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
    </application>
    ...
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

 

6) Implementation

Now that everything is set up, we are ready to implement play services. Since all our game classes are inside the libGDX core project, we can’t directly call these methods because these are Android methods. So we create an interface inside our core project and implement this interface inside the Android Project. Makes sense ?

So inside the core Project, create a new interface and call it PlayServices. In this example we will implementing these basic play game services.

public interface PlayServices
{
    public void signIn();
    public void signOut();
    public void rateGame();
    public void unlockAchievement();
    public void submitScore(int highScore);
    public void showAchievement()
    public void showScore();
    public boolean isSignedIn();
}

Inside the android Project, open up the default Activity, in my case it is called AndroidLauncher.java

Declare these 2 members inside the class

private GameHelper gameHelper;
private final static int requestCode = 1;

Inside the onCreate() method, initialize these members

gameHelper = new GameHelper(this, GameHelper.CLIENT_GAMES);
gameHelper.enableDebugLog(false);

GameHelper.GameHelperListener gameHelperListener = new GameHelper.GameHelperListener()
{
    @Override
    public void onSignInFailed(){ }

    @Override
    public void onSignInSucceeded(){ }
};

gameHelper.setup(gameHelperListener);

Now we want play services to start automatically when the game begins and stop when the game exits, also we need to handle exceptions when the user fails to sign in. This is where the BaseGameUtil libraries come in, it takes care of all this, we just have to override our Activity methods and pass it on to them.

 @Override
    protected void onStart()
    {
        super.onStart();
        gameHelper.onStart(this);
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        gameHelper.onStop();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);
        gameHelper.onActivityResult(requestCode, resultCode, data);
    }

Now, let’s implement the interface we created.

public class AndroidLauncher extends AndroidApplication implements PlayServices

Define the implemented methods like this.

    @Override
    public void signIn()
    {
        try
        {
            runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    gameHelper.beginUserInitiatedSignIn();
                }
            });
        }
        catch (Exception e)
        {
             Gdx.app.log("MainActivity", "Log in failed: " + e.getMessage() + ".");
        }
    }

    @Override
    public void signOut()
    {
        try
        {
            runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    gameHelper.signOut();
                }
            });
        }
        catch (Exception e)
        {
            Gdx.app.log("MainActivity", "Log out failed: " + e.getMessage() + ".");
        }
    }

    @Override
    public void rateGame()
    {
        String str = "Your PlayStore Link";
        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(str)));
    }

    @Override
    public void unlockAchievement()
    {
        Games.Achievements.unlock(gameHelper.getApiClient(),
         getString(R.string.achievement_dum_dum));
    }

    @Override
    public void submitScore(int highScore)
    {
        if (isSignedIn() == true)
        {
            Games.Leaderboards.submitScore(gameHelper.getApiClient(),
             getString(R.string.leaderboard_highest), highScore);
        }
    }

    @Override
    public void showAchievement()
    {
        if (isSignedIn() == true)
        {
            startActivityForResult(Games.Achievements.getAchievementsIntent(gameHelper.getApiClient(),
             getString(R.string.achievement_dum_dum)), requestCode);
        }
        else
        {
            signIn()
        }
    }

    @Override
    public void showScore()
    {
        if (isSignedIn() == true)
        {
            startActivityForResult(Games.Leaderboards.getLeaderboardIntent(gameHelper.getApiClient(),
             getString(R.string.leaderboard_highest)), requestCode);
        }
        else
        {
            signIn()
        }
    }

    @Override
    public boolean isSignedIn()
    {
        return gameHelper.isSignedIn();
    }

But how can the core Project reference these methods ? For that we need to pass an object of this activity to the core Project class. Here MainGame is my core Project class, I’m passing an object of AndroidLauncher which is my default Activity.

initialize(new MainGame(this), config);

Now inside the MainGame class, we create a constructor to pass this reference to the interface PlayServices

public static PlayServices playServices;

public MainGame(PlayServices playServices)
{
    this.playServices = playServices;
}

My MainGame class has minimal functionality, it only sets the MainMenu screen, and I want to be able to call the PlayServices functions from the MainMenu screen. To do that, pass the object of MainGame when you set the screen.

setScreen(new MainMenu(this));

In the MainMenu class, create an object of MainGame and use a constructor to pass this reference

public static MainGame game;

public MainMenuScreen(MainGame game)
{
    this.game = game;
}

Now using this object you can call any of the PlayServices interface methods like this.

game.playServices.signIn();
game.playServices.signOut();
game.playServices.rateGame();
game.playServices.unlockAchievement();
game.playServices.submitScore(score);
game.playServices.showScore();
game.playServices.showAchievement();
game.playServices.isSignedIn();

 

If you have any doubts, leave them in the comments section below.

Advertisements

How to obtain SHA1 Signing certificate fingerprint from Android Studio

Untitled-8

I’m pretty sure that looking at this pop-up for the first time would be intimidating. This is a simple method to extract the SHA1 fingerprint right from Android Studio without using keytool. If you have no idea what I’m talking about, read along and understand the whole process.

Steps to obtain the SHA1 fingerprint is at the end of this post.

 

What is a signing certificate ?

268751

Android requires that all apps be digitally signed with a certificate before they can be installed. Think of it like labeling your app as your own. You make a label with your name and stick it on your app, this ensures you are the rightful developer of the app. Only with the same signing certificate you can roll out future updates for your app, and for that reason you should never lose this certificate.

To further protect your app, this certificate is coupled with a digital key so that it remains reasonably unhackable.

 

What is a key store ?

The key store is basically a file containing all your cryptographic keys. All your certificates and corresponding keys are saved in this file encrypted.

There are 2 types of keystores

  1. Debug key store : This key store is generated by the Android SDK so that you don’t have to sign the app each time you deploy it for testing.
  2. Release key store : However you cannot use the debug key store when you want to publish the app. You have to generate your own release keystore and sign your app with a release key to publish your app.

 

How to create a release key  ?

Open up Android Studio. Goto Build > Generate Signed APK

First let’s create a new key store. Click on Create new

Untitled-5

A new dialogue box pops-up.

Untitled-6

Key store path: Make sure you give a secure location. You do not want to lose it. I repeat, you do not want to lose it!

Key store Password: This password is for the key store file, remember you can use the same keystore for storing all your keys for your various app(s). So this is like a master password.

Key Alias: Name this as <your app name>+’Key’ or something. This is specific to this signing key for this app. ( This is the equivalent of a  key in a hashtable )

Key Password: This password is specific to this signing key for this app. You can very well use the same password used for the keystore.

Validity: Give it say, 100 years!

Certificate: You are required to fill in at least one entry in this.

Click OK and proceed with the build.

Untitled-7

Make sure you choose the Build Type as release and click Finish

 

Deploy in release mode

Untitled-9

The release key signed APK is generated, but this does not deploy it on the device/emulator like it normally would. To do that, Goto File > Project Structure

In the left, under Modules, choose android

Untitled-10

Choose the Signing tab, click on the green + button and fill in the details, which you gave when you created the release key. The default configuration name is config. Let it be.

Go to Build Types, Choose release

Untitled-14

In the Signing Config option, choose config. Click on OK.

To use the release signing key when deploying the app, click on the tiny square found at the bottom left of Android Studio and choose Build Variants

Untitled-13

In the Build Variants sidebar, choose release. From now on, whenever you deploy the app, the signed version  with your release key is pushed on to the device/emulator.

But when you deploy it for the first time, you will encounter this error.

Untitled-18

This is because of the conflicting signatures for the same package. Click on OK and the release build will be pushed.

 

What is a SHA1 fingerprint ?

SHA1 stands for Secure Hash Algorithm One. A one-way cryptographic function that can be used to act as a ‘signature’ for a sequence of bytes. It is very unlikely that 2 different byte sequences would produce the same value (though not impossible). So instead of shipping the app with the entire key store and uploading a copy of it to the playstore, we use this cryptographic signature to easily validate the authenticity. Read more about SHA1 here.

 

Obtain the SHA1 fingerprint

Important : Run your app in release mode once before proceeding.

Click on Gradle ( or SBT ) found on the top right of Android Studio. First time you open it, it’ll be blank, click on the refresh button and it’ll list the name of your project ( My project name is Segments ).

Untitled-15

Expand the tree like this and double click on Signing Report

Untitled-16

Voila! you find the SHA1 fingerprint of both the release key and the debug key.

Untitled-17

You can even use the debug key SHA1 for testing Google API services. Just make sure that the app accessing this API is signed with the same key as that provided to authorize the app.

 

An unexpected error occurred. Please try again later. (480000x)

You might get this error when you submit the SHA1 fingerprint, this happens when you use the same fingerprint+package combination as a new linked app. Go to your developer console and delete any duplicates projects that you may find. Deletion takes 7 days though.