As of August 1, 2014, Google will be deprecating their old AdMob service in favor of a new one that’s built on top of the Google Play service. After this time, Google will no longer accept apps built with the old SDK, and apps will need to be updated as it’s likely that they’ll stop providing ads to the old system.

This new SDK from Google requires a minimum Android SDK of 2.3.3. Corona switched to a 2.3.3 minimum with Daily Build 2014.2264. This means that to use the new AdMob V2 plugin, you must use this build or later. The next public build will also enforce this 2.3.3 SDK as the minimum.

Changing your app from the original AdMob over to V2 is pretty simple — just change the following section of your build.settings from this…

    plugins =
    {
        ["CoronaProvider.ads.admob"] =
        {
            publisherId = "com.coronalabs"
        },
    },

…to this…

    plugins =
    {
        ["plugin.google.play.services"] =
        {
            publisherId = "com.coronalabs"
        },
    },

With this change, your AdMob ads.* calls should work with no additional changes. That being said, the new plugin supports a few new features that you may want to consider taking advantage of. We’ll also cover some questions which frequently come up in the forums.

Including the Plugin

For those who haven’t used ads before — in particular AdMob — let’s start at the beginning. To use AdMob V2, you must add a block of code to your build.settings file (see the recent tutorial if this topic is unfamiliar). This block goes into the plugins sub-table of the parent settings table:

settings =
{
    plugins =
    {
        ["plugin.google.play.services"] =
        {
            publisherId = "com.coronalabs"
        },
    },      
}

Understanding the Corona Ad System

At the basic level, including ads in your app involves these core factors:

  • Initializing the ad provider.
  • Showing an ad.
  • Hiding an ad.

AdMob, like the other ad providers, must have its service initialized within your code. For this to occur, you’ll need an “App ID” from AdMob. In specific AdMob terms, this is referred to as an Ad Unit ID and it’s a string that looks similar to this:

ca-app-pub-28374982782348972983749273/4987234823

Going forward, this tutorial will use ca-app-pub-nnnnnnnnnnn/nnnnnnnn, but it’s your responsibility to substitute your Ad Unit ID whenever the tutorial calls for setting the AppID.

Most ad providers use one AppID per platform. This means that you’d have one AppID on iOS and another AppID on Android. Thus, at the point when you initialize your ad provider in code, you’d include some conditional logic to determine if the platform is Android or iOS and then provide the appropriate AppID. For example:

local ads = require( "ads" )
local appID = "myiOSAdProviderAppID"
if ( system.getInfo( "platformName" ) == "Android" ) then
    appID = "myAndroidAdProviderAppID"
end

local adProvider = "superDuperAds"
local function adListener( event )
    --(more on this later)
end

ads.init( adProvider, appID, adListener )

However, AdMob takes this one step further. In addition to having a unique ID per platform, you must also provide a unique ID per ad type. This is discussed in the next section.

Ad Types

Most ad providers offer two types of ads and AdMob is no different in this respect:

  • Banners — ads which may appear somewhere within a scene of your app.
  • Interstitials — ads (typically fullscreen) which may appear between scenes in your app.

Most Corona developers want to use both types of ads, and AdMob supports this in the form of a unique Ad Unit ID for both ad types on each platform. This means that, for deployment to iOS and Android, you may have four IDs to manage. As such, you may want to consider this strategy:

local ads = require( "ads" )
local bannerAppID = "ca-app-pub-nnnnnnnnnnn/nnnnnnnnn"  --for your iOS banner
local interstitialAppID = "ca-app-pub-nnnnnnnnnnn/nnnnnnnn"  --for your iOS interstitial
if ( system.getInfo( "platformName" ) == "Android" ) then
    bannerAppID = "ca-app-pub-nnnnnnnnnnn/nnnnnnnnn"  --for your Android banner
    interstitalAppID = "ca-app-pub-nnnnnnnnnnn/nnnnnnnnn"  --for your Android interstitial
end

local adProvider = "admob"
local function adListener( event )
    --(more on this later)
end

ads.init( adProvider, appID, adListener )

Note that you should carefully consider the user’s experience when planning an advertising strategy. Everyone wants to make money from their apps, so showing both banners and interstitials may seem a logical approach. However, advertising can detract from the user experience and often you’ll have greater success with compelling content versus frequent ads.

Showing Ads

For most ad providers, showing an ad can be done with simply the ad type and a table of parameters:

ads.show( adtype, table_of_parameters )

For instance, with iAds, you can simply show a banner ad by providing the ad type along with an x and y location on the screen:

ads.show( "banner", { x=0, y=0 } )

Because of how AdMob abstracts its ad types, however, you have to change IDs based on the ad type. This is factored into the parameters table via an appID key:

