AdMob

Tried with new one, same problem, I started to ask around in the admob forum but no one answers this forum and there is no one to ask at admob.  Was just thinking that maybe the problem is that child safe is set to true?  Any ideas on how I should move with this?  Not sure what to do other then hope it will work when I release.

So with child safe setting deleted im still getting the same error.  You saw my code and pic of app ID’s so we know its not that im putting this in wrong.

Im guessing that the error message is spelling the ad unit with “//” in the middle and “/” at the end for parsing purposes?  If not then its obvious the reason is because Corona is adding “\” and “” but I saw it did that with my test ads too so really dont think its this.  Also why is “isError” false if there is an error?

08-21 13:53:04.971  2280  2318 I Corona  :   “data”:"{“errorMsg”:“Internal Error”,“errorCode”:0,“adUnitId”:“ca-app-pub-XXXXXXXX\/XXXXXXX”}",

08-21 13:53:04.971  2280  2318 I Corona  :   “name”:“adsRequest”,

08-21 13:53:04.971  2280  2318 I Corona  :   “phase”:“failed”,

08-21 13:53:04.971  2280  2318 I Corona  :   “provider”:“admob”,

08-21 13:53:04.971  2280  2318 I Corona  :   “response”:“loadFailed”,

08-21 13:53:04.971  2280  2318 I Corona  :   “type”:“rewardedVideo”,

08-21 13:53:04.971  2280  2318 I Corona  :   “isError”:false

08-21 13:53:04.971  2280  2318 I Corona  : }

Found it…  I feel pretty bad about this one but apparently at my home screen which i was never going to it said:

 “your ad units arent serving ads because your payment information is missing…”

This was not the case at first.  I talked with someone at Google (not admob but G-suite) to try and change my payment profile to my American one as that option was greyed out and he said he would get back to me but he must have raised the option for me to change this as after i clicked this box to add payment info it allowed me to choose the American payment profile and my Israeli one was already chosen and greyed out.  I have now submitted this and they say in 24 hours they will update and then im pretty sure I will be good!!!

I really appreciate all the help, I was a bit nervace and didn’t think I would have any support but in the end you guys came through really fast, professionally and with educated answers!

If I may, one last really easy question, which one of these is this coded correctly for childsafe=true, Im pretty sure the first one right?

admob.load( “interstitial”, { adUnitId=“ca-app-pub-XXXXXXXXXXXX/XXXXXXXX”, childSafe=true } )

OR SOMETHING LIKE

admob.load( “interstitial”, { adUnitId=“ca-app-pub-XXXXXXXXXXXX/XXXXXXXX”, {childSafe=true }} )

The first one is correct.

Rob

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.