sbugert / react-native-admob

A react-native component for Google AdMob banners
BSD 2-Clause "Simplified" License
1.13k stars 531 forks source link

two AdMobInterstitial load problem (!!CRASH!!) !!! ----> Thread 1: EXC_BAD_ACCESS (code=1,address=0x10)) _requestAdResolve(nil); #284

Open furkancelik opened 6 years ago

furkancelik commented 6 years ago

hi, I have nested components in AdMobInterstitial ads.

component1 (Game.js)

import React, { Component } from "react";
import {...} from "react-native";
import Header from "../../Components/Game/Header";
...
...
import {
  AdMobInterstitial
} from "react-native-admob";

export default class Game extends Component {
   static navigationOptions = {
     header: props => <Header {...props} />,
     gesturesEnabled: false
   };

  componentDidMount() {

    AdMobInterstitial.setTestDevices([AdMobInterstitial.simulatorId]);
    AdMobInterstitial.setAdUnitID("ca-app-pub-XXXXXXXXXXXX/XXXXXX");

    AdMobInterstitial.addEventListener("adLoaded", () => {
      console.log("AdMobInterstitial adLoaded");
    });
    AdMobInterstitial.addEventListener("adFailedToLoad", error =>
      console.warn(error)
    );
    AdMobInterstitial.addEventListener("adOpened", () =>
      console.log("AdMobInterstitial => adOpened")
    );
    AdMobInterstitial.addEventListener("adClosed", () => {
      console.log("AdMobInterstitial => adClosed");

      AdMobInterstitial.requestAd().catch(error => console.warn(error));
    });
    AdMobInterstitial.addEventListener("adLeftApplication", () =>
      console.log("AdMobInterstitial => adLeftApplication")
    );

    AdMobInterstitial.requestAd().catch(error => console.warn(error));

    AppStore.setShowInterstitial(this.showInterstitial);
  }

  componentWillUnmount() {
    AdMobInterstitial.removeAllListeners();
  }

  showInterstitial() {
    AdMobInterstitial.showAd().catch(error => console.warn(error));
  }

  endGame() { this.showInterstitial(); }
  render() {
    return (
          .....
    );
  }
}

EndGame show Interstitial ads.

component2 (Header.js)

import React, { Component } from "react";
import {... } from "react-native";
....
....
import { NavigationActions } from "react-navigation";

import {
  AdMobInterstitial
} from "react-native-admob";

export default class Header extends Component {
componentDidMount() {

    AdMobInterstitial.setTestDevices([AdMobInterstitial.simulatorId]);
    AdMobInterstitial.setAdUnitID("ca-app-pub-XXXXXXXXXXXX/XXXXXX");

    AdMobInterstitial.addEventListener("adLoaded", () => {
      console.log("AdMobInterstitial adLoaded");
    });
    AdMobInterstitial.addEventListener("adFailedToLoad", error =>
      console.warn(error)
    );
    AdMobInterstitial.addEventListener("adOpened", () =>
      console.log("AdMobInterstitial => adOpened")
    );
    AdMobInterstitial.addEventListener("adClosed", () => {
      console.log("AdMobInterstitial => adClosed");

      AdMobInterstitial.requestAd().catch(error => console.warn(error));
    });
    AdMobInterstitial.addEventListener("adLeftApplication", () =>
      console.log("AdMobInterstitial => adLeftApplication")
    );

    AdMobInterstitial.requestAd().catch(error => console.warn(error));

    AppStore.setShowInterstitial(this.showInterstitial);
  }

  componentWillUnmount() {
    AdMobInterstitial.removeAllListeners();
  }

  showInterstitial() {
    AdMobInterstitial.showAd().catch(error => console.warn(error));
  }

  render() {
    const { coin, showInterstitial } = AppStore;
    return (....
      <TouchableOpacity onPress={()=>{this.showInterstitial()}}><Text>Back Page</Text></ToıchableOpacity>
    ....);
  }
}

header, back page click show Interstitial ads.

error:

ekran resmi 2018-04-07 16 10 25

what could be the cause of the problem???

ossamaweb commented 6 years ago

You're requesting the ad while it's already loaded. set adLoaded to the state from eventListener then request if it's not loaded!

ghost commented 6 years ago

I'm having the same problem.. I can't fix it

smcox13 commented 5 years ago

I am having the exact same problem only in Xcode simulator but on the device it works fine... can someone explain more the solution?

tahakhozooie commented 5 years ago

i have this problem too

tahakhozooie commented 5 years ago

Could someone solve this problem?

MutableLoss commented 4 years ago

I had this exact issue as well, but did find that preloading the next interstitial on adClosed worked quite well. Here's an example of what I have in use now:

const [adLoaded, setLoaded] = useState(false)
const { myTrigger } = props

const requestAd = () => AdMobInterstitial.requestAd().catch(_error => setLoaded(false))

AdMobInterstitial.addEventListener('adLoaded', () => setLoaded(true))
// preload next ad after interstitial is consumed
AdMobInterstitial.addEventListener('adClosed', () => requestAd())

// show preloaded ad once the trigger is hit
useEffect(() => {
  if (myTrigger) {
    AdMobInterstitial.showAd().catch(error => console.log(`ShowAd: ${error}`))
  }

  // load on component mount and any state change, when needed
  if (!adLoaded) {
    requestAd()
  }

  return function cleanup() {
    AdMobInterstitial.removeAllListeners()
  }
})

return (
  adLoaded ? <AfterAdComponent /> : <LoadingComponent />
)

This will preload the ad, and when the trigger is hit, show the ad. If the ad isn't ready when it's time to show (which causes the crash), it instead shows the LoadingComponent until the ad is loaded, and then shows the ad. You shouldn't see the LoadingComponent unless the ad is loaded too quickly, otherwise it will simply transition into the ad, and then render the AfterAdComponent without any crashes.

I hope someone else can make as much use of this, as I did. 👍

LAST EDIT: Updated to pattern so that it works with the edge case where re-triggering too fast causes it to show the ad before it's ready.