AdMob

I have recently purchased the AdMob plugin and have had a few problems.  All my testing is done on Android (S7 edge).

When I use my Reward Ad Unit Id I am not getting a video (in both test and production mode).  I know I have everything properly coded because when I use the test google reward ad unit id “ca-app-pub-3940256099942544/5224354917” it does work. I know you dont have much to go off here without error codes but below questions can help me:

Are these Limitations:

  1. Fill problem as I live in Israel and have “childSafe” to true?

  2. Using default keystore provided by Corona?

  3. Using Live Build App?

Questions:

1 . Test reward ad unit id from google sometimes works and sometimes does not?  Shouldn’t this be 100% fill?

  1. How do I use “adsRequest”.  If im able to use this then I can get error codes but I really need it to be able to utilize the “reward” callback to make sure user has successfully watched reward video.  In the adsRequest API there are no samples and I cannot find any examples.

  2. How can I figure out the exact error as to why an ad is not working.  Be it fill, internet, bad appID / adUnitId, etc…?

Last question on a bit of a different subject, please let me know if I should erase this and post somewhere else.  I hold citizenship in USA and Israel.  When creating all my dev accounts / adMob account I use Israel as my location as this is where I currently live.  As a developer will my app have less fill rate being Israeli as opposed to being American or is this solely based on the user receiving the ad?  Am I restricted to anything such as maybe posting my app to other countries?  Is there any difference (of course payouts, taxes, etc… will have differences) but any difference on something such as how they might advertise me.  I know this is not related to Corona but maybe you have heard of such limitations.

Any help on any of this is immensely appreciated.  Thanks.

I’m not sure I have answers to all your questions. But before anyone can really help, you need to be able to get messages out of your device’s console log so we can know what’s happening.

You probably have a function that’s the listener to your .init() call. Assuming you called it adListener() (which you may have or may not have named it that), you should make this change:

local function adListener( event )       local json = require( "json" )       print( json.prettify( event ) )       -- the rest of your function end

This will dump the even table and all the information it contains. This way you know what events you’re receiving and any messages attached to them. If you’re having a fill error it will tell you. If you have a configuration problem, there should be info there that will help you solve your problems.

As far as fill rates go, I’m not 100% sure, but I’m pretty sure it’s where the app user is located. Generally, most ad providers have more fill in the US than they do other countries, so I suspect that AdMob is no different, though I understand that AdMob does have one of the best fill rates worldwide, but there isn’t a 100% fill guarantee. 

Rob

Thanks so much for the help Rob.  I now have all working except one thing.

When I call a rewardVideo test video, it plays fine, I watch the full video then leave the video but I am not getting the reward callback.  Is it maybe because its a google test provided ad unit?  Should I have some extra code somewhere to call the ad listener after admob.show? 

Code below:

-- Load an AdMob rewardedVideo ad if livesFile==0 then local function adListener( event ) if ( event.phase == "init" ) then admob.load( "rewardedVideo", { adUnitId="ca-app-pub-3940256099942544/5224354917", childSafe=true } ) --Google provided AdUnitID if ( event.phase == "reward" ) then -- also tried with elseif gameFileContents[2]=1 jsonWrite(gameFile, gameFilesPath, gameFileContents) jsonWrite(currentLevelFile, currentLevelPath, currentLevelContents) removeObjects() composer.gotoScene("easyGame") end end end admob.init( adListener, { appId="ca-app-pub-XXXXXXXXXXXX~XXXXXXXXXXX", testMode=true} ) --My Ad ID end ------------------------------------------------------------------------------------------------ if ( admob.isLoaded( "rewardedVideo" ) ) then admob.show( "rewardedVideo" ) end

If i put the code that is inside the ( event.phase == “reward” ) after the admob.show call then it does work but the problem is that if you cancel the video without watching the whole thing you still get the reward of course.  As of now I just call the admob.show and am expecting whatever code is in ( event.phase == “reward” ) to get executed after the video is successfully watched. Is that a wrong assumption?

If your wondering im getting these test ad units from, https://developers.google.com/admob/android/test-ads

I use this because it says in the API that if you use the ad in test mode “testMode==true” then the reward video will not show an ad (hence I wont be able to test it).

Well this won’t work:

 if ( event.phase == "init" ) then admob.load( "rewardedVideo", { adUnitId="ca-app-pub-3940256099942544/5224354917", childSafe=true } ) --Google provided AdUnitID if ( event.phase == "reward" ) then -- also tried with elseif gameFileContents[2]=1 jsonWrite(gameFile, gameFilesPath, gameFileContents) jsonWrite(currentLevelFile, currentLevelPath, currentLevelContents) removeObjects() composer.gotoScene("easyGame") end end

Because event.phase has to be “init” to get to your if statement where you’re testing to see if event.phase equals “reward”. Since event.phase can’t be both at the same time in the same event. You would need to do:

 if ( event.phase == "init" ) then admob.load( "rewardedVideo", { adUnitId="ca-app-pub-3940256099942544/5224354917", childSafe=true } ) --Google provided AdUnitID elseif ( event.phase == "reward" ) then -- also tried with elseif gameFileContents[2]=1 jsonWrite(gameFile, gameFilesPath, gameFileContents) jsonWrite(currentLevelFile, currentLevelPath, currentLevelContents) removeObjects() composer.gotoScene("easyGame") end end

But likely something else is going on causing your rewarded video to not behave correctly. Everyone implementing ads really needs to learn how to use print statements to debug their app on a device to learn what’s going on. Every ad plugin provides information about why it’s not working.

local function adListener( event ) local json = require( "json" ) --\<---- Add these two lines print( json.prettify( event ) ) --\<---- Add these two lines if ( event.phase == "init" ) then admob.load( "rewardedVideo", { adUnitId="ca-app-pub-3940256099942544/5224354917", childSafe=true } ) --Google provided AdUnitID if ( event.phase == "reward" ) then -- also tried with elseif gameFileContents[2]=1 jsonWrite(gameFile, gameFilesPath, gameFileContents) jsonWrite(currentLevelFile, currentLevelPath, currentLevelContents) removeObjects() composer.gotoScene("easyGame") end end

Now you can:

  1. If you’re on Mac, tether your test device to the Mac and use Corona’s ability to “Install to device” build option. If you do this, and you do not close the dialogs after the build completes, Corona will route the device’s console log to the Corona console log window for you. You can then run the app and see what AdMob says is going on.

  2. If you’re not on a Mac, or even on a Mac, you can install the command line/terminal tools for Android knowns as ADB or Android Debug Bridge. This will give you a command you can run from the command line and you can run:

adb logcat

to dump the device’s console log. Run your app on the device and watch the output for the various messages.

  1. If you’re not command line friendly and can put up with the beefier install, you can do the same thing with Android Studio.

Once you have some intel on what’s going it, it will be easier to move forward. 

Rob

Thanks,  yeah thats a stupid mistake I did when I was writing the code over in the code block.  It was correct in the real code.  I reverted back to the ifelse and setup the json log event line (already using Json so dont need “local json = require( “json” )”)

With the ifelse it sometimes works (which is much worse then not working).  I am the IT director at a large startup so am very familiar with the various command lines and how to use them.  I use windows, the adb logcat is unfortunately not telling me much.  I logged a successful reward video, copied the contents to text sheet then did the same for an unsuccessful reward callback and there are no differences regarding “reward”.  There are hundreds of messages so I cant read all of it, I just search for the reward callback.  Would it help if I gave you these logs?  Should I do the logcat with specific PID to my game to limit the logs?  I am just not sure if limiting the logs to my process only will eliminate the reward callback or any other important log.

There is an option for “adb logcat” that lets you filter out messages from the Corona activity:

adb logcat Corona:v *:s

 

This will only show you the print statements from Corona which will cut down on the clutter. It however may miss messages from Admob, but if you want to focus on the dump of the event table, this filter should help.

Rob

Hey Rob thanks for all this, this really helps with a lot of things regarding this problem and outside this problem.  I am still testing and doing various things to make this work but looking much better so far!  I have tried to use this with production keys and never get fed an ad and dont have test enabled in the code.  Im guessing it knows either my device, user on device, or IP, or all of this to know that im a test device.  I have sent the app to someone in USA and they are not getting fed ads either.  Does it maybe know that im in internal test track and not production so not serving ads or maybe because demand is not high enough so it wont serve ads till it receives more requests from more people.  I read from google that as long as a test ad works then you know everything is working and all you have to do is replace with your keys for it to work, it also says they will not fill ads until they have seen many requests.  I get that what they are saying means I will not be fed an ad but from experience is that true and I should release and just hope it works or is there some way I can get fed a real ad to make sure real ads work (I know about maybe account suspension with this but I only need around 6 to test and I of course wont click them).  For now I will triple check that test ads work completely ie. giving reward callback and then replace with production adunits for production and wait a couple weeks to a month to see if I start pulling ad data reports within admob (is this bad idea?)

Ok I think I have found the problem.  When every screen loads the logs tell me “WARNING: admob.init(listener, options), init() should only be called once”.  Its only being called once on every screen.  Im guessing that the proper way is to call admob.init once in main.lua then only use ad listener in all the different screens? If this is the case why is it not written in the API?  If this is not the case then this is becoming a big problem, if the reward callback is received all is fine, if its not then the whole game gets messed up and I need to go and clear all the storage of the app to bring it back to first time installed for it to even open???  This plugin was a bit of money to not have clear documentation or bugs please help guys.

Side Note:

in every screen that can contain ads is local admob = require( “plugin.admob” ) right after the scene is called and on destroy is package.loaded[“plugin.admob”] = nil

  admob = nil

Ok now have in main.lua and still reward callback not fulfilled, tried with adlistener only in main.lua and tried with adlistener within every screen.  This fixed the bug of crashing the whole game but still reward callback not received. 

I see that you’ve opened a support ticket on this. We need to answer the question in one place or the other. The forums are best since others can learn from the discussion and answers, so I will repeat myself here. Please pick one of the two support channels to continue the discussion.

In the code you shared in the support ticket, I noticed a few things. First your adListener function doesn’t do anything more than test to see if the plugin was initialized (event.phase == “init”) and load ads.  This function has to do more like detect when the rewarded video is complete and then call your code to grant the reward to the user.

You have to add code to the listener function that prints out what’s being sent from AdMob.  Without seeing messages coming into the listener, you can only guess what’s going on. 

Finally, you don’t need need to un-required Admob and JSON in each scene. Corona loads it only once, in your case when you load it in main.lua. All other loads are just a reference to the already loaded module. I would remove your unload code.

Rob

Sorry already responded back to the email.  I agree, hopefully someone can pull an example from here, lets continue here.  So I cleaned up as you said and first error I get in menu.lua which is called from main.lua at start is of course “attempt to index global json a nill value”?  all i did was remove below from menu.lua 

local json = require( “json” )

and

  package.loaded[“json”] = nil

  json = nil

If I add this back and remove local admob = require( “plugin.admob” ) then I get the same exact problem but with admob.  Both of these are called in main.lua why am i getting this error that it cant find the plugin if I dont have to call it in the scene?

You still need to load json and admob at the top of each module:

local json&nbsp;= require( "json" ) local admob&nbsp;= require( "plugin-admob" )

Just don’t un-requirement by setting package.loaded[“json”] to nil.

Rob

I have two scenarios, using my adunitID and using test ID.  With my id i fail to load video and I think this is again due to not enough people requesting ads.

Now with test ad I made some changes and finally was able to get reward call consistently and it fulfills the reward call every time!!!

Tiny question and im out of your hair.  Is it possible to pass a variable from one scene to my main.lua reward call.  I want the reward to load a certain screen and many different scenes are relying on the same ad  but require different scenes to load after the reward.  So want to pass a variable right before I show the video then if I can work on this variable in main.lua where the reward is called everything would be perfect.

Thinking of it I guess I could just use a json file for that.

For the situation of not getting ads on your adUnitId: What messages are being printed to your test device’s console log? You can’t know why you’re not getting ads until you print out the event table and see the reason why you’re not getting ads.

To the tiny question which has a pretty big answer. 

There are many different ways for the adListener function to communicate with a scene or know what scene you need to go to.  There are two simple ways that are equally acceptable if you want the adListener to just have some variable that holds the scene name to go to.

  1. Use a faux-global data table.  See: http://docs.coronalabs.com/tutorial/basics/globals/index.html

With this method you could set a variable in the data table that holds the scene name you should go to.  Then in your adListener you access that variable and go to the scene whose name is in the variable.

  1. Use the composer methods:  .setVariable() and .getVariable().

Since you’re requiring the composer module everywhere, it’s just a faux-global table anyway. You could just use it instead of a dedicated data module. But you can’t be certain that any variable name you add to the table won’t overwrite a required Composer entry or won’t be used by Corona later if we update Composer, so we provide two methods, .setVariable( variableName, value ) and .getVariable( variableName ) to safely add values to the Composer module that can be passed between scenes and modules.

So in one scene, you could do:

composer.setVariable( "sceneToGoTo", "someSceneName" )

Then in your adListener function you can do:

local sceneToGoTo = composer.getVariable( "sceneToGoTo" ) composer.gotoScene( sceneToGoTo )

Now this may not be the best option for your game flow. If you need to go to a new scene, this will work great, but if you want to stay in the same scene, there is a better way.  The adListener() interrupts the current scene, does its code and returns to the original scene right where it left off. If you’re going to show a rewarded video, the user views that video and then closes it, you’re naturally back in the original scene. If you want that reward to get processed without going to a new scene, you can write a function to process the scene and add it to the scene object in the current scene:

function scene:processReward() &nbsp; &nbsp; -- code to grant the reward end

then in your adListener function, even though you don’t have a clue which scene generated the reward you can do:

local function adListener( event ) &nbsp; &nbsp; &nbsp;if event.phase == "reward" then &nbsp; &nbsp; &nbsp; &nbsp; local callingScene = composer.getScene(&nbsp;composer.getSceneName( "current" ) ) &nbsp; &nbsp; &nbsp; &nbsp; callingScene:processReward() &nbsp; &nbsp; &nbsp;end end

So as long as any scene that can generate a rewarded video response has a function named processReward() you can then have the scene actually handle the reward. Don’t forget you can pass parameters to processReward() if you program it to take parameters, which would let you potentially pass in values event.data.rewardItem and event.data.rewardAmount from the adListener function into the scene.

Rob

This whole thing scene:processReward function and the way it works is golden!  With the json I tried it did not work for all the reasons you said it would not work :slight_smile: .   I call some specific screen removal functions before removing screen so just transitioning screens from main.lua was a disaster but now with the way you said it all works incredible!!!

As for my ads with my Ad Unit ID not loading:

08-17 12:54:32.420 15754 15810 I Corona  :   “data”:"{“errorMsg”:“Internal Error”,“errorCode”:0,“adUnitId”:“ca-app-pub-XXXXXXXXX\/XXXXX”}",

08-17 12:54:32.420 15754 15810 I Corona  :   “name”:“adsRequest”,

08-17 12:54:32.420 15754 15810 I Corona  :   “phase”:“failed”,

08-17 12:54:32.420 15754 15810 I Corona  :   “provider”:“admob”,

08-17 12:54:32.420 15754 15810 I Corona  :   “response”:“loadFailed”,

08-17 12:54:32.420 15754 15810 I Corona  :   “type”:“rewardedVideo”,

08-17 12:54:32.420 15754 15810 I Corona  :   “isError”:false

08-17 12:54:32.420 15754 15810 I Corona  : }

There seems to be a few common causes to getting the “Internal Error”.

  1. There needs to be some time after setting up the Ad Unit before ads become available.  See:
    https://github.com/sbugert/react-native-admob/issues/220  

It seems like you’ve had this setup for some time, so I’m not sure this is the issue.

  1. Somehow AdMob things your device is a test device:

https://github.com/googleads/googleads-mobile-unity/issues/374

That was from the Unity forum. From what I can tell, you have to make an API call to tell AdMob your device is a test device and our plugin doesn’t support setting test device’s through software. I don’t know if there is a way to enable your device as a test device through the AdMob portal or on your Android device.

  1. The device is somehow offline. I don’t know if it shows test ads without a network connection or not. 

  2. You have some configuration error. AdMob uses AppId’s and Placement Id’s that look very similar and it’s easy to make a mistake here. Without seeing your actual code (without obscuring the ID’s) and access to your AdMob account, it will be impossible to provide direct help in this area. Just make sure you have all the right ID’s with the right syntax.

Rob

  The test ones sometimes fail to load and sometimes load successfully which tell me that its not an internet problem or that test ones are cached.  So ID has ~ and ad unit id has / . I have seen some people talking about ad Unit Id’s for android and a different one for IOS, I do not have this within adMob though, all I have is one ID for each ad unit I setup.

I have been going off this directly from adMob:

"How long does it take for ads to begin appearing after the first ad request?

When apps are newly registered with AdMob, it takes some time and a few ad requests to allow inventory to build. Because of this, you may not see live impressions immediately.

Once your app is making more requests, you should see more consistent results. Please note that test ads operate through the same channels as live ads. Being able to return a test ad ensures that your application is communicating properly with our network."

Also I sent an email with screenshots that I think should maybe clear up the question of id’s.

I would expect you would get a “No Fill” message if there were no ads available though.

I’ve not seen the email come in yet, but I’ll go poke around and see if I can find it.

Rob

Maybe I should delete these Ad Unit ID’s and make new Ad Unit ID’s?  I made them around 2 months ago and never made a call to them until around a week ago so maybe this is a problem?

I don’t know if that will work or not, you could certainly add a new rewarded ad unit and give that a try.