After adding native Android dependencies the app was crashing right after startup. This was happening on both Android emulators and live devices. Using abd logcat
I was able to see the error causing the crash:
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/common/api/Api$zz
This was hard to find a fix for, it took me–cumulatively–about two work days to get it fixed. 😬 Google searches for the error return quite a few other folks with the same or similar issue. Using those examples I was able to piece something together that worked for our situation.
react-native-info
React Native Environment Info:
System:
OS: macOS 10.14
CPU: (8) x64 Intel(R) Core(TM) i7-3615QM CPU @ 2.30GHz
Memory: 29.81 MB / 8.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 8.12.0 - ~/.nvm/v8.12.0/bin/node
Yarn: 1.12.3 - /usr/local/bin/yarn
npm: 6.4.1 - ~/.nvm/v8.12.0/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 12.0, macOS 10.14, tvOS 12.0, watchOS 5.0
Android SDK:
API Levels: 27, 28
Build Tools: 27.0.3, 28.0.3
IDEs:
Android Studio: 3.2 AI-181.5540.7.32.5056338
Xcode: 10.0/10A255 - /usr/bin/xcodebuild
npmPackages:
react: 16.6.1 => 16.6.1
react-native: 0.57.5 => 0.57.5
npmGlobalPackages:
react-native-cli: 2.0.1
react-native: 0.57.5
We included https://github.com/zo0r/react-native-push-notification in the project for push notification support. Bringing that into the project via settings.gradle
and app/build.gradle
triggered the crash. Nothing beyond including it was needed to cause issues.
After much Googling it seemed that react-native-push-notification
's version of play-services-gcm
and firebase-messaging
was causing conflicts with other project dependenies, leading to the crash. I don't fully understand how the gradle dependencies work and why this is an issue, but it was.
In tolu360/react-native-google-places#142 (comment) the author outlines a fix for the same issue relating to a different module. The idea there is to exclude transitive module dependencies https://docs.gradle.org/current/userguide/managing_transitive_dependencies.html#sec:excluding_transitive_module_dependencies Again, even after reading that I'm still hazy on how it all fits together, but here we are.
Before making a similar change to our gradle setup, I wanted to understand more about what the push notification module was doing. Specifically what version of the conflicting deps it required. In https://github.com/zo0r/react-native-push-notification/blob/master/android/build.gradle#L55 we can see that it's requesting versions of play-services-gcm
and firebase-messaging
based on if we have global version settings. In our case we have googlePlayServicesVersion = "11.0.0"
in our global project build.gradle
, but nothing for firebaseVersion
so it would use whatever the default is there.
OK, so to exclude those troublesome dependencies we change our app/build.gradle
from:
...
implementation project(':react-native-push-notification')
...
to:
implementation (project(':react-native-push-notification')) {
exclude group: 'com.google.android.gms', module: 'play-services-gcm'
exclude group: 'com.google.firebase', module: 'firebase-messaging'
}
implementation "com.google.android.gms:play-services-gcm:16.0.0"
implementation "com.google.firebase:firebase-messaging:17.3.4"
...
Included in this gist are full copies of our build.gradle
and app/build.gradle
files so you can see the changes in context.
So–as far as I can tell–what we're saying there is; "hey gradle, don't use react-native-push-notification's versions of play-services-gcm
and firebase-messaging
, instead use these specific versions here." And again run react-native run-android
and open the app. Still crashing with a similar error. The error showed me that we had another third party module with conflicting dependencies. This time it was https://github.com/Agontuk/react-native-geolocation-service/blob/master/android/build.gradle#L29
The fix for that is the same process, update app/build.gradle
from:
...
implementation project(':react-native-geolocation-service')
...
to:
...
implementation (project(':react-native-geolocation-service')) {
exclude group: 'com.google.android.gms', module: 'play-services-location'
}
implementation "com.google.android.gms:play-services-location:16.0.0"
...
and again react-native run-android
and open the app. No more crashing.