questions about Admob

Hi - my app is a flashcard app. It has a main menu from which you can choose a topic module to work on. My aim is to show an interstitial ad each time the user goes back to the main menu from a module, or after having answered 10 flashcard questions. My app code lives in several files (a main.lua, and one .lua file per module) but I have a common data file containing functions and tables that are used by all modules. I put my admob calling code in the common data file. It looks like this:

c.showAnAd = function() local function adListener( event ) local json = require( "json" )   print( json.prettify( event ) )           if ( event.phase == "init" ) then  -- Successful initialization                  admob.load("interstitial",{adUnitId="XXXXX", childSafe = true })    end end admob.init( adListener, {appId="XXXXX" }  ) if ( admob.isLoaded( "interstitial" ) ) then admob.show( "interstitial" ) end end

I published the app on the google play store. When I run the app, I’m expecting to see an ad each time I go to the main menu (the code for the menu calls the function above every time the menu appears). What happens is I seem to see an occasional ad at random times, and only about 1 ad for every 20 times I go to the menu. 

I have tried to tether my Android phone to my Macbook and chose “copy to device and launch” so I can view the console output. But I get the following error message when I try to install the app on the phone.

I also get this in the console: 

Error running /Applications/Corona/Corona Simulator.app/Contents/Resources/android\_sendapp.sh (                         "-r",                         "/Users/davidp/Desktop/Mini Music Theory School.apk"

Android version is 5.1. Corona is 2018.3326

I’m not sure if this was the right forum to post this so feel free to move it elsewhere. Thanks.

It looks like you’re asking two unrelated questions here. 

I’ll respond to the one about failed install:

Delete the old copy of the app from your device manually and try installing again.

This message tells me you may have changed your signing certs between installations.

I deleted the old copy of th app from the phone (and cleared the cache partition) and tried again with  “copy to device and launch”.

I tried it twice, first time with my google play keystore and second time with the “debug” keystore. Failed both times. I get the same “Device installation problem” mentioned above. 

For the failed install, can you post your build.settings?

Do you have multiple logins/accounts on your test device?

As for only getting ads 1 in 20 times, it very well could be a fill issue. If you hook your device up to your computer via USB and use “adb logcat” or Android Studio to look at the device’s console log you can figure out why you’re not getting ads. You do have the listener function printing out information already.  You probably should also be using test mode to show test ads while you’re testing.

Rob

OK thanks, I’m making progress. I did have two users on the phone. I deleted one and the app installed. I’m now seeing lots of output in the Corona console. Will the Corona console give me the necessary info, or do I need adb logcat as well?

One other issue I have is that at the console I’m seeing this:

“WARNING: admob.init(listener, options), init() should only be called once”

I was calling it every time I called admob.load( (see OP), so I set it up so admob.init is ony called once, at the start of the program, but now I’m being told:

“ERROR: admob.isLoaded(adType [, options]), admob.init() must be called before calling other API functions”

So I’m a bit confused about when and where to put admob.init  … thanks.

If you’re on a mac and using it to install to your device, the Corona console log is a copy of the “adb logcat” messages that are generated by your app. You should just be able to see all the messages there.

You are only permitted to call the .init() method once. Most people do this in main.lua.

It sounds like you’re calling:

admob.init()

followed immediately by

admob.isLoaded() 

You can’t do this. The .init() function is an asynchronous function. That is it returns immediately and completes its initialization in the background. You will receive an event in your adListener function once the initialization is complete. Once you get that event, you can then use the other functions. 

In most use cases, you’re not going to show an ad from main.lua. You typically would load your ads in the adListener() function after you get the “init” event. The in some other scene, like a menu scene, or at the point where you want to show an interstitial ad or rewarded video ad, check to see if the ad is loaded and then show it. Rarely do you want to hit the app user with an add while main.lua is finishing up.

Rob

hi, yes, my main.lua contains my main menu code. When a user hits “menu” from from one of the flashcard screens, it calls a function in main.lua to display the main menu again. At the top of the main menu code is a call to the “ShowAnAd()” function in the OP above.

So would it be better to have

local function adListener( event ) [...] end admob.init( adListener,  {appId="XXX", testMode=true }  )

at the very beginning of main.lua (called only once), and then do the following in a different .lua file, perhaps within the ‘return to menu’ button listener within a flashcard module?

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

I’m not clear why I can’t immediately follow admob.init by admob.isloaded. Does the init function need more time to complete before we call isLoaded? Thanks.

As I said above, it takes time for the plugin to initialize. It then takes more time to load an ad. To prevent your app’s UI from blocking, many network-based API’s behave like this. That is they return immediately, process the task in the background and notify the foreground via an event when it finishes.

Today’s computers and mobile devices execute millions of instructions per second and the time between .init() finishing and the finishing of your main.lua is fractions of a second later, which isn’t nearly enough time for network operations to finish.

Rob

OK I have admob.init and its listener once only, right at the start of main.lua.

The calls to show the ad are elsewhere.

I’m still finding that I’m hardly getting any ads (I’m in test mode). The behaviour I’m seeing at the moment is that after I do a build and copy to device and launch, the very first ad call works … but then every subsequent time I hit the menu button (and call an ad) there is no ad (I tried around 30 times in a row). The only time I saw anything ad-related in the console was when the ad displayed. On the subsequent failed calls it displays nothing.

I put a print statment into admob.isloaded to see if it is or not. It only ever is the first time it’s called

I’m finding this kind of confusing at the moment: the init listener calls admob.load. Does this load just one ad, or a whole bunch? Presumably a bunch, if we’re only supposed to call admob.init once in the app. Yet right now it’s behaving like it’s just fetching one ad, and that’s it.

Are you calling ad.load() each time?

Rob

I only have “admob.load” once. It’s in the listener for admob.init:

        if ( event.phase == "init" ) then  -         admob.load("interstitial" .... ...         end

That’s the one and only place i had it.

So I tried just now to add admob.load(…params…) right before

    if ( admob.isLoaded( "interstitial" ) )         admob.show( "interstitial" ) 

but I’m not getting any ads now!

Not sure if it’s helful but here’s a bit of console output. The “not loaded” is from a print statement I added showing that admob.isLoaded is false. “Inside showanad” in another print statment I added.

Aug 20 04:16:14.743 XT1032: inside showanad
Aug 20 04:16:14.743 XT1032:
Aug 20 04:16:14.744 plugin.admob: Test mode active for device ‘C936582D06E66C0D1D3C68DC8610E229’
Aug 20 04:16:14.872 XT1032: not
Aug 20 04:16:14.873 loaded
Aug 20 04:16:14.893 XT1032:
Aug 20 04:16:14.893  getRunningAppProcesses: caller 10069 does not hold REAL_GET_TASKS; limiting output
Aug 20 04:16:14.903 XT1032: get
Aug 20 04:16:14.904 RunningAppProcesses: caller 10122 does not hold REAL_GET_TASKS; limiting output
Aug 20 04:16:14.907 XT1032: getRunni
Aug 20 04:16:14.907 ngAppProcesses: caller 10069 does not hold REAL_GET_TASKS; limiting output
Aug 20 04:16:16.646 XT1032: {
                    XT1032:   “data”:"{“adUnitId”:“XXXXXXXXXX”}",
                    XT1032:   “name”:“adsRequest”,
                    XT1032:   “phase”:“loaded”,
Aug 20 04:16:16.647 XT1032:   “provider”:“admob”,
                    XT1032:   “type”:“interstitial”,
                    XT1032:   “isError”:false
                    XT1032: }
Aug 20 04:16:37.573 XT1032: in
Aug 20 04:16:37.573 side showanad
                    XT1032: plugin.admob: Test mode active for device ‘C936582D06E66C0D1D3C68DC8610E229’
Aug 20 04:16:37.607 XT1032: getRu
Aug 20 04:16:37.607 nningAppProcesses: caller 10122 does not hold REAL_GET_TASKS; limiting output
Aug 20 04:16:37.618 XT1032: not loa
Aug 20 04:16:37.618 ded

 

You should be getting more events than that. When you call admob.show(“interstitial”), there should be an event or two coming into the listener. For instance, there should be a “closed” phase when an interstitial is closed.  There should be a “displayed” phase when the ad was shown. 

You can, when you’ve gotten either the “closed” phase or possibly the “displayed” phase, call admob.load() to load the next interstitial ad. That will preload the next ad for the next time you need to show it. You could potentially call admob.show() and immediately call admob.load(), but I’m not 100% sure of how AdMob will behave in that case.

Rob

I’ve seen the displayed and closed events in my output.

Where would I add this code? Do I need to add more cases to the admob.init’s listener? Something like this?

    if ( event.phase == "init" ) then     admob.load("interstitial",{adUnitId }) elseif (event.phase == "displayed) then admob.load(...... elseif (event.phase == "closed") admob.load(..... .....      end

That code would go in your adListener function. You shouldn’t need it anywhere else. Also, you probably don’t need to call admob.load() for both “displayed” and “closed”, pick the one that works for you.

Rob

OK seems to be working now, thanks so much for all the help.

It looks like you’re asking two unrelated questions here. 

I’ll respond to the one about failed install:

Delete the old copy of the app from your device manually and try installing again.

This message tells me you may have changed your signing certs between installations.

I deleted the old copy of th app from the phone (and cleared the cache partition) and tried again with  “copy to device and launch”.

I tried it twice, first time with my google play keystore and second time with the “debug” keystore. Failed both times. I get the same “Device installation problem” mentioned above. 

For the failed install, can you post your build.settings?

Do you have multiple logins/accounts on your test device?

As for only getting ads 1 in 20 times, it very well could be a fill issue. If you hook your device up to your computer via USB and use “adb logcat” or Android Studio to look at the device’s console log you can figure out why you’re not getting ads. You do have the listener function printing out information already.  You probably should also be using test mode to show test ads while you’re testing.

Rob

OK thanks, I’m making progress. I did have two users on the phone. I deleted one and the app installed. I’m now seeing lots of output in the Corona console. Will the Corona console give me the necessary info, or do I need adb logcat as well?

One other issue I have is that at the console I’m seeing this:

“WARNING: admob.init(listener, options), init() should only be called once”

I was calling it every time I called admob.load( (see OP), so I set it up so admob.init is ony called once, at the start of the program, but now I’m being told:

“ERROR: admob.isLoaded(adType [, options]), admob.init() must be called before calling other API functions”

So I’m a bit confused about when and where to put admob.init  … thanks.

If you’re on a mac and using it to install to your device, the Corona console log is a copy of the “adb logcat” messages that are generated by your app. You should just be able to see all the messages there.

You are only permitted to call the .init() method once. Most people do this in main.lua.

It sounds like you’re calling:

admob.init()

followed immediately by

admob.isLoaded() 

You can’t do this. The .init() function is an asynchronous function. That is it returns immediately and completes its initialization in the background. You will receive an event in your adListener function once the initialization is complete. Once you get that event, you can then use the other functions. 

In most use cases, you’re not going to show an ad from main.lua. You typically would load your ads in the adListener() function after you get the “init” event. The in some other scene, like a menu scene, or at the point where you want to show an interstitial ad or rewarded video ad, check to see if the ad is loaded and then show it. Rarely do you want to hit the app user with an add while main.lua is finishing up.

Rob