sunnycupertino / cordova-plugin-admob-simple

Cordova plugin allowing Admob interstitials and banner ads.
MIT License
164 stars 150 forks source link

Interstitial request error after first display. #5

Closed russellchapin closed 8 years ago

russellchapin commented 8 years ago

First interstitial displays perfectly, but subsequent interstitial calls cause this error in the XCode log: Request Error: Will not send request because interstitial object has been used.

The same interstitial from the first display call is shown.

According to AdMob docs: Interstitials are a one time use object. You must create a new interstitial object to make another interstitial ad request.

My code looks exactly like readme.

sunnycupertino commented 8 years ago

You need to wait till onReceiveInterstitialAd is called back to request the second one or this happens. It takes some time to load. How long do you wait?

russellchapin commented 8 years ago

Didn't wait for that. I'll try and see if it works. Thanks.

russellchapin commented 8 years ago

I waited but it didn't solve the problem. Again waiting until onDismissInterstitialAd is called back to create and request another interstitial like in the readme:

registerAdEvents();
window.plugins.AdMob.createInterstitialView();
window.plugins.AdMob.requestInterstitialAd();

......... ......... .........

document.addEventListener('onDismissInterstitialAd', function() {
     window.plugins.AdMob.createInterstitialView();
     window.plugins.AdMob.requestInterstitialAd();
 });

Basically, I'm trying to show a different ad after user engages with one specific feature every time, so it's the same place in code, just showing a different ad.

XCode log shows that showInterstitialAd() is added and called on the same interstitial object, i.e. if showInterstitialAd() has already been called once, the log will show it being called twice the next time it is called, so a new interstitial is not being created, it's just adding duplicate calls to the already used interstitial.

How do I ensure a new interstitial object is being created and (if necessary) if the old one is destroyed every time I call?

sunnycupertino commented 8 years ago

We'll get back to you on this in a day or 2.

sunnycupertino commented 8 years ago

As far as we can see it is getting a new ad from the google servers. The fact that the same ad shows to you is probably because google sees you are testing, and just serves the same ad.

Here is the basic code we used to test, which shows in the console that createInterstitialView and then requestInterstitialAd were indeed called each time.

 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicitly call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');
        initAd();
        showBannerFunc();
        window.plugins.AdMob.createInterstitialView();  //get the interstitials ready to be shown 
        window.plugins.AdMob.requestInterstitialAd();
        console.log('Received Event: ' + id);
    }
};

app.initialize();

//initialize the goodies
function initAd(){
        if ( window.plugins && window.plugins.AdMob ) {
            var ad_units = {
                ios : {
                   banner: 'ca-app-pub-9606049518741138/5367067208',        //PUT ADMOB ADCODE HERE
                    interstitial: 'ca-app-pub-9606049518741138/6843800409'  //PUT ADMOB ADCODE HERE
                },
                android : {
                    banner: 'ca-app-pub-9606049518741138/5367067208',       //PUT ADMOB ADCODE HERE
                    interstitial: 'ca-app-pub-9606049518741138/6843800409'  //PUT ADMOB ADCODE HERE
                }
            };
            var admobid = ( /(android)/i.test(navigator.userAgent) ) ? ad_units.android : ad_units.ios;

            window.plugins.AdMob.setOptions( {
                publisherId: admobid.banner,
                interstitialAdId: admobid.interstitial,
                adSize: window.plugins.AdMob.AD_SIZE.SMART_BANNER,  //use SMART_BANNER, BANNER, IAB_MRECT, IAB_BANNER, IAB_LEADERBOARD
                bannerAtTop: false, // set to true, to put banner at top
                overlap: true, // banner will overlap webview
                offsetTopBar: false, // set to true to avoid ios7 status bar overlap
                isTesting: false, // receiving test ad
                autoShow: false // auto show interstitial ad when loaded
            });

            registerAdEvents();
        } else {
            //alert( 'admob plugin not ready' );
        }
}
//functions to allow you to know when ads are shown, etc.
function registerAdEvents() {
        document.addEventListener('onReceiveAd', function(){});
        document.addEventListener('onFailedToReceiveAd', function(data){});
        document.addEventListener('onPresentAd', function(){});
        document.addEventListener('onDismissAd', function(){ });
        document.addEventListener('onLeaveToAd', function(){ });
        document.addEventListener('onReceiveInterstitialAd', function(){showInterstitialFunc(); });
        document.addEventListener('onPresentInterstitialAd', function(){ });
        document.addEventListener('onDismissInterstitialAd', function(){      
            window.plugins.AdMob.createInterstitialView();  //get the interstitials ready to be shown and show when it's loaded.
            window.plugins.AdMob.requestInterstitialAd();
        });
    }
 //display the banner
 function showBannerFunc(){
     window.plugins.AdMob.createBannerView();
 }
 //display the interstitial
 function showInterstitialFunc(){

     window.plugins.AdMob.showInterstitialAd();
 }

If you would like to be even more certain that a new ad is retrieved each time, you could go into the plugin code in CDVAdMob.m and play around with commenting in and out the following if statement and its 2 corresponding function calls. Choose one or the other.

    if(! self.interstitialView) {
        [self __cycleInterstitial];
    } else {
        [self.interstitialView loadRequest:[self __buildAdRequest]];
    }
sunnycupertino commented 8 years ago

It's definitely getting a new interstitial, as the
self.interstitialView.delegate = nil; self.interstitialView = nil; are set each time the new interstitial is shown and a new one is created.

sunnycupertino commented 8 years ago

Can we close this now. Did you get it going?

russellchapin commented 8 years ago

This example you gave is just to show that the new ad is being served every time, right?

document.addEventListener('onReceiveInterstitialAd', function(){showInterstitialFunc(); });
        document.addEventListener('onPresentInterstitialAd', function(){ });
        document.addEventListener('onDismissInterstitialAd', function(){      
        window.plugins.AdMob.createInterstitialView();  
        window.plugins.AdMob.requestInterstitialAd();
});

Because it shows another interstitial right after the previous one has been dismissed in an infinite loop.

I found a less than ideal workaround for my problem by doing this, which presents a new ad each time and does not fire the previous error:

            registerAdEvents();
        } else {
            // alert( 'admob plugin not ready' );
        }
}

// functions to allow you to know when ads are shown, etc.
function registerAdEvents() {
    document.addEventListener('onReceiveAd', function() {
        console.log("Received ad");
    });
    document.addEventListener('onFailedToReceiveAd', function(data) {
        console.log("Failed to receive ad: "+data);
    });
    document.addEventListener('onPresentAd', function() {});
    document.addEventListener('onDismissAd', function() {});
    document.addEventListener('onLeaveToAd', function() {});
    document.addEventListener('onReceiveInterstitialAd', function() {showInterstitialFunc();});
    document.addEventListener('onPresentInterstitialAd', function() {});
    document.addEventListener('onDismissInterstitialAd', function() {});
}

function createAndRequestInterstitialFunc(){
    window.plugins.AdMob.createInterstitialView();
    window.plugins.AdMob.requestInterstitialAd();
}

function showBannerFunc(){
    window.plugins.AdMob.createBannerView();
}

function showInterstitialFunc(){
    window.plugins.AdMob.showInterstitialAd();
}

createAndRequestInterstitialFunc() is called in another file every time after the user completes the same specific task.

The problem here is that the ad is being created and requested right before it's shown, so if it's a video or rich media, it's often still loading after it's shown. It would be ideal to create, request and download the ad content in the background so that the ad is fully rendered when showInterstitialFunc() is called.

sunnycupertino commented 8 years ago

The example I sent you is not for production, it's just to show that our plugin works properly. Yes it shows another as soon as it's closed and loads the other in the background like you want. If you want to avoid calling it before it is downloaded, then make sure you download the interstitial as soon as the current one is closed, set a variable when it's finished downloading, and don't call it unless that variable is set. There is no other way to do it and you cannot speed up the time it takes for google to serve the ad to you. The plugin has no issues and can perform exactly what you want.

russellchapin commented 8 years ago

Ah, wasn't setting the flag. It's working now. Thanks!

sunnycupertino commented 8 years ago

Great!