Zippy
Zippy

Reputation: 3887

Handling Google Play Game Achievements when player isn't logged in

I'm using Google's Achievements API for the first time and have found it fairly simple to set-up. I got it up and running in about an hour, however, one thing I just can't figure out, is how to go about unlocking achievements when the user isn't signed in (or rather storing the fact that achievement x has been unlocked locally so it can actually be unlocked when the user next logs in).

My achievements are unlocking OK if the user is signed in.

Initially, when I was testing this without being logged in, I was getting a 'googleAPIClient is not connected yet' error popping up in my LogCat.

So I did something like this:

public void unlockAchievements(){
    if (isSignedIn()){        
        Games.Achievements.unlock(getApiClient(), myAchievementID);
    }
}

This obviously avoids the crash, but (again, obviously), doesn't unlock the achievement if the user isn't yet signed in.

Is there an 'official' way the handle this (I can't seem to find any mention of this in the doccumentation - although I may have missed it).

If there isn't, what would be a good way to do this?

I could do something like:

if (score>1000){  
    score1000Achievement = true;  //Save this to SharedPreferences
}

And then later, do this:

onSignInSucceeded(){
    if (score1000Achievement){
        Games.Achievements.unlock(getApiClient(), myAchievementID);  
    }
}

However, this would run and attempt an unlock at every login, which, with multiple achievements and multiple users, would surely increase my API calls and therefore eat into my quota unnecessarily?

Grateful for any advise

Edit

Just found this on an Android Developers Site

An unlocked achievement means that the player has successfully earned the achievement. An achievement can be unlocked offline. When the game comes online, it syncs with the Google Play games services to update the achievement's unlocked state.

However, there seems to be no further mention of it and no example of how this is accomplished.

Upvotes: 2

Views: 2737

Answers (3)

VARUN ISAC
VARUN ISAC

Reputation: 443

It seems,there is no sufficient documentation. Well I have made some observations after some R&D works. May be it will be useful for someone.

  1. Network connectivity is needed for initial sign in.

  2. Initial "sign-in" creates a copy of the achievements locally.

  3. Whenever the application becomes OFFLINE (that is without network connectivity, but signed in), the application operates on the locally stored copy.

  4. Whenever the mGoogleApiClient connects with the google server via network again, it automatically updates the server, with locally, unlocked achievements.

Upvotes: 0

Narayan Acharya
Narayan Acharya

Reputation: 1499

I know it is late but still wanted to share my approach My approach was similar i.e. saving the states of all achievements to the SharedPreferences. But I did not use two booleans(according to Simon's answer) one to store and the achievement and other to check whether the achievement was unlocked on Google Play. Instead I used an int to store the state of the achievement.

For eg -1 meant the achievement was not unlocked yet, 0 meant it was unlocked and 1 meant that it was published to Google Play.

Here is a small snippet of code for reference.

public class AccomplishmentsOutbox {
    public static final int LOCKED = -1;
    public static final int UNLOCKED = 0;
    public static final int PUSHED = 1;

    private static final String PREFS_KEY_ACCOMPLISHMENTS = "player_accomplishments";
    // ACHIEVEMENTS
    private static String PREFS_KEY_ACH_1;

    // Singleton instance
    private static AccomplishmentsOutbox mOutbox;
    private SharedPreferences settings;

    private AccomplishmentsOutbox(Context mContext) {
        settings = mContext.getSharedPreferences(PREFS_KEY_ACCOMPLISHMENTS, Context.MODE_PRIVATE);

        // ACHIEVEMENTS
        PREFS_KEY_ACH_1 = mContext.getString(R.string.achievement_one);
    }
    public static AccomplishmentsOutbox getAccomplishmentsOutbox(Context context) {
        if (mOutbox == null) {
            mOutbox = new AccomplishmentsOutbox(context);
        }
        return mOutbox;
    }

    public int isOne() {
        return settings.getInt(PREFS_KEY_ACH_1, LOCKED);
    }

    public void putOne(int value) {
        settings.edit().putInt(PREFS_KEY_ACH_1, value).apply();
    }
}

Now when I wanted to check whether a achievement was unlocked in the Activity I used : This now saves the state in Shared Preferences.

AccomplishmentsOutbox mOutbox = AccomplishmentsOutbox.getAccomplishmentsOutbox(this);

if (corrected == 0) {
            mOutbox.putOne(AccomplishmentsOutbox.UNLOCKED);
}

Now when I am connected to Play Games then I simple check if the achievement is unlocked locally and then unlock it on Play Games.

if (isSignedIn()) {
            if (mOutbox.isOne() == AccomplishmentsOutbox.UNLOCKED) {
                Games.Achievements.unlock(mGoogleApiClient, getString(R.string.achievement_one));
                mOutbox.putOne(AccomplishmentsOutbox.PUSHED);
            }

All the best :) Hope it was helpful to someone.

Upvotes: 0

Simon
Simon

Reputation: 504

I did the same approach as you did, but I saved another boolean to know if the achievement was unlocked on Google play. Can't remember though, if the unlocking has a success-return value.

Upvotes: 1

Related Questions