Skip to content

Commit 6985af9

Browse files
authored
Handle jniresultcallback not loading due to lack of gms.Task. (#953)
* Handle jniresultcallback not loading due to lack of gms.Task. * Make initialization of google_play_services optional in app. Check for initialization in util.cc. * Add alternate inclusion method for app that doesn't require play-services. * Add readme note * Return an error if you try to use ModuleInitializer without play-services.
1 parent 1d1bba1 commit 6985af9

File tree

8 files changed

+126
-55
lines changed

8 files changed

+126
-55
lines changed

Android/firebase_dependencies.gradle

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,24 @@ import org.gradle.util.ConfigureUtil;
1717
// A map of library to the dependencies that need to be added for it.
1818
def firebaseDependenciesMap = [
1919
'app' : ['com.google.firebase:firebase-analytics:21.0.0'],
20+
'play_services' : ['com.google.android.gms:play-services-base:18.0.1'],
2021
'admob' : ['com.google.firebase:firebase-ads:19.8.0',
21-
'com.google.firebase:firebase-analytics:21.0.0',
22-
'com.google.android.gms:play-services-base:18.0.1'],
23-
'analytics' : ['com.google.firebase:firebase-analytics:21.0.0',
24-
'com.google.android.gms:play-services-base:18.0.1'],
22+
'com.google.firebase:firebase-analytics:21.0.0'],
23+
'analytics' : ['com.google.firebase:firebase-analytics:21.0.0'],
2524
'auth' : ['com.google.firebase:firebase-auth:21.0.3'],
2625
'database' : ['com.google.firebase:firebase-database:20.0.5'],
2726
'dynamic_links' : ['com.google.firebase:firebase-dynamic-links:21.0.1'],
2827
'firestore' : ['com.google.firebase:firebase-firestore:24.1.2'],
2928
'functions' : ['com.google.firebase:firebase-functions:20.1.0'],
30-
'installations' : ['com.google.firebase:firebase-installations:17.0.1',
31-
'com.google.android.gms:play-services-base:18.0.1'],
29+
'installations' : ['com.google.firebase:firebase-installations:17.0.1'],
3230
'invites' : ['com.google.firebase:firebase-invites:17.0.0'],
3331
// Messaging has an additional local dependency to include.
3432
'messaging' : ['com.google.firebase:firebase-messaging:23.0.4',
3533
'firebase_cpp_sdk.messaging:messaging_java',
3634
'androidx.core:core:1.6.0-alpha03',
37-
'com.google.flatbuffers:flatbuffers-java:1.12.0',
38-
'com.google.android.gms:play-services-base:18.0.1'],
35+
'com.google.flatbuffers:flatbuffers-java:1.12.0'],
3936
'performance' : ['com.google.firebase:firebase-perf:20.0.6'],
40-
'remote_config' : ['com.google.firebase:firebase-config:21.1.0',
41-
'com.google.android.gms:play-services-base:18.0.1'],
37+
'remote_config' : ['com.google.firebase:firebase-config:21.1.0'],
4238
'storage' : ['com.google.firebase:firebase-storage:20.0.1'],
4339
'testlab' : []
4440
]
@@ -68,6 +64,10 @@ class Dependencies {
6864

6965
def getApp() {
7066
libSet.add('app')
67+
libSet.add('play_services')
68+
}
69+
def getAppWithoutPlayServices() {
70+
libSet.add('app')
7171
}
7272
def getAdmob() {
7373
libSet.add('admob')
@@ -146,6 +146,7 @@ project.afterEvaluate {
146146
// App is required, so add it if it wasn't included.
147147
if (!firebaseCpp.dependencies.libSet.contains('app')) {
148148
firebaseCpp.dependencies.libSet.add('app')
149+
firebaseCpp.dependencies.libSet.add('play_services')
149150
}
150151

151152
for (String lib : firebaseCpp.dependencies.libSet) {

admob/integration_test/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ android {
7575
}
7676

7777
apply from: "$gradle.firebase_cpp_sdk_dir/Android/firebase_dependencies.gradle"
78+
// AdMob doesn't require play-services-base as a dependency, so include the
79+
// version of App without it, to ensure the C++ SDK also doesn't require it.
7880
firebaseCpp.dependencies {
81+
appWithoutPlayServices
7982
admob
8083
}
8184

app/src/app_android.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ METHOD_LOOKUP_DEFINITION(
150150
namespace {
151151

152152
static int g_methods_cached_count = 0;
153+
static bool g_initialized_google_play_services = false;
153154

154155
void ReleaseClasses(JNIEnv* env);
155156

@@ -165,11 +166,13 @@ bool CacheMethods(JNIEnv* env, jobject activity) {
165166
if (!(app::CacheMethodIds(env, activity) &&
166167
options_builder::CacheMethodIds(env, activity) &&
167168
options::CacheMethodIds(env, activity) &&
168-
version_registrar::CacheMethodIds(env, activity) &&
169-
google_play_services::Initialize(env, activity))) {
169+
version_registrar::CacheMethodIds(env, activity))) {
170170
ReleaseClasses(env);
171171
return false;
172172
}
173+
if (google_play_services::Initialize(env, activity)) {
174+
g_initialized_google_play_services = true;
175+
}
173176
}
174177
return true;
175178
}
@@ -182,7 +185,10 @@ void ReleaseClasses(JNIEnv* env) {
182185
options_builder::ReleaseClass(env);
183186
options::ReleaseClass(env);
184187
version_registrar::ReleaseClass(env);
185-
google_play_services::Terminate(env);
188+
if (g_initialized_google_play_services) {
189+
google_play_services::Terminate(env);
190+
g_initialized_google_play_services = false;
191+
}
186192
util::Terminate(env);
187193
}
188194
}

app/src/util.cc

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#include "app/src/include/firebase/internal/platform.h"
2626

2727
#if FIREBASE_PLATFORM_ANDROID
28+
#include "app/src/google_play_services/availability_android.h"
2829
#include "app/src/include/google_play_services/availability.h"
30+
#include "app/src/util_android.h"
2931
#endif // FIREBASE_PLATFORM_ANDROID
3032
#include "app/src/include/firebase/internal/mutex.h"
3133
#include "app/src/log.h"
@@ -77,32 +79,49 @@ static void PerformInitialize(ModuleInitializerData* data) {
7779

7880
#if FIREBASE_PLATFORM_ANDROID
7981
if (init_result == kInitResultFailedMissingDependency) {
80-
// On Android, we need to update or activate Google Play services
81-
// before we can initialize this Firebase module.
82-
LogWarning("Google Play services unavailable, trying to fix.");
83-
84-
Future<void> make_available = google_play_services::MakeAvailable(
85-
data->app->GetJNIEnv(), data->app->activity());
86-
87-
make_available.OnCompletion(
88-
[](const Future<void>& result, void* ptr) {
89-
ModuleInitializerData* data =
90-
reinterpret_cast<ModuleInitializerData*>(ptr);
91-
if (result.status() == kFutureStatusComplete) {
92-
if (result.error() == 0) {
93-
LogInfo("Google Play services now available, continuing.");
94-
PerformInitialize(data);
95-
} else {
96-
LogError("Google Play services still unavailable.");
97-
int num_remaining = data->init_fns.size() - data->init_fn_idx;
98-
data->future_impl.Complete(
99-
data->future_handle_init, num_remaining,
100-
"Unable to initialize due to missing Google Play services "
101-
"dependency.");
82+
// Note: If Initialize here succeeds, google_play_services::Terminate
83+
// is called in the OnCompletion handler below. Note that these
84+
// are reference-counted so it's safe to init/terminate an extra time..
85+
if (google_play_services::Initialize(data->app->GetJNIEnv(),
86+
data->app->activity())) {
87+
// On Android, we need to update or activate Google Play services
88+
// before we can initialize this Firebase module.
89+
LogWarning("Google Play services unavailable, trying to fix.");
90+
91+
Future<void> make_available = google_play_services::MakeAvailable(
92+
data->app->GetJNIEnv(), data->app->activity());
93+
94+
make_available.OnCompletion(
95+
[](const Future<void>& result, void* ptr) {
96+
ModuleInitializerData* data =
97+
reinterpret_cast<ModuleInitializerData*>(ptr);
98+
if (result.status() == kFutureStatusComplete) {
99+
if (result.error() == 0) {
100+
LogInfo("Google Play services now available, continuing.");
101+
PerformInitialize(data);
102+
google_play_services::Terminate(data->app->GetJNIEnv());
103+
} else {
104+
LogError("Google Play services still unavailable.");
105+
int num_remaining = data->init_fns.size() - data->init_fn_idx;
106+
data->future_impl.Complete(data->future_handle_init,
107+
num_remaining,
108+
"Unable to initialize due to "
109+
"missing Google Play services "
110+
"dependency.");
111+
google_play_services::Terminate(util::GetJNIEnvFromApp());
112+
}
102113
}
103-
}
104-
},
105-
data);
114+
},
115+
data);
116+
} else {
117+
int num_remaining = data->init_fns.size() - data->init_fn_idx;
118+
data->future_impl.Complete(
119+
data->future_handle_init, num_remaining,
120+
"Could not run Google Play services update due to app "
121+
"misconfiguration. Please add "
122+
"com.google.android.gms:play-services-base as an Android "
123+
"dependency to enable this functionality.");
124+
}
106125
}
107126
#else // !FIREBASE_PLATFORM_ANDROID
108127
// Outside of Android, we shouldn't get kInitResultFailedMissingDependency.

app/src/util_android.cc

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ static pthread_mutex_t g_task_callbacks_mutex;
245245
// classes.
246246
static std::vector<jobject>* g_class_loaders;
247247

248+
static bool g_jniresultcallback_loaded = false;
249+
248250
JNIEXPORT void JNICALL JniResultCallback_nativeOnResult(
249251
JNIEnv* env, jobject clazz, jobject result, jboolean success,
250252
jboolean cancelled, jstring status_message, jlong callback_fn_param,
@@ -393,7 +395,10 @@ static void ReleaseClasses(JNIEnv* env) {
393395
uri::ReleaseClass(env);
394396
object::ReleaseClass(env);
395397
uribuilder::ReleaseClass(env);
396-
jniresultcallback::ReleaseClass(env);
398+
if (g_jniresultcallback_loaded) {
399+
jniresultcallback::ReleaseClass(env);
400+
g_jniresultcallback_loaded = false;
401+
}
397402
JavaThreadContext::Terminate(env);
398403
#if defined(FIREBASE_ANDROID_FOR_DESKTOP)
399404
java_uri::ReleaseClass(env);
@@ -526,12 +531,13 @@ bool Initialize(JNIEnv* env, jobject activity_object) {
526531
return false;
527532
}
528533

529-
if (!(jniresultcallback::CacheClassFromFiles(env, activity_object,
530-
&embedded_files) &&
531-
jniresultcallback::CacheMethodIds(env, activity_object) &&
532-
jniresultcallback::RegisterNatives(env, &kJniCallbackMethod, 1))) {
533-
return false;
534-
}
534+
// With a subset of dependencies, jniresultcallback can't be loaded due to
535+
// lack of gms.Task. This is fine - just make sure not to try terminating it.
536+
g_jniresultcallback_loaded =
537+
(jniresultcallback::CacheClassFromFiles(env, activity_object,
538+
&embedded_files) &&
539+
jniresultcallback::CacheMethodIds(env, activity_object) &&
540+
jniresultcallback::RegisterNatives(env, &kJniCallbackMethod, 1));
535541

536542
if (!JavaThreadContext::Initialize(env, activity_object, embedded_files)) {
537543
return false;

release_build_files/Android/firebase_dependencies.gradle

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,24 @@ import org.gradle.util.ConfigureUtil;
1717
// A map of library to the dependencies that need to be added for it.
1818
def firebaseDependenciesMap = [
1919
'app' : ['com.google.firebase:firebase-analytics:21.0.0'],
20+
'play_services' : ['com.google.android.gms:play-services-base:18.0.1'],
2021
'admob' : ['com.google.firebase:firebase-ads:19.8.0',
21-
'com.google.firebase:firebase-analytics:21.0.0',
22-
'com.google.android.gms:play-services-base:18.0.1'],
23-
'analytics' : ['com.google.firebase:firebase-analytics:21.0.0',
24-
'com.google.android.gms:play-services-base:18.0.1'],
22+
'com.google.firebase:firebase-analytics:21.0.0'],
23+
'analytics' : ['com.google.firebase:firebase-analytics:21.0.0'],
2524
'auth' : ['com.google.firebase:firebase-auth:21.0.3'],
2625
'database' : ['com.google.firebase:firebase-database:20.0.5'],
2726
'dynamic_links' : ['com.google.firebase:firebase-dynamic-links:21.0.1'],
2827
'firestore' : ['com.google.firebase:firebase-firestore:24.1.2'],
2928
'functions' : ['com.google.firebase:firebase-functions:20.1.0'],
30-
'installations' : ['com.google.firebase:firebase-installations:17.0.1',
31-
'com.google.android.gms:play-services-base:18.0.1'],
29+
'installations' : ['com.google.firebase:firebase-installations:17.0.1'],
3230
'invites' : ['com.google.firebase:firebase-invites:17.0.0'],
3331
// Messaging has an additional local dependency to include.
3432
'messaging' : ['com.google.firebase:firebase-messaging:23.0.4',
3533
'com.google.firebase.messaging.cpp:firebase_messaging_cpp@aar',
3634
'androidx.core:core:1.6.0-alpha03',
37-
'com.google.flatbuffers:flatbuffers-java:1.12.0',
38-
'com.google.android.gms:play-services-base:18.0.1'],
35+
'com.google.flatbuffers:flatbuffers-java:1.12.0'],
3936
'performance' : ['com.google.firebase:firebase-perf:20.0.6'],
40-
'remote_config' : ['com.google.firebase:firebase-config:21.1.0',
41-
'com.google.android.gms:play-services-base:18.0.1'],
37+
'remote_config' : ['com.google.firebase:firebase-config:21.1.0'],
4238
'storage' : ['com.google.firebase:firebase-storage:20.0.1'],
4339
'testlab' : []
4440
]
@@ -49,6 +45,10 @@ class Dependencies {
4945

5046
def getApp() {
5147
libSet.add('app')
48+
libSet.add('play_services')
49+
}
50+
def getAppWithoutPlayServices() {
51+
libSet.add('app')
5252
}
5353
def getAdmob() {
5454
libSet.add('admob')
@@ -121,6 +121,7 @@ project.afterEvaluate {
121121
// App is required, so add it if it wasn't included.
122122
if (!firebaseCpp.dependencies.libSet.contains('app')) {
123123
firebaseCpp.dependencies.libSet.add('app')
124+
firebaseCpp.dependencies.libSet.add('play_services')
124125
}
125126

126127
for (String lib : firebaseCpp.dependencies.libSet) {

release_build_files/readme.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,32 @@ Android SDK (20.x.x). Please ensure that you use firebase-ads version 19.8.0 in
166166
conjunction with the latest firebase-analytics version to maintain
167167
compatibility.
168168

169+
#### Gradle dependency file
170+
171+
Firebase C++ includes an `Android/firebase_dependencies.gradle` file
172+
that helps you include the correct Android dependencies and native C++
173+
libraries for each Firebase product. To use it, include the following
174+
in your build.gradle file (you can omit any Firebase products you
175+
aren't using):
176+
177+
```
178+
apply from: "$gradle.firebase_cpp_sdk_dir/Android/firebase_dependencies.gradle"
179+
firebaseCpp.dependencies {
180+
app // Recommended for all apps using Firebase.
181+
admob
182+
analytics
183+
auth
184+
database
185+
dynamicLinks
186+
firestore
187+
functions
188+
installations
189+
messaging
190+
remoteConfig
191+
storage
192+
}
193+
```
194+
169195
### iOS Dependencies
170196

171197
iOS users can include either xcframeworks or static libraries depending upon their
@@ -572,6 +598,12 @@ workflow use only during the development of your app, not for publicly shipping
572598
code.
573599

574600
## Release Notes
601+
### Upcoming release
602+
- Changes
603+
- General (Android): Fixed a bug that required Android apps to include
604+
`com.google.android.gms:play-services-base` as an explicit dependency when
605+
only using AdMob, Analytics, Remote Config, or Messaging.
606+
575607
### 9.0.0
576608
- Changes
577609
- General (iOS): Firebase C++ on iOS is now built using Xcode 13.3.1.

remote_config/integration_test/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ android {
7575
}
7676

7777
apply from: "$gradle.firebase_cpp_sdk_dir/Android/firebase_dependencies.gradle"
78+
// Remote Config doesn't require play-services-base as a dependency, so include
79+
// the version of App without it, to ensure the C++ SDK also doesn't require it.
7880
firebaseCpp.dependencies {
81+
appWithoutPlayServices
7982
remoteConfig
8083
}
8184

0 commit comments

Comments
 (0)