ads.show( "banner", { x=0, y=0, appId=bannerAppID } )
ads.show( "interstitial", { appId=interstitialAppID } )

Without this appID parameter, AdMob will be unable to match the Ad Unit ID of the requested type with the platform and the ad delivery will fail.

The “adListener” Callback Function

Corona’s ads library supports a function which listens for certain ad-related events. In general, this function is called either when an ad loads successfully or when it fails to load.

Note the “load” terminology here. If you consider how ads work, they must first be fetched from the ad server (“loaded”) and then displayed (“shown”) to the user. Corona has consolidated this to a single function in most cases, so typically ads.show() performs both actions. This is an important designation that will be covered below.

Let’s look at a typical adListener() function for AdMob:

local function adListener( event )
    -- The 'event' table includes:
    -- event.name: string value of "adsRequest"
    -- event.response: message from the ad provider about the status of this request
    -- event.phase: string value of "loaded", "shown", or "refresh"
    -- event.type: string value of "banner" or "interstitial"
    -- event.isError: boolean true or false

    local msg = event.response
    -- Quick debug message regarding the response from the library
    print( "Message from the ads library: ", msg )

    if ( event.isError ) then
        print( "Error, no ad received", msg )
    else
        print( "Ah ha! Got one!" )
    end
end

With this listener function, you can watch the device’s console log and see what’s happening with your ads code. If you’re not familiar with viewing the device’s console log, the tutorial on basic debugging may be useful. Note that almost all ad services require that you test on an actual physical device.

Banner Ads

Banner ads are short rectangles that usually span the width of a phone — 320×50 is a fairly typical size. These work best when drawn at the top or bottom of the screen. You’re only allowed to show one banner at a time, and changing of ads is controlled on the server side at a range of 30-60 seconds.

AdMob provides several “formats” for banner ads:

  • Text-Only
  • Static Graphic
  • Animated

The AdMob portal allows you to choose either text or graphic, but it doesn’t allow you to request animated in specific. Animated banners have a higher eCPM value (more value to you), but they’re resource-intensive and can impact the app frame rate when shown.

Google strongly advises that you do not show banners at times where your CPU time is at a premium, for example, during the main gameplay state of a fast-paced game. In any case, users will likely ignore ads during intensive gameplay, so these ads provide minimal value to the advertiser. Additionally, these may hinder the overall experience so much that users outright uninstall the app. In almost every instance, it’s better to show banner ads when the user is more likely to tap on them, for example, during level select screens, on the app’s main menu, etc.

Handling Banner Height

AdMob banner ads can also have a variable height which can impact your user interface (UI). You could just leave space for the maximum banner height, but if you want your UI to fit snuggly alongside the advertising, you’ll need to know the ad’s height.

Corona allows you to gather this height, but only after the ad has successfully loaded. More specifically, if the adListener() function is called and indicates that the ad is successfully loaded, you can call the ads.height() function to determine the height of the ad and adjust your UI accordingly.

Positioning Banners

Banner ads are positioned around their top and left corner point. Thus { x=0, y=0 } in the parameters table indicate that the top-left corner of the ad should be in the top-left corner of the screen content area. If you want to show an ad at the top of the screen, this isn’t an issue — just position it at x=0, y=0. However, positioning a banner at the bottom of the screen is theoretically more tricky, since you don’t know the height of the ad until after it loads, and thus you can’t set a specific y offset from the bottom of the screen.

Fortunately, you can utilize a trick to position it perfectly along the bottom. Because advertisers don’t want you to show ads partially off screen, the ad library itself ensures that the ad is fully shown on screen — just intentionally set the ad’s y position offscreen and Corona will automatically bring it back on the screen:

ads.show( "banner", { x=0, y=100000 } )

Cycling Banner Ads

In the AdMob portal, banner ads can be set to cycle at a time increment between 30 and 60 seconds. There’s no function in Corona to request an ad cycle, and using ads.hide() followed by ads.show() will not “force” an ad cycle.

Interstitial Ads

Interstitial ads are designed to show between scenes. They’re typically full screen and they should have a method to close the ad (typically a small × in the corner). Any other touches should send the user to the ad’s destination site. Some interstitial ads are even animated and may include interactivity.

Like banners, you can use ads.show() to show interstitial ads:

ads.show( "interstitial" )

Remember that if you’re mixing both banner and interstitial ads, you must also include the appId of the ad type in the parameters table:

ads.show( "interstitial", { appId=interstitialAppID } )

Note that you don’t need to provide an x and y position for interstitial ads since they occupy the whole screen.

Pre-Loading Interstitials

Because these rich ads can take time to download (perhaps several seconds), loading an interstitial ad “on demand” using ads.show() may be too slow for your game flow. Fortunately, the AdMob V2 plugin supports pre-loading of interstitial ads, allowing you to load the next ad in advance of when you wish to show it.

