Lately I switched from Java based Android development to native C++ code and started using the famous cocos2d-x framework for implementing my second Android game Henhouse Trouble, that I released almost a year ago. At that time I had quite some trouble with interfacing third party Android libraries like the AdMob SDK. Finally, I managed to get a working solution based on this article. While the article was extremely helpful for me in getting my own solution up and running, considering that I have minimal experience with JNI, I thought that AdMob SDK integration is quite a common task to deserve its own easy to integrate cocos2d-x extension. In this article I’ll present a step by step guide on how to integrate AdMob advertisements into your cocos2d-x 2.x.x application using the extension.

I’ll first present the generic steps of AdMob integration that are also the prerequisites of setting up AdMob with cocos2d-x.

Step 1 – Adding the AdMob SDK library to your project

First, you have to add GoogleAdMobAdsSdk-x.x.x.jar to your project. In Eclipse you can do so by going to Project -> Properties -> Java Build Path, and then on the Libraries tab clicking on the Add JARs… button and then selecting the jar file in the file browser to add it to your project. In my projects I like to keep the jar file inside my source tree so you probably also want to first copy the file to your project’s libs folder before adding it to the project in the Eclipse GUI.

Step 2 – Setting up your AndroidManifest.xml

The second step is to set up your Android manifest file. In order for the AdMob SDK to be able to present the ads you have to add the following activity definition under your manifest/application element in the XML:

<activity android:name="com.google.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation"/>

Next, you have to declare the Android permissions that are needed for the SDK to work. At a bare minimum INTERNET and ACCESS_NETWORK_STATE permissions are required. You can request the permissions by adding the following two items under the manifest element in your XML:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

For some configurations you might need to add additional permission requirements to your application, but I’ll talk about it later.

Step 3 – Adding extension files to your project

The source tree of the extension contains two directories: java and cpp. The files correspond to the files needed for your Eclipse project and the files needed for your NDK build.

First, you have to copy the contents of the java folder to the src folder of your Eclipse project. The only modification you need to make to your Java Android project is to instantiate an AdMobHelper object in your activity’s onCreate method. After that your activity’s class should look something like the following example:

public class MyGameActivity extends Cocos2dxActivity {

    protected AdMobHelper mAdMobHelper;

    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        mAdMobHelper = new AdMobHelper(this);
    }

    static {
        System.loadLibrary("myNativeGameLib");
    }
}

That’s all for the Java part. Now you have to copy the contents of the cpp folder to your C++ source tree (e.g. directly under your Classes folder). If you are using Visual Studio to test your application under Windows, make sure you add the files also to your Visual Studio project.

In order for the new C++ files to get compiled into your native library, you have to add the source file to the list of files to compile in your NDK makefile which you can find in your Eclipse project at jni/Android.mk. After adding the file to the list, your makefile should look something like this:

...
LOCAL_SRC_FILES := hellocpp/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/CCAdView.cpp \
...

That’s all about the generic integration steps of the extension. Now it’s time to present how you use it.

Basic usage

The extension adds a new node type to the cocos2d namespace called CCAdView. In order to present your ad, you just have to create an instance of this node and add it to your cocos2d-x layer that you want to present it in. In order to do so, you need to remember two important piece of information when you create your ad unit in the AdMob web interface: the ad type you’ve created and the identified of the ad unit. After having this information, you just have to add the following code to the init method of your layer:

CCAdView* adView = CCAdView::create(AD_SIZE, AD_UNIT_ID);
this->addChild(adView, AD_VIEW_Z_ORDER);
adView->loadAd();

Here AD_UNIT_ID is the string identifier of the ad unit, while AD_SIZE specifies the type (or size) of the ad unit you’ve created and can be one of the constants of the following enum (equivalent with the corresponding Java constants of the AdSize class):

typedef enum _CCAdSize
{
    kCCAdSizeSmartBanner,
    kCCAdSizeBanner,
    kCCAdSizeMediumRectangle,
    kCCAdSizeFullBanner,
    kCCAdSizeLeaderboard,
    kCCAdSizeWideSkyscraper
} CCAdSize;

Remember, these information come from the AdMob web interface. For example, if you created a simple banner then you should use the kCCAdSizeBanner constant, and the ad unit id will be the 15 character long string identifier the AdMob web interface allocated for it.

The value of AD_VIEW_Z_ORDER is actually indifferent on Android as there the actual visual item showing the ad is an Android View, not really a cocos2dx node, thus no matter what Z order you specify the ad will always appear on top of any cocos2d-x rendered primitive. However, the extension comes also with a stub Windows implementation that will show you a white outlined black rectangle as a placeholder of where your ad will actually show up when running your application on an Android device, and as that placeholder is shown as a regular cocos2d-x node on Windows, it is recommended to specify a Z order higher than any other displayed node so that the visual appearance on Windows will match the one you’ll see on the actual device.

You probably also noted that we call the loadAd method of the CCAdView node which is actually equivalent with the Java interface’s loadAd method and it tells the AdMob SDK to load a new ad to the ad unit. You can call this method anytime you want to make sure that a new ad is presented (however, the SDK doesn’t guarantees that a new ad will be shown each time you call this method in order to avoid potential abuse).

Ad placement and visibility

By default, your ad will be shown in the top-left corner of your application. However, you can change its location by specifying its horizontal and vertical alignment with the setAlignment method. For example, in order to place your ad horizontally centered at the bottom of the screen you have to add the following line to your code:

adView->setAlignment(kCCHorizontalAlignmentCenter, kCCVerticalAlignmentBottom);

Currently there is no way to set an explicit position for the ad, but I think for most use cases setting the screen alignment should be satisfactory (at least it was for me).
Besides that, you might also want to hide your ad unit from time to time and then re-show it again later. You can use the setVisible method of the CCAdView node just like you do it with any other cocos2d-x node. In general, it is a good practice to just hide and then show you ad again, instead of deleting and re-creating every single time your whole CCAdView node. Also, you probably want to load a new ad each time you show your ad unit again. These can be easily implemented as follows:

// show new ad
adView->setVisible(true);
adView->loadAd();
...
// hide ad
adView->setVisible(false);

Location based ads

The AdMob SDK also allows you to present targeted ads to the users of your application based on their location. This allows you to show more relevant ads to the user which can both result in better user experience and higher ad revenue. The location used for determining what ads to show can be either based on the user’s coarse-grain location (simple mobile network provided data) or fine-grain location (GPS provided location). In general, the former is perfectly acceptable and is probably less intrusive from the user’s point of view, but for the sake of completeness, the extension supports both types.

By default, the user’s location is not used by AdMob or by this extension. You can check that by using the getUsedLocation method that will return the value kCCLocationNone by default.

If you want to use the user’s coarse-grain location to increase the relevance of ads you have to add the following line to your code:

adView->useLocation(kCCLocationCoarse);

The effect of the useLocation method will take effect the next time you call loadAd.

However, in order to use the coarse-grain location in your application, you also have to request permission to do so in your Android manifest by adding the following line under the manifest element of your XML:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

In a similar fashion, if you want to use the user’s fine-grain location, add the following line to your C++ code:

adView->useLocation(kCCLocationFine);

While in your Android manifest you have to request the ACCESS_FINE_LOCATION permission instead:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Note that, however, both of these permissions are optional, and you only need at most one of them, based on what policy you use for location based ads.

Summary

You can see how easy AdMob integration into cocos2d-x projects could be with the extension and the functionality provided is probably enough for most users, at least it was for me. However, I’m pretty new to writing Android JNI code so people who are more experienced in the field would probably find my implementation kind of hacky. That’s perfectly fine, the extension is open source and I’d really like to see people improving it, so feel free to contact me if you have any improvement ideas or patches. The source code is available as a Google Code project here: https://code.google.com/p/cocos2d-x-admob/

Also, the current implementation has the following limitations:

  • Only supports Android (and Windows, through a stub that is meant only for development purposes). It would be great if somebody could provide ports to other platforms.
  • Only a single CCAdView node is going to work. That means if you create an additional node, that will practically overwrite the state of the previous one. Though I don’t consider this a practical limitation as AdMob doesn’t allow you to display more than one ad at a time anyways.
  • Only cocos2d-x 2.x.x is supported, but if you’re still using cocos2d-x 1.x.x I would anyways recommend you to upgrade.

So while there is a lot of room for improvements, I hope that the extension will help people not to have to go through the same problems that I had and can concentrate more on their actual application.