What have I done so far...
I am using Tasks.await
blocking mechanism for firebase calls in worker threads for avoiding callbacks.
I am using a worker thread (JobIntentService) for some initialization progress. JobIntentService starts when app opens and runs only once. below is my worker thread code
if (isDeviceConnectedToInternet()) {
Tasks.await(FirebaseConfigHelper.getRemoteConfig().fetchAndActivate()); //error here
initFirebaseConfigVariables();
// other codes
}
//FirebaseConfigHelper.java
public static FirebaseRemoteConfig getRemoteConfig() {
FirebaseRemoteConfig mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
mFirebaseRemoteConfig.setDefaultsAsync(R.xml.remote_config_defaults);
return mFirebaseRemoteConfig;
}
I am using
implementation 'com.google.firebase:firebase-config:19.0.4'
About the error
It is working fine in testing devices. I tested in another 15 Devices in Firebase Test Lab. There was no issues at all. but when I released to production this error occurred in some specific Mi and Samsung devices.
Error log
I was able to get only this log, because error happens in production
java.util.concurrent.ExecutionException:
com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException:
The client had an error while calling the backend! at
com.google.android.gms.tasks.Tasks.zzb(Unknown Source:61) at
com.google.android.gms.tasks.Tasks.await(Unknown Source:23) at
com.maju.myapp.service.SyncWithFirebaseJobIntentService.syncWithFirebaseConfig(SyncWithFirebaseJobIntentService.java:207) at
com.maju.myapp.service.SyncWithFirebaseJobIntentService.onHandleWork(SyncWithFirebaseJobIntentService.java:55) at
androidx.core.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:392) at
androidx.core.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:383) at
android.os.AsyncTask$3.call(AsyncTask.java:378) at
java.util.concurrent.FutureTask.run(FutureTask.java:266) at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at
java.lang.Thread.run(Thread.java:919)Caused by:
com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException:
The client had an error while calling the backend! at
com.google.firebase.remoteconfig.internal.ConfigFetchHttpClient.fetch(com.google.firebase:firebase-config@@19.0.4:194) at
com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackend(com.google.firebase:firebase-config@@19.0.4:278) at
com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackendAndCacheResponse(com.google.firebase:firebase-config@@19.0.4:251) at
com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchIfCacheExpiredAndNotThrottled(com.google.firebase:firebase-config@@19.0.4:191) at
com.google.firebase.remoteconfig.internal.ConfigFetchHandler.lambda$fetch$0(com.google.firebase:firebase-config@@19.0.4:160) at
com.google.firebase.remoteconfig.internal.ConfigFetchHandler$$Lambda$1.then(Unknown
Source:4) at com.google.android.gms.tasks.zzf.run(Unknown
Source:2) ... 3 moreCaused by: java.net.ConnectException: Failed to
connect to
firebaseremoteconfig.googleapis.com/2404:6800:4007:809::200a:443 at
com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:147) at
com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116) at
com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186) at
com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128) at
com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97) at
com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289) at
com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232) at
com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465) at
com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131) at
com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262) at
com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219) at
com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30) at
com.google.firebase.remoteconfig.internal.ConfigFetchHttpClient.setFetchRequestBody(com.google.firebase:firebase-config@@19.0.4:321) at
com.google.firebase.remoteconfig.internal.ConfigFetchHttpClient.fetch(com.google.firebase:firebase-config@@19.0.4:182) ...
9 more
(Callbacks are making code ugly and messy, for making clean code I prefer Tasks.await)
An API that makes an app crash, with no option to catch the exception, when a device is offline or the connection drops while accessing it. Amazing. But interestingly, using addOnCompleteListener
instead of await
works fine.
Hence there's a solution, add and use this helper instead:
suspend fun fetchAndActivateRemoteConfig() = suspendCancellableCoroutine {
Firebase.remoteConfig.fetchAndActivate().addOnCompleteListener { _ ->
it.resume(Unit)
}
}
It's important that you do not try to access the result of addOnCompleteListener
, because doing so may trigger yet another crash that Google really does not want to fix: https://github.com/firebase/firebase-android-sdk/issues/5540
Fatal Exception: com.google.android.gms.tasks.RuntimeExecutionException: com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException: Firebase Installations failed to get installation auth token for fetch.
at com.google.android.gms.tasks.zzw.getResult(com.google.android.gms:play-services-tasks@@18.0.2:3)
If you do require the true/false result, you'll need to resort to manually checking Firebase.remoteConfig.info.lastFetchStatus
after this call, which doesn't seem to crash.
I contacted Firebase Support for this issue
They said
This happens if the connection of the device user had an issue as our SDK tried to call the fetch of data, and it would cause “The client had an error while calling the backend!” error. With that, it looks like you’re doing the right thing on validating the connectivity on your recent updates before you fetch the remote config data. You can check our implementation here that you could visualize our call that would trigger this issue.
You could use the Android network debugger to simulate the network calls, so you could catch your handling mechanism to ensure that your actual device has a proper connectivity on doing the fetch.
So the problem might be the network connectivity of the device. I check the network connectivity in recent updates. but still I am getting this error in some devices. The reason may be the the poor quality of the Internet connection at the moment of the devices (@Tash Pemhiwa suggested in comment)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With