To pre-load an interstitial ad, call the ads.load() API. The function takes all the same parameters as ads.show(), but in this case, you’re separating the ad process into two parts — fetching the ad (ads.load()) and displaying the ad (ads.show()).

In respect to interstitial ads, the delay comes from the loading portion, while showing the ad happens almost instantaneously. In terms of handling events, an event phase of "loaded" is triggered when you call ads.load(), but if you just call ads.show(), you won’t get any events until the ad is closed. The reason for this behavior is that if you just call ads.show() and you don’t get an ad, you’ll get an event where the phase is irrelevant. In this case, you can check the .isError value and, if it’s true, you can attempt to fetch an ad from another service. For example:

local function adListener( event )
    if ( event.isError ) then
        -- attempt to fetch another ad
    elseif ( event.phase == "loaded" ) then
        -- an ad was preloaded
    elseif ( event.phase == "shown" ) then
        -- the ad was viewed and closed
    end
end

Since your callback function will trigger when the ad is loaded, you could theoretically set a flag and later check the flag to determine if the ad is ready to show. However, Corona provides an additional convenience function called ads.isLoaded(), so when you’re ready to show the ad, simply call:

if ( ads.isLoaded("interstitial") ) then
    ads.show("interstitial")
end

Detecting When an Interstitial Closes

Sometimes you may need to know when the interstitial ad closes. For example, you may want to start/resume audio playback, timers, transitions, or physics. As of July 15, 2014, the AdMob V2 plugin will trigger the adListener() function with a phase of "shown" when an interstitial ad is closed.

Conclusion

Because of the August 1st deadline, you should convert to the Admob V2 plugin as soon as possible. For Pro/Enterprise subscribers, you can do so now via Daily Build 2014.2264 or later. For Starter/Basic users, watch the forums or this blog for news about the next public release in which the Android 2.3.3 SDK will be enforced.

  1. I see you mention the animated banners but you don’t show any code on how to actually call them. I can’t find it in any of the docs or anything can you give an example of use? Also I like the trick of setting the Y off the screen and corona will load it on the bottom I will be adopting that for sure.

  2. What should the appID be if we have both banner and interstitial? Or do we need to init twice?

    ads.init( adProvider, appID, adListener )

    • You will have two AppID’s, one for the Banner Ad, one for the Interstitial. It really doesn’t matter which one you init with since you have to provide the AppID on the actual ad.show() or ad.load() call.

      Rob

  3. admob v2 plugin seems not working correctly if you are also using facebook plugin. it crashed on a wide portion of my android test devices regularly. no problem on ios doh.

    • deniz – in case you haven’t already, can you post about this in the forum? It will be much easier to take the report there and comment on it…

  4. ROB – THANK YOU!
    I’ve been all over the forum tweaking my implementation and this write up is exactly what the community needed. Also, with the addition of the “shown” phase we finally have a useful callback.

    I will say your last statement is a bit misleading. I’m a new basic user and have consumed admob v2 already, I’m hoping you all intend to release the next public version relatively soon… ie. before the 1st (it’s been more than 2-3 months since the last public release). To that point, you’re not giving your users a lot of time to handle this which is disappointing. Making app updates, performing device testing, regression testing, and app store submissions in a short time frame hurts, Rob, it hurts.

  5. I’m using Admob v2 with daily build 2359. When I build an app and install it on an iOS device I get the following warning (using Xcode to see the console output).

    : Google Mobile Ads SDK: You are currently using 6.8.0 of the SDK. A new version, 6.9.2, is available at http://goo.gl/Zc0BYt . Please consider updating your SDK to get the latest features and bug fixes

    My banner ads are showing as expected and I can see from my Admob account that my usage is being reported.

    Just wondering what this warning means. Do I need to do something or will the plug-in be updated?

  6. looks like you are working on the plugin right now as im getting this error:

    A device build error occurred on the server.

    BuildID: 53c7faaf31a52
    Error: Get plugin failed.
    Publisher: com.coronalabs
    Plugin: plugin.google.play.services

  7. My game shows a banner ad from admob when there is a game over. Since the user click “Play again” fast, the ad is too slow to show up. Maybe it is just me, but now the ad it is even slower than before to show up. :-(

    What I am doing is a ads.show() when there is a game over, and a ads.hide() when the user press “Play again”. Am I doing it right?

    Here you have the game to check it out for yourself:

    https://play.google.com/store/apps/details?id=com.dosdrebel.heavydevil

  8. It’s a complex answer. There are too many variables that affect when we put out a public release. Desired features, certain bugs, timing of OS releases and Apple/Google mandated changes, etc. all impact our release schedule. The daily builds have to be solid enough and have not broken something that was working in the previous public build (regression bugs). We don’t like giving dates, until we know we can hit them and when there are too many variables, its hard to know.

  9. This means, that it is no more possible to use admob with a basic subscription after the first of August until the next puplic build is out?

    Please tell me I understood something wrong.

    Felix

      • Well.
        ok, thank you for the answer.
        Do you know what will happen with my game that is out now with admob v1 after August 1st, if I do not remove admob?
        I mean will the game break when an ad is loaded or will there simply be no ad?

        Felix

  10. I realized that if I use AdMob and Vungle then ads.load() will crash the app if Vungle is initialized. I always have to use ads:setCurrentProvider( “admob” ) before calling ads.load()

  11. Nice tutorial – thanks!

    I’m trying to use an Interstitial ad when the app first starts (this works fine) and switch to a banner app after the user closes the interstitial. Previously I only had banner ads so I know my IDs are correct but I can’t get the banner to work after the interstitial was displayed.

    I even tried this:

    appID = bannerAppID;
    ads.init( adProvider, appID, adListener );
    ads.show( “banner”, { x=0, y=0, appID } );

    But this doesn’t work either. Am I suppose to somehow remove the first call to ads.init?

    appID = interstitialAppID;
    ads.init( adProvider, appID, adListener );

    • If you only are using AdMob, then you should only call init once. Switching between banners and interstiital’s is done via the ads.show() API call. If you use multiple ad providers, you will need one ads.init() for each provider.

      Rob

      • Here’s what’s going on:

        appID = interstitialAppID;
        ads.init( adProvider, appID, adListener ); — init is first called with the interstitialAppID

        — check if online, if so then

        ads.show( “interstitial”, { appID=interstitialAppID } ); — this does show the interstitial ad

        — once closed, the user clicks a button to start and the following is executed:

        ads.show( “banner”, { x=0, y=0, appID=bannerAppID } );

        — No banner is ever displayed :(

  12. I am getting this response in my app:

    2014-09-04 12:22:26.890 AppName[14189:90b] Google Mobile Ads SDK: You are currently using 6.8.0 of the SDK. A new version, 6.11.1, is available at http://goo.gl/Zc0BYt . Please consider updating your SDK to get the latest features and bug fixes

    Will you guys be updating to the new SDK soon?

    • We will update at some point, usually when the changes warrant it. I’ll remind engineering, but unless there is some serious bugs being fixed or new features, we can’t just go be rebuilding these plugins every time there is an update. Google changes things and it could break many users.

      Rob

      • Can you please tell me why I can’t show banner ads?

        This is my code, is anything wrong?

        settings =
        {
        plugins =
        {
        [“plugin.google.play.services”] =
        {
        pub-8347067101481503 = “com.coronalabs”
        },
        },
        }

        android =
        {
        usesPermissions =
        {
        “android.permission.INTERNET”,
        “android.permission.ACCESS_NETWORK_STATE”,
        },
        },

        local ads = require( “ads” )
        local bannerAppID = “ca-app-pub-8347067101481503/4080572917″ –for your iOS banner
        if ( system.getInfo( “platformName” ) == “Android” ) then
        bannerAppID = “ca-app-pub-8347067101481503/2335507715″ –for your Android banner
        end

        local adProvider = “admob”
        local function adListener( event )
        –(more on this later)
        end

        ads.show( adtype, table_of_parameters )

        ads.show( “banner”, { x=0, y=0, appId=bannerAppID } )

        local function adListener( event )
        — The ‘event’ table includes:
        — event.name: string value of “adsRequest”
        — event.response: message from the ad provider about the status of this request
        — event.phase: string value of “loaded”, “shown”, or “refresh”
        — event.type: string value of “banner” or “interstitial”
        — event.isError: boolean true or false

        local msg = event.response
        — Quick debug message regarding the response from the library
        print( “Message from the ads library: “, msg )

        if ( event.isError ) then
        print( “Error, no ad received”, msg )
        else
        print( “Ah ha! Got one!” )
        end
        end

        ads.init( adProvider, appID, adListener )

        ads.show( “banner”, { x=0, y=100000 } )

        • This in your build settings is incorrect: pub-8347067101481503 = “com.coronalabs”
          It should be: publisherId = “com.coronalabs”

  13. Thanks for the tutorial! What’s the recommendation for testing? I note in the Google docs they refer to using “test ads”? ( https://developers.google.com/mobile-ads-sdk/docs/admob/android/banner#test_ads ):

    “You should use test ads during development to avoid generating false impressions. Additionally, you can always count on a test ad being available. Set up test ads by passing your hashed Device ID to AdRequest.Builder.addTestDevice: AdRequest request = new AdRequest.Builder() … ”

    I assume Corona doesn’t support this? Not sure what the negative is to testing using the final setup, but before you’ve deployed live to Apple (i.e. just when you’re building then putting on your own device).

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>