Implementing OpenFeint with Android

November 10, 2011 in Programming

UPDATE

Since this has become one of our more popular pages I just wanted to update it to say that UPSAT has now launched! If you find this page useful or just want to see some of the cool things we did with OpenFeint, including custom notifications, then please consider supporting us by getting the full version of UPSAT and by following us on Facebook or Twitter!

UPDATE

So you have an amazing Android game and you’ve decided you want to join the 21st century and add social connectivity? Well kudos and welcome to the party!

If you’re reading this then you’re probably at least somewhat interested in OpenFeint and what is entailed in getting this working with your game. The good news is it’s actually really easy. The bad news, since OpenFeint is relatively new on Android, the documentation can be a bit lacking which makes the task SEEM very daunting. I have to admit that I was a little bit nervous about doing this before I started, but in the end it only took me around 5 hours. So, if you have any coding skills whatsoever (unlike myself) then you could probably get it done in less. I’ve decided to write this little tutorial to help future users who find themselves running into the same problems as I did and to begin chipping away at the community support void that OpenFeint for Android is currently experiencing.

IMPLEMENTATION SPECIFICS

Since my game was created using the Android SurfaceView class and not OpenGL, I can’t attest as to the viability of this tutorial in other situations. That being said, the fundamentals should still be the same for any multi-thread gaming environment. At it’s core, Android is just Activities and Views, and both GLSurfaceView and SurfaceView classes are just views that operate on separate threads. So if you’re using something besides the regular SurfaceView class, don’t stop reading, this information could still prove useful. I’m running Windows 7 and using Eclipse 3.7.0. I’m going to focus on Step 4 of the getting started with OpenFeint tutorial from the developer support site, as steps 1-3 are essentially repeated here.We’re also going to assume you already have your project in Eclipse.

GETTING STARTED: IMPORTING OPENFEINT

I’m going to go ahead and skip steps 1-4 on this page because it’s all pretty self explanatory. If you can’t figure that out then I don’t think any number of tutorials will help you. So our first task is actually getting OpenFeint imported into your workspace. You’ll want to make sure you download and extract the OF SDK to somewhere convenient. I put mine in the same location as my Android SDK. To import the API’s follow these steps

  1. Right-click on your project in the project or package explorer
  2. Click Import.
  3. On the following screen select General and then click Existing Projects into Workspace..
  4. Click Next.

    OpenFeint tutorial Import Window

  5. Click on Select Root Directory and then Browse
  6. Browse to the directory in which the OpenFeintAPI and GameFeed libraries are stored.
  7. Click OK.

    OpenFeint Tutorial Import Projects

  8. Click the checkboxes for GameFeed and OpenFeintAPI. If you’ve already imported the projects they will be grayed out as is shown here
  9. Select Copy projects into workspace
  10. Click Finish.

OpenFeint Tutorial Projects Imported

You should now see the two projects in your package/project explorer. If they are not there, try deleting them out of your workspace through Windows Explorer and then following the steps above. If your images don’t look exactly like mine, that’s ok. I have some of my files in SVN repositories so they display a little differently.

BUILDING AND SETTING UP THE PROJECT

Next we need to verify that the projects have been built and that both projects are classified as libraries. This part seems to be the main area of confusion and I had the most trouble here. From reading other forums, it seems as though, depending on how you perform the import, the files may automatically be classified as libraries, in which case your project would be fine. If this doesn’t happen then you will start seeing errors as you actually implement the API into your code. It’s best just to perform these quick verification steps to be safe.

  1. In the top menu bar, select Project and then check to see if Build Automatically is selected. If it is, go to the next step. If it’s not, then select Build All and then select Build Automatically 

    OpenFeint Tutorial Build Projects

  2. Right click on the OpenFeintAPI project in the project explorer and select Properties
  3. In the window that appears select Android and then make sure Target is set to Android 1.6 and Is Library is selected as well. I had issues with the project being set to anything besides 1.6, but if it works for you then that’s fine too.

    OpenFeint Tutorial Properties Setting

  4. Click OK
  5. Follow steps 2 -4 for the GameFeed project in the project explorer
  6. Right click on your game project in the project explorer and select Properties
  7. On the Android tab make sure Is Library is NOT selected.
  8. Click Add and then select both the GameFeed and OpenFeintAPI projects and select OK. You should now see the two references with green check marks.
  9. Click OK to close the window.

Your project is now set up and you’re ready to begin coding. At this point you shouldn’t have any errors. If you do then please retry all the steps and if you are still having issues feel free to comment here and I will try to help you out.

INITIALIZING OPENFEINT IN YOUR GAME

“Ladies and Gentleman, Boys and Girls…. It’s time for the MAAAAAAIIIINNNNN Event!” This is the part you’ve no doubt been waiting for. Before we get started I want to take a minute to explain my setup and how I’ll be implementing the code. Simplifying greatly, my project consists of one Activity (AndroidGame) which is the UI thread and one SurfaceView( Screen) which is the worker thread where I perform all my game logic and rendering. Through some trial and error coding, I found that the OpenFeint methods have to be called from within an Activity class or context and not a view (or SurfaceView for that matter). This means that as far as I know, the calls must be made from the UI thread. I also found some apparent errors in the code given on the OpenFeint developers site and will point these out to you.

The first few steps for editing the Android Manifest file are pretty straightforward:

  1. Edit the AndroidManifest.xml file in your project:
    • Add the following activities inside your <application>tag:
      <activity android:name="com.openfeint.internal.ui.IntroFlow"
        android:label="IntroFlow"
        android:configChanges="orientation|keyboardHidden"
        android:theme="@style/OFNestedWindow"/> <activity
        android:name="com.openfeint.api.ui.Dashboard"
        android:label="Dashboard"
        android:configChanges="orientation|keyboardHidden"
        android:theme="@style/OFNestedWindow"/>
      <activity android:name="com.openfeint.internal.ui.Settings"
        android:label="Settings"
        android:configChanges="orientation|keyboardHidden"
        android:theme="@style/OFNestedWindow"/>
      <activity android:name="com.openfeint.internal.ui.NativeBrowser"
        android:label="NativeBrowser"
        android:configChanges="orientation|keyboardHidden"
        android:theme="@style/OFNestedWindow"/>
    • Add the following permissions to AndroidManifest.xml outside of your tag:
       <uses-permission android:name="android.permission.INTERNET" />
    • To grant OpenFeint the ability to save data in the /sdcard/, which is faster and uses less of the user’s built-in flash memory, add the following to the AndroidManifest.xml:
       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    • To allow OpenFeint to retrieve the logged-in user’s email address from Phone SDK version 5 or above so that the user does not have to type the email address in when creating an account, add the following to the AndroidManifest.xml:
      <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    • To allow OpenFeint to detect network connectivity state, which will allow it to notify the user when they can’t login (instead of taking many seconds to time out), add the following to the AndroidManifest.xml:
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  2. Refresh (File->Refresh) the project so that the items you added appear.

If you’ve successfully completed everything, then your Manifest file should build with no errors. If you get an error with the “@style/OFNestedWindow” line, then you need to go back and make sure that the OpenFeint API’s are both libraries and that they are both referenced in your project.  Next we need to set up the variables that let the OpenFeint network know what game this is. You’ll do this in the main Activity of your game wherever the OnCreate() method is called. You’ll want to define these as variables outside of the onCreate() method and then use them to instantiate the settings.

  1. Import the following packages into your file:
    import com.openfeint.api.OpenFeint;
    import com.openfeint.api.OpenFeintDelegate;
    import com.openfeint.api.OpenFeintSettings;
    import com.openfeint.api.resource.Achievement;
    import com.openfeint.api.resource.Leaderboard;
    import com.openfeint.api.resource.Score;
    import com.openfeint.api.ui.Dashboard;
    import android.widget.Toast;
  2. Define  the following variables in the class definition replacing the words in quotes with the values as defined on the OpenFeint developer site:
    static final String gameName = "Name of your application";
    static final String gameID = "gameID";
    static final String gameKey = "gameKey";
    static final String gameSecret = "gameSecret";
  3. Use these variables to construct the settings object in the OnCreate() method:
    OpenFeintSettings settings =
      new OpenFeintSettings(gameName, gameKey, gameSecret, gameID);
  4. Initialize OpenFeint by calling the following method:
    OpenFeint.initialize(this, settings, new OpenFeintDelegate() {});

    The openfeint support states that this must be called in the OnCreate() method, but in reality the only requirement is that it is called after creating settings and before calling any other OpenFeint methods. It is therefore a good idea to call this as soon as possible because OpenFeint will need to connect to it’s network before you can do anything else. If you’re using a loading screen it may be a good idea to call this just before that screen to give OpenFeint time to connect while your game is loading resources.

    Here is how I implemented all of the above:

    public abstract class AndroidGame extends Activity implements Game {
        AndroidFastRenderView renderView;
        Graphics graphics;
        Audio audio;
        Input input;
        FileIO fileIO;
        Screen screen;
        WakeLock wakeLock;
        static final String gameName = "UPSAT";
        static final String gameID = "391633";
        static final String gameKey = "abcdefghijklmnop";
        static final String gameSecret = "ajlassdkgjhdsgo944098shdkghsodg890sdjhg";
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            OpenFeintSettings settings =
                      new OpenFeintSettings(gameName, gameKey, gameSecret, gameID);
            OpenFeint.initialize(this, settings, new OpenFeintDelegate() {});
  5. Run your game!

If you’ve done everything right then the first time you run your game you should see something like this:

OpenFeint Tutorial Initialized

OpenFeint Tutorial Initialized

CONGRATULATIONS! You have now successfully implemented online connectivity into your game. Every time you log in after this you will no longer see this screen and instead will see a pop-up saying welcome back.

IMPLEMENTING OPENFEINT FEATURES

Now we get to the fun stuff. Yes you have online functionality, but unfortunately you have no way to get to it. We need to add code into our game to unlock achievements, post high scores, and then open the dashboard so the user can edit their profile, sign on/off, and of course, be social!

Since all of my game logic is performed in the SurfaceView thread, I needed to have an easy way to make OpenFeint calls on the UI thread. The easiest way for me to do this was to create several public methods in my AndroidGame activity that could be called from the SurfaceView when OpenFeint activities needed to occur. This also makes implementation into an existing game a breeze because it keeps all the lengthy OpenFeint calls to leaderboards and achievements in one place and then all I need to do is add one line of code throughout the game when necessary.

We’ll start with the dashboard because that is the easiest thing to implement.

  1. Add the following line to the code in your main Activity where you’d like to call the dashboard:
    Dashboard.open();

BOOM! That’s it! It’s that easy. I was amazed too. 17 simple characters and your players will be socializing like it’s their job. From the dashboard the players can check their wall, meet up with friends, and check their achievements and leaderboards. It’s pretty awesome.

My code looked something like this once it was wrapped in a method in my AndroidGame activity:

public void openDashboard(){
        Dashboard.open();
    }

And then the call from anywhere on my SurfaceView thread becomes:

game.openDashboard();

Where “game” is an instance of my AndroidGame class.

Next up is the second easiest thing; posting a score to the leaderboards.

  1. Add the following snippet to the code in your main Activity where you’d like to post a score:
    long scoreValue = longScoreValue;
    Score s = new Score(scoreValue, null); // Second parameter is null to indicate that custom display text is not used.
    Leaderboard l = new Leaderboard("leaderboardID");
    s.submitTo(l, new Score.SubmitToCB() {
      @Override public void onSuccess(boolean newHighScore) { 		// sweet, score was posted
        MyClass.this.setResult(Activity.RESULT_OK);
        MyClass.this.finish();
      }
      @Override public void onFailure(String exceptionMessage) {
        Toast.makeText(MyClass.this, "Error (" + exceptionMessage + ") posting score.", Toast.LENGTH_SHORT).show();
        MyClass.this.setResult(Activity.RESULT_CANCELED);
        MyClass.this.finish();
      }
    });
  2. Replace “longScoreValue” with the players score you’d like to post
  3. Replace “leaderboardID” with the number of a leaderboard you created on the OpenFeint developer website
  4. Replace “MyClass” with the name of the Activity containing the code

This one is a bit trickier and I came across an issue here with the “MyClass.this.finish();” command. This is a call to close the Activity. Now I don’t understand why this was included in here, but chances are if you’re implementing this into an already created game, then you have some other method that will close the activity when it is ready. Deleting these two lines will do no harm and my implementation works fine:

public void postLeaderboard(int score){
        long scoreValue = (long) score;
        Score s = new Score(scoreValue, null); // Second parameter is null to indicate that custom display text is not used.
        Leaderboard l = new Leaderboard("977406");
        s.submitTo(l, new Score.SubmitToCB() {
          @Override public void onSuccess(boolean newHighScore) {         // sweet, score was posted
            AndroidGame.this.setResult(Activity.RESULT_OK);
          }
          @Override public void onFailure(String exceptionMessage) {
            Toast.makeText(AndroidGame.this, "Error (" + exceptionMessage + ") posting score.", Toast.LENGTH_SHORT).show();
            AndroidGame.this.setResult(Activity.RESULT_CANCELED);
          }
        });
    }

As you can see I’ve wrapped the code in a method in my AndroidGame activity again and passed in an int score variable which I then convert to a long as it is required by the OpenFeint code. I can then call this method from the SurfaceView thread as follows:

game.postLeaderboard(gameStatus.overallScore);

If a new highscore is indeed achieved then a neat message pops up alerting the user as follows:

OpenFeint High Score Message in UPSAT

We have yet to rearrange any of our UI or fix things up aesthetically, but because this is all contained within the OpenFeint library, it is possible to reformat these message to make them fit the style of your game.

Finally, the trickiest thing to figure out was posting an Achievement. Although the code itself is very similar to the previous example, I believe I found a typo in the online support which made this quite frustrating. The code below originally did not call for a boolean in the arguments of the OnSuccess() class. I spent some time trying to figure out where this boolean was supposed to come from and what it was referencing, but in the end I just decided to throw in a generic boolean variable and everything works smoothly now. The corrected implementation is used here.

  1. Add the following snippet to the code in your main Activity where you’d like to post an achievement:
    new Achievement("achievementID").unlock(new Achievement.UnlockCB () {
      @Override public void onSuccess(boolean bool) {
        MyClass.this.setResult(Activity.RESULT_OK);
        MyClass.this.finish();
      }
      @Override public void onFailure(String exceptionMessage) {
        Toast.makeText( MyClass.this, "Error (" + exceptionMessage + ") unlocking achievement.",Toast.LENGTH_SHORT).show();
        MyClass.this.setResult(Activity.RESULT_CANCELED);
        MyClass.this.finish();
      }
    });
  2. Replace “achievementID” with the number of an achievement you created on the OpenFeint developer website
  3. Replace “MyClass” with the name of the Activity containing the code

Again, you can choose to delete the two “finish()” lines if you do not want the activity to end after posting the achievement. My implementation is as follows:

public void postAchievement(int ID){
        new Achievement(String.valueOf(ID)).unlock(new Achievement.UnlockCB () {
              @Override public void onSuccess(boolean bool) {
                AndroidGame.this.setResult(Activity.RESULT_OK);
              }
              @Override public void onFailure(String exceptionMessage) {
                Toast.makeText( AndroidGame.this, "Error (" + exceptionMessage + ") unlocking achievement.",Toast.LENGTH_SHORT).show();
                AndroidGame.this.setResult(Activity.RESULT_CANCELED);
              }
            });
    }

I’ve also wrapped this code in a method in the AndroidGame activity which takes an int ID as an argument to tell us which Achievement to unlock. I then call the following code whenever I decide that an achievement has been unlocked:

game.postAchievement(1348322);

Where the number is the achievement id from the OpenFeint developer site. If you’ve done it correctly then you should see a pop-up like this when the achievement is unlocked:

OpenFeint Tutorial Achievement Unlocked UPSAT

CLOSING ARGUMENTS

That’s it. If you’ve made it this far then hopefully you now have a fully working implementation of OpenFeint. Also, you must REALLY like to read. There is still a little bit more to do with GameFeed and editing the theme of the popups, but I’ll leave that for another day. This wall of text will crumble under it’s own weight if I add any more. All in all I found the integration of OpenFeint into our game to be EXTREMELY easy and even – GASP – enjoyable! I hope you found this post informative and that you’ll consider sticking around and reading some of the other stuff we have here about designing our game. If you come across any other questions then please feel free to comment here or on facebook or twitter!