Wednesday, February 6, 2013

Admob with Andengine

If you have a game developed with Andengine you probably don't use a XML layout file and your activity simply extends the BaseGameActivity class or the SimpleBaseGameActivity class.
I assume that you know hot to add the Admob jar to your project and to set the required permissions in the AndroidManifest file. If you don't, then check the tutorials on the Admob web site first.

The first thing you need to do is create a new XML layout file, let's call it game_layout.xml
The content of this file should be similar to the following:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    android:orientation="vertical" >

    <org.andengine.opengl.view.RenderSurfaceView
        android:id="@+id/SurfaceViewId"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:gravity="center" />

    <com.google.ads.AdView
        android:id="@+id/adViewId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        ads:adSize="BANNER"
        ads:adUnitId="YOU_ID_HERE"
        ads:loadAdOnCreate="true" />
    
</RelativeLayout>

In this case, the Layout is RelativeLayout, because we want the ad to be drawn over the game surface. Based on your requirements, you could try to use a other layouts, but i find the relative one to be the best. Inside the layout there are 2 components, the surface view and the ad view, each with it's own id (adViewId and SurfaceViewId). Also, don't forget to define the namespace for the Admob components, in my case "ads:".


Now that we have our layout file, we must include it in the activity. In a normal android application you could do this by calling setContentView(R.layout.game_layout);  in the onCreate method of the activity. In Andengine, we need to use a different approach.
I will assume that you extend the SimpleBaseGameActivity class because the first step you need to do is adapt the class to extend the BaseGameActivity class.
The class hierarchy for the activity classes in Andengine is presented in the following figure:


In order to display ads we must extend the LayoutGameActivity class.
Let's assume that you have the following class that extends the SimpleBaseGameActivity:
public class MainActivity extends SimpleBaseGameActivity {

  public static final int CAMERA_HEIGHT = 720;
  public static final int CAMERA_WIDTH = 480;

  private Camera camera;
  private BitmapTexture blocksTexture;

  @Override
  public EngineOptions onCreateEngineOptions() {
    this.camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
    EngineOptions engineOptions = new EngineOptions(true,
        ScreenOrientation.PORTRAIT_FIXED,
        new FillResolutionPolicy(), camera);
    return engineOptions;
  }

  @Override
  protected void onCreateResources() {
    try {
      this.blocksTexture = new BitmapTexture(this.getTextureManager(),
            new IInputStreamOpener() {
        @Override
        public InputStream open() throws IOException {
          return getAssets().open("gfx/block.png");
        }
      });
      blocksTexture.load();
      
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override
  protected Scene onCreateScene() {
    GameScene scene = new GameScene(blocksTexture, this);
    this.mEngine.registerUpdateHandler(scene);
    return scene;
  }

}

This is a minimalist class, with all the logic defined in the GameScene class, for the sake of simplicity.
After extending the LayoutGame class, the file will look like this:
public class MainActivity extends LayoutGameActivity {

  public static final int CAMERA_HEIGHT = 720;
  public static final int CAMERA_WIDTH = 480;

  private Camera camera;
  private BitmapTexture blocksTexture;

  @Override
  public EngineOptions onCreateEngineOptions() {
    this.camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
    EngineOptions engineOptions = new EngineOptions(true,
        ScreenOrientation.PORTRAIT_FIXED,
        new FillResolutionPolicy(), camera);
    return engineOptions;
  }

  @Override
  public void onCreateResources(
      OnCreateResourcesCallback pOnCreateResourcesCallback)
          throws Exception {
    try {
      this.blocksTexture = new BitmapTexture(this.getTextureManager(),
            new IInputStreamOpener() {
        @Override
        public InputStream open() throws IOException {
          return getAssets().open("gfx/block.png");
        }
      });
      blocksTexture.load();

    } catch (IOException e) {
      e.printStackTrace();
    }
    pOnCreateResourcesCallback.onCreateResourcesFinished();
  }

  @Override
  public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
      throws Exception {
    GameScene scene = new GameScene(blocksTexture, this);
    this.mEngine.registerUpdateHandler(scene);
    pOnCreateSceneCallback.onCreateSceneFinished(scene);
  }

  @Override
  public void onPopulateScene(Scene pScene,
      OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception {
    pOnPopulateSceneCallback.onPopulateSceneFinished();
  }

  @Override
  protected int getLayoutID() {
    return R.layout.game_layout;
  }

  @Override
  protected int getRenderSurfaceViewID() {
    return R.id.SurfaceViewId;
  }

}

There are 2 methods related to the layout file. The first method is getLayoutID, that must return the id of the file containing the layout. The other method is getRenderSurfaceViewID, that must return the id of the surface view.
The other methods simply do what the SimpleBaseGameActivity class does for the BasicGameActivity.

This is all you need to do in order to display ads in an Andengine game.

12 comments:

  1. How to implement it exactly with BaseGameActivity?
    Do i just need to add
    @Override
    protected int getLayoutID() {
    return R.layout.game_layout;
    }

    @Override
    protected int getRenderSurfaceViewID() {
    return R.id.SurfaceViewId;
    }

    in my gameactivity class which is extending BaseGameActivity?

    ReplyDelete
    Replies
    1. You need to extends LayoutGameActivity (which in turn extends BaseGameActivity).
      There you override the 2 methods that tell the layout and the game view.

      Delete
  2. changed my GameActivity extends from BaseGameActivity to extend LayoutGameActivity and added the 2 layout methods.
    The app is getting crashed now with following errors.

    03-08 18:00:00.968: E/AndroidRuntime(11035): java.lang.RuntimeException: Unable to start activity ComponentInfo{package/package.GameActivity}: android.view.InflateException: Binary XML file line #16: Error inflating class com.google.ads.AdView

    ReplyDelete
    Replies
    1. Make sure to add the admob activity in the manifest file.

      Delete
  3. Already did that.
    Infect I was using onsetcontentview method previously with FrameLayout.LayoutParams and it was showing the admob ads but the ads were coming of half height. And when i clicked on an ad went to the ad url then came back to the game by pressing back button the ad height was coming right. Tried to find solutions but nothing worked so thought of using this method.
    I was using BaseGameActivity which now I changed to LayoutGameActivity as you told me. But app is crashing.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Hi gulyan and thanks for your tutorial,

    I have the same error as rohit (Error inflating class com.google.ads.AdView, and I added the admob activity in the manifest file like this :

    activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"

    But it still doesn't work, and I don't know what to do to solve this.

    ReplyDelete
  6. Hey guys, there is an error, probably something changed cause this code snipped is a bit old. In game_layout.xml you chould change class location:

    from com.google.ads.AdView
    to com.google.android.gms.ads.AdView

    This helped me a lot. Everything else is fine.

    ReplyDelete
  7. I followed all the steps of this tutorial but I'm having a problem. There is a message in the ad: Required XML attibute "adSize" was missing.
    Can someone help?

    ReplyDelete
    Replies
    1. Hi Andre,

      Do have the solution for adSize issue?

      Delete