Installing react-native-google-mobile-ads causes dev-client to crash immediately

I recently upgraded to SDK45 and am trying to replace expo-ads-admob with react-native-google-mobile-ads. To start with, I have commented out all my code related to ads and can run the app fine in Expo Go and in dev-client. Next I run expo install react-native-google-mobile-ads and then do eas build. When I try to launch the resulting dev-client app on iOS, it crashes immediately (even before expo home screen comes up or anything) and I get nothing in the console logs. The only change from my working dev-client is the presence of the react-native-google-mobile-ads library, and I’m not even importing it in the code yet.

What are some things I can try to troubleshoot this issue (e.g. where would I look for an error message)?

Here is my abbreviated app.json (the id values are scrubbed for this post but I’ve double-checked they are correct):

{
  "expo": {
  ...
  },
  "react-native-google-mobile-ads": {
    "android_app_id": "ca-app-pub-[X]",
    "ios_app_id": "ca-app-pub-[Y]"
  }
}

Trying to run it on Expo Go results in the following error:

Invariant Violation: `new NativeEventEmitter()` requires a non-null argument.
at node_modules\expo\build\environment\react-native-logs.fx.js:27:4 in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:95:4 in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:141:19 in handleException
at node_modules\react-native\Libraries\Core\setUpErrorHandling.js:24:6 in handleError
at node_modules\@react-native\polyfills\error-guard.js:49:36 in ErrorUtils.reportFatalError
at node_modules\metro-runtime\src\polyfills\require.js:203:6 in guardedLoadModule
at http://192.168.86.48:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=ios&dev=true&hot=false&strict=false&minify=false:406620:3 in global code

But is this error just because the library can’t run in Expo Go and needs to run in the dev-client?

Ok so working with the maintainer over at react-native-google-mobile-ads, he says this:

If it crashes on startup, that is almost certainly a missing admob id (the app output if you run it from xcode or if you watch it in Console.app will show the exception so you can be sure) - the chain of events that needs to happen for the admob id to be present in a way the native SDK sees it on startup is:

  • admob id in app.json correctly (name of key in the json needs to be correct, consult our example app)
  • pod install runs (not sure how expo triggers this, ‘prebuild’ ?) which installs a build step to run our ios setup shell script
  • run the build, and the ios setup shell script should modify the plist to add the keys in the generated Info.plist in DerivedData or your ios build directory if you specify it
  • run the app, and it should work

Something in that chain of events is not happening and if you search for Info.plist file in the build output directory and examine it you will probably not see the admob id, but if you run our example app you should see it. Something sort of expo specific will be in the mix here.

That does look right, in your app.json. Maybe it’s missing the config plugin entry?

Sure enough, inspecting the info.plist in the built ipa shows the admob key and id did not get copied in. So I tried a fresh new expo project with no changes after expo init, added the keys to app.json and installed react-native-google-mobile-ads, and after eas build I am seeing the dev-client running successfully with ads on both iOS and android. I tried my original app on android and it is also working too.

So now the only issue is that my original app is not getting the admob id copied into the info.plist during the dev-client ios build, which in turn causes the crash. Looking at the build logs, it appears it is doing something with RNGoogleMobileAds:

 Preparing Scoot » Info.plist
› Executing Scoot » Bundle React Native code and images
    the transform cache was reset.
› Generating debug Scoot » Scoot.app.dSYM
› Executing Scoot » [CP] Copy Pods Resources
› Executing Scoot » Upload Debug Symbols to Sentry
› Executing Scoot » [CP-User] [RNGoogleMobileAds] Configuration
› Signing   Scoot » Scoot.app
› Creating  Scoot » Scoot.app
› Archive Succeeded

What could be happening here to cause the info.plist not to get updated with the admob keys?

Here is my full app.json if it helps:

{
  "expo": {
    "name": "Scoot",
    "slug": "scoot",
    "privacy": "public",
    "platforms": [
      "ios",
      "android"
    ],
    "version": "3.0.5",
    "scheme": "scoot",
    "userInterfaceStyle": "automatic",
    "notification": {
      "icon": "./assets/images/icon-96-greyscale.png",
      "color": "#F7D52F",
      "iosDisplayInForeground": true
    },
    "icon": "./assets/images/icon-1024.png",
    "splash": {
      "image": "./assets/images/Scoot9.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "androidStatusBar": {
      "translucent": true
    },
    "updates": {
      "fallbackToCacheTimeout": 30000
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "developmentClient": {
      "silentLaunch": false
    },
    "ios": {
      "supportsTablet": true,
      "requireFullScreen": true,
      "config": {
        "googleSignIn": {
          "reservedClientId": "com.googleusercontent.apps.[XXXX]"
        }
      },
      "bundleIdentifier": "com.thescootapp.scoot",
      "buildNumber": "3.0.5.0",
      "infoPlist": {
        "NSLocationWhenInUseUsageDescription": "Allow app to use location for the purpose of loading weather conditions at the user's location.",
        "NSPhotoLibraryUsageDescription": "Allow app to use photos to be able to set a background image and images for each family member.",
        "NSCalendarsUsageDescription": "Allow Scoot to show your iOS calendar events in this view. You can disable this later in your Scoot Settings if desired.",
        "NSRemindersUsageDescription": "Allow app to integrate your iOS reminder events in with Scoot calendar events.",
        "NSUserTrackingUsageDescription": "This will be used to deliver personalized ads to you.",
        "NSContactsUsageDescription": "Allow app to access your contacts so you can send event reminders to them."
      },
      "appStoreUrl": "https://apps.apple.com/us/app/scoot-family-organizer/id1493870275"
    },
    "android": {
      "package": "com.thescootapp.scoot",
      "versionCode": 3050,
      "permissions": [
        "READ_CALENDAR",
        "WRITE_CALENDAR",
        "READ_EXTERNAL_STORAGE",
        "WRITE_EXTERNAL_STORAGE",
        "ACCESS_COARSE_LOCATION",
        "ACCESS_FINE_LOCATION",
        "FOREGROUND_SERVICE",
        "BILLING",
        "READ_CONTACTS",
        "WRITE_CONTACTS"
      ],
      "adaptiveIcon": {
        "foregroundImage": "./assets/images/scooticon-foreground-1024.png",
        "backgroundImage": "./assets/images/scooticon-background-1024.png",
        "backgroundColor": "#FFFFFF"
      },
      "softwareKeyboardLayoutMode": "resize",
      "useNextNotificationsApi": true,
      "playStoreUrl": "https://play.google.com/store/apps/details?id=com.thescootapp.scoot",
      "googleServicesFile": "./google-services.json"
    },
    "description": "",
    "hooks": {
      "postPublish": [
        {
          "file": "sentry-expo/upload-sourcemaps",
          "config": {
            "organization": "duggster",
            "project": "scoot",
            "authToken": "[secret]"
          }
        }
      ]
    },
    "plugins": [
      "sentry-expo"
    ]
  },
  "react-native-google-mobile-ads": {
    "android_app_id": "ca-app-pub-[X~X]",
    "ios_app_id": "ca-app-pub-[Y~Y]"
  }
}

Hi @duggster

It definitely needs a dev client rather than Expo Go.

Anything that mentions “react-native link” or “pod install” (or, of course, making changes in the android or ios projects) will not work in Expo Go, unless it is already built into the Expo SDK. (e.g. react-native-svg’s installation instructions mention react-native link and pod install, but since it’s included in the Expo SDK it will work in Expo Go.)

The build server runs expo prebuild and later pod install. See here for details:

I assume this would work. If not, you could maybe run this script from the eas-build-post-install hook.

I have no idea what the script does. It might also be possible to add stuff to the “infoPlist” section of your app.json (or app.config.js) instead of running the script.

OK, I’ve found the script now and am looking through it. So far, I see it calls both Ruby and Python3 and I don’t know off hand if the build servers have Python3 installed. So that could possibly be a problem. But the build logs should say something like the following if it’s missing:

python3 not found, app.json file processing error.

I see the script basically just takes the react-native-google-mobile-ads part of app.json and adds a base64-encoded copy of it and also possibly some parts of it to two different Info.plist files. I’m not sure what those Info.plist files are. If it was just the normal Info.plist file then it should be enough to add this stuff to expo.ios.infoPlist. I think the best way to do that would be using app.config.js so that you could generate the base64-encoded version on the fly. But since there are two Info.plist files… I suppose this won’t be sufficient.

I did not notice a config plugin mentioned in react-native-google-mobile-ads’ installation instructions. Is there one?

OK, then it seems the script is being called and Python3 is installed on the build servers.

Check the build logs for the output of the script. You should see something similar to the following:

info: -> RNGoogleMobileAds build script started
info: 1) Locating app.json file:
info:      (1 of 2) Searching in '...' for a app.json file.
info:      app.json found at ...
info: 2) Injecting Info.plist entries: 
[list of plist entries here]
[followed by several lines like the following]
info:      setting plist entry '$1' of type '$2' in file '$4'
info: <- RNGoogleMobileAds build script finished

@wodin thank you so much, your research and pointers helped me find the issue! Here’s what I found in the xcode logs:

info: -> RNGoogleMobileAds build script started
info: 1) Locating app.json file:
info:      (1 of 2) Searching in '/Users/expo/workingdir/build' for a app.json file.
info:      app.json found at /Users/expo/workingdir/build/app.json
-e:47: syntax error, unexpected local variable or method, expecting ')'
...eather conditions at the user's location.",
...                              ^
-e:47: syntax error, unexpected string literal
...itions at the user's location.",
...                              ^
-e:48: syntax error, unexpected constant, expecting end-of-input
..."NSPhotoLibraryUsageDescription": "Allow app to use photos t...
... ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
info: 2) Injecting Info.plist entries: 
    ->  0) google_mobile_ads_json_raw string e30=
info:      setting plist entry 'google_mobile_ads_json_raw' of type 'string' in file '/Users/expo/Library/Developer/Xcode/DerivedData/Scoot-dxafajfnmudobohdoabbyjtwdhpq/Build/Intermediates.noindex/ArchiveIntermediates/Scoot/BuildProductsPath/Debug-iphoneos/Scoot.app/Info.plist'
info:      setting plist entry 'google_mobile_ads_json_raw' of type 'string' in file '/Users/expo/Library/Developer/Xcode/DerivedData/Scoot-dxafajfnmudobohdoabbyjtwdhpq/Build/Intermediates.noindex/ArchiveIntermediates/Scoot/BuildProductsPath/Debug-iphoneos/Scoot.app.dSYM/Contents/Info.plist'
info: <- RNGoogleMobileAds build script finished

Looks like the apostrophe in my permissions strings elsewhere in my app.json caused the react-native-google-mobile-ads build script to break. Not sure if I needed to escape that character in some way or not, but either way I changed the string to just not use an apostrophe and it is all working now. I also posted over on the other forum in case they can update the script to be more resilient for this case. Really appreciate all the help!

1 Like

Glad I could help.

The quoting in the script is a bit nasty, so that makes sense. I think doing this in a config plugin would be a lot cleaner. I’m just unsure about the two Info.plist files. I think Expo’s Info.plist handling is just for the one in ios/appname/Info.plist.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.