Android ChromeCast RuntimeException : Remote load failed. No local fallback found - android

I am using cast feature in my application. It was working fine but suddenly I can see the increase in the number of crashes on play store console.
I am initializing CastContext properly as defined in the guidelines and Moreover, I am checking that device is compatible or not before calling this method CastContext.getSharedInstance(context) So that should not be an issue.
I am not able to reproduce this crash even on emulators with or without google-play-services one.
Any help will be appreciated.
Crash :
Fatal Exception: java.lang.RuntimeException: Unable to start activity
ComponentInfo{... .activity.TVActivityPhone}:
java.lang.RuntimeException: com.google.android.gms.dynamite.DynamiteModule$zza: Remote load
failed. No local fallback found. at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2677)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2747)
at android.app.ActivityThread.access$900(ActivityThread.java:187) at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1584)
at android.os.Handler.dispatchMessage(Handler.java:111) at
android.os.Looper.loop(Looper.java:194) at
android.app.ActivityThread.main(ActivityThread.java:5877) at
java.lang.reflect.Method.invoke(Method.java) at
java.lang.reflect.Method.invoke(Method.java:372) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815) Caused
by java.lang.RuntimeException:
com.google.android.gms.dynamite.DynamiteModule$zza: Remote load
failed. No local fallback found.
Code I am getting an error inside the if the condition that means, it's not about the google play service availability.
if (googlePlayServicesVerified(context)) { // checking (result==ConnectionResult.SUCCES)
Log.d("TAG", "instantiated");
castContext = CastContext.getSharedInstance(context);
} else {
Log.e(TAG, "FAILED");
}
Filed bug to google:
https://issuetracker.google.com/issues/65359941
** Update **
Check these two issues :
https://issuetracker.google.com/issues/65359941
https://issuetracker.google.com/issues/79405933
The temporary solution is in my answer.

This is the temporary solution.
1) Your app should always check GPS version before using any Cast APIs
2) Allow CastContext.getSharedInstance() to fail. Probably throw/catch an exception (or alternatively return null).
3) Make sure, you don't break anything if the dynamite module fails to load. There are some UI widgets that are initialized implicitly which calls CastContext.getSharedInstance(), such as MiniControllerFragment. You should avoid letting it crash if dynamite fails to load.
public static boolean isAvailable(Context context)
{
GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
return isGooglePlayServicesAvailable(context, availability) &&
isCastContextAvailable(context);
}
public static boolean isAvailable(Context context) {
if (googlePlayServicesVerified(context)) {
try {
castContext = CastContext.getSharedInstance(context);
Log.d(TAG, "CastContext instantiated");
} catch (Exception e) {
Log.report(e);
castContext = null;
}
} else {
CrashReporter.report("CastContext FAILED to be instantiated : googlePlayServicesVerified() has failed."));
castContext = null;
}
}

I get this issue when play services are out of date (mainly on emulators running API 24). This worked for me:
GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
int resultCode = googleApiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED) {
googleApiAvailability.getErrorDialog(this, resultCode, 1000).show();
return;
}
startApp();
I run this code in an Activity which checks if MainActivity should be started

Related

Android Pie (9.0) WebView in multi-process

Starting Android Pie (API 28), Google isn't allowing using a single WebView instance in 2 different processes.
Documentation: https://developer.android.com/reference/android/webkit/WebView.html#setDataDirectorySuffix(java.lang.String)
As required, I called WebView.setDataDirectorySuffix("dir_name_no_separator") but unfortunately, I get an exception.
I tried to call this method inside the 2nd process Service onCreate().
java.lang.RuntimeException: Unable to create service com.myapp.service.MyService: java.lang.IllegalStateException: Can't set data directory suffix: WebView already initialized
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3544)
at android.app.ActivityThread.access$1300(ActivityThread.java:199)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1666)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.IllegalStateException: Can't set data directory suffix: WebView already initialized
at android.webkit.WebViewFactory.setDataDirectorySuffix(WebViewFactory.java:136)
at android.webkit.WebView.setDataDirectorySuffix(WebView.java:2165)
at com.myapp.service.MyService.onCreate(MyService.java:134)
I couldn't find any reason for that exception. I didn't call this method twice nor I called it in my main process. Any ideas?
Solved.
My project hosts AdMob ads and I call the MobileAds.initialize() method inside my Application class onCreate(). The ads initializer loads a WebView which is now forbidden to do in a new process before you call the WebView.setDataDirectorySuffix("dir_name_no_separator") method.
When the second process is created, it also goes through the same application create flow, meaning it calls the same onCreate() inside the Application class, which calls the MobileAds.initialize() that tries to create a new WebView instance and by that causes the crash.
IllegalStateException: Can't set data directory suffix: WebView already initialized
How I solved this?
I get the process name using the below method and check if it's my main process - call the MobileAds.initialize() method and if it's my second process, call the
WebView.setDataDirectorySuffix("dir_name_no_separator") method.
Get process name:
public static String getProcessName(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
if (processInfo.pid == android.os.Process.myPid()) {
return processInfo.processName;
}
}
return null;
}
Application class onCreate():
if (!Utils.getProcessName(this).equals("YOUR_SECOND_PROCESS_NAME")) {
MobileAds.initialize(this);
} else {
WebView.setDataDirectorySuffix("dir_name_no_separator")
}
To summarize the fix with all the improvements, this is the code in Kotlin:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (packageName != Application.getProcessName()) {
WebView.setDataDirectorySuffix(Application.getProcessName())
}
}
Add it to your Application class to onCreate() method.
Note this is will only fix problem with maximum 2 processes. If your app is using more, you have to provide different WebView suffix for each of them.
when error due to ads, then in application class
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val process = getProcessName()
if (packageName != process) WebView.setDataDirectorySuffix(process)
}
MobileAds.initialize(this)
AudienceNetworkAds.initialize(this)
} catch (e: Error) {
Timber.e(e)
} catch (e: Exception) {
Timber.e(e)
}

GoogleApiClient builder failing to build

I'm implementing Google Smart Lock into an app, and I was having no trouble with the Api Client building before. In fact, I was finalizing some syntax changes and cleaning up the code (didn't even touch the code that initializes the Api Client), and my app now dies when build() is called on the Api Client builder, due to abstract method zza. Here is the error being displayed:
java.lang.AbstractMethodError: abstract method "com.google.android.gms.common.api.Api$zze com.google.android.gms.common.api.Api$zza.zza(android.content.Context, android.os.Looper, com.google.android.gms.common.internal.zzq, java.lang.Object, com.google.android.gms.common.api.GoogleApiClient$ConnectionCallbacks, com.google.android.gms.common.api.GoogleApiClient$OnConnectionFailedListener)"
at com.google.android.gms.common.api.GoogleApiClient$Builder.build(Unknown Source)
I have no clue why it suddenly started failing, and I couldn't find any changes I made that would have caused this error. Why isn't that abstract method being overridden? It's nested deep inside the library so I don't understand how I could have affected it.
I wrapped the Google Api Client calls in a manager I named CredentialManager. Here is the code I used to initialize the client:
public CredentialManager(ContextProvider contextProvider) {
mContextProvider = contextProvider;
mCredentialsApiClient = new GoogleApiClient.Builder(mContextProvider.getContext())
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(CredentialManager.TAG, "Api connected");
}
#Override
public void onConnectionSuspended(int i) {
Log.i(CredentialManager.TAG, "Connection suspended with status " + i);
}
})
.enableAutoManage(mContextProvider.getContext(), connectionFailedResult -> {
if (connectionFailedResult.hasResolution()) {
try {
connectionFailedResult.startResolutionForResult(
mContextProvider.getContext(),
CredentialManager.Codes.RESOLVE_CONNECTION_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
// Unable to resolve, log error
Log.e(CredentialManager.TAG, "Resolution failed: " + e.getMessage());
}
} else {
//instead of displaying a dialog, just let the user continue and login manually.
Log.e(CredentialManager.TAG, "Connection failed: " + connectionFailedResult.getErrorMessage());
}
})
.addApi(Auth.CREDENTIALS_API)
.build();
}
If you have any insight as to what is causing this error, please let me know. I've scoured the internet for anyone that has seen something like this before, but couldn't find anything.
The issue was that some google play services dependencies had their versions updated and not the play-services-auth dependency used for google smart lock. The apk would compile fine, but crash when the Google Api Client was trying to initialize. The fix was to make all the versions the same, and invalidate cache + restart android studio, recompile, and run.

How to avoid TagManager "IllegalStateException: Results have already been set"

I have recently introduced Google TagManager into my Android app in order to push changes to app config without needing to redeploy the app.
But I am getting instances of:
java.lang.IllegalStateException: Results have already been set
at com.google.android.gms.common.internal.p.a(Unknown Source)
at com.google.android.gms.common.api.b$a.a(Unknown Source)
at com.google.android.gms.tagmanager.ed.a(Unknown Source)
at com.google.android.gms.tagmanager.ed.a(Unknown Source)
at com.google.android.gms.tagmanager.ed$b.a(Unknown Source)
at com.google.android.gms.tagmanager.ed$b.a(Unknown Source)
at com.google.android.gms.tagmanager.cj.c(Unknown Source)
at com.google.android.gms.tagmanager.ck.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
They occur across a variety of devices from Android 4.4 to 5.0.1
As you can see there is no element of my app in the stacktrace, and I am really at a loss and to what I can do (other than remove TagManager) to avoid or mitigate the error.
I have found one reference to the same error message associated with GooglePlus login so I am thinking it might be to do with the Google Play Services library.
Anyone else seen it?
Any ideas?
Have raised issue with Play-Games project:
https://code.google.com/p/play-games-platform/issues/detail?id=209
This is an internal bug due to a race condition within TagManager and should be fixed in Google Play Services 6.7 (February 17, 2015).
See https://productforums.google.com/forum/?utm_medium=email&utm_source=footer#!msg/tag-manager/NOlng117_2g/w46OkQS5Gm8J
and also https://developers.google.com/analytics/devguides/collection/android/changelog
In the mean time you can work around it by:
private static class MyHandler implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler defaultHandler;
MyHandler(Thread.UncaughtExceptionHandler defaultHandler) {
this.defaultHandler = defaultHandler;
}
#Override
public void uncaughtException(Thread thread, Throwable ex) {
String classpath = null;
if (ex != null && ex.getStackTrace().length > 0) {
classpath = ex.getStackTrace()[0].toString();
}
if (classpath != null &&
ex.getMessage().contains("Results have already been set") &&
classpath.contains("com.google.android.gms.tagmanager") ) {
// ignore
} else {
// run your default handler
defaultHandler.uncaughtException(thread, ex);
}
}
};
// Application#onCreate
public void onCreate() {
// for catching app global unhandled exceptions
final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new MyHandler(defaultHandler));
}
According to this link, Google has fixed this issue in newer versions:
https://developers.google.com/analytics/devguides/collection/android/changelog

GameHelper crashes on onConnectionFailed()

I've got the following crash in GameHelper.java:
[main] java.lang.NullPointerException at
com.google.android.gms.common.ConnectionResult.startResolutionForResult(Unknown
Source) at
com.google.example.games.basegameutils.GameHelper.resolveConnectionResult(GameHelper.java:752)
at
com.google.example.games.basegameutils.GameHelper.onConnectionFailed(GameHelper.java:729)
The only reason I think that could happen is if mActivity == null at GameHelper.java:752:
mConnectionResult.startResolutionForResult(mActivity, RC_RESOLVE);
mActivity gets null on onStop()
Is it possible that GameHelper.java has bug and can crash if onConnectionFailed() happens after onStop() is called?
Thanks.
EDITED:
It happened after update to the latest Play API (rev 15) together with the updated GameHelper.java.
EDIT:
This now has been fixed in latest GameHelper version:
https://github.com/playgameservices/android-samples/commit/e7b3758c136b5b434f1dfd9ca8c03f75aad70f09
OLD ANSWER:
For me it happens on the start of the app, when Google Play Services asks me to sign in and if I click cancel, this same error happens.
So when leaving from your own activity to sign in activity, it dispatches onStop event, and fails to connect because of the user initiated process, which is resolvable, thus the error happens.
So my quick hack was changing:
catch (SendIntentException e)
to simply
catch (Exception e)
So it would also catch Null pointer exception
Of course in this case the signup process might not proceed, so I initate relogin on another action and it seems to work for now.
More thorough hack could be trying to resolve the result on activity start, for that we define pending resolution variable:
// Are we expecting the result of a resolution flow?
boolean mExpectingResolution = false;
boolean mPendingResolution = false;
Then on the error line we check if activity is not null
if(mActivity != null)
mConnectionResult.startResolutionForResult(mActivity, RC_RESOLVE);
else
mPendingResolution = true;
And on start we check and try to resolve it:
if(mPendingResolution && mConnectionResult != null)
try {
mConnectionResult.startResolutionForResult(mActivity, RC_RESOLVE);
} catch (SendIntentException e) {
e.printStackTrace();
}
This should help until the official resolution from lib supporters :)
Today is 16th september 2014 and I still facing this problem.
I don't know why anyone else did not answer about to comment GameHelper line.
In onStop method there is a line to set mActivity variable as null.
I commented this line (like below) and my app is working properly.
/** Call this method from your Activity's onStop(). */
public void onStop() {
debugLog("onStop");
assertConfigured("onStop");
if (mGoogleApiClient.isConnected()) {
debugLog("Disconnecting client due to onStop");
mGoogleApiClient.disconnect();
} else {
debugLog("Client already disconnected when we got onStop.");
}
mConnecting = false;
mExpectingResolution = false;
// let go of the Activity reference
//mActivity = null; //COMMENT THIS LINE!!!!
//COMMENT ABOVE LINE
}
Is there any problem doing that:?

Android Activity Recognition - Reconnecting following Disconnection

With Google Play Services' Activity Recognition, they recommend that if the service disconnects (which it might) then we should remove the client:
http://developer.android.com/training/location/activity-recognition.html
In some cases, Location Services may disconnect from the activity
recognition client before you call disconnect(). To handle this
situation, implement onDisconnected(). In this method, set the request
flag to indicate that a request is not in progress, and delete the
client
That's fine, but it gives no instructions for how to reconnect [safely]. I'm running this from a foreground service which needs to maintain activity recognition at all times, so following disconnection:
#Override
public void onDisconnected() {
mRecognitionEnabled = false;
mRequestInProgress = false;
mRecognitionClient = null;
//Re-initialise Activity Recognition if service is still running
if (sServiceRunning) {
triggerActivityRecognition();
}
}
I reinstantiate the client and reconnect:
private void triggerActivityRecognition() {
if (!mRequestInProgress ) {
mRequestInProgress = true;
mRecognitionClient = new ActivityRecognitionClient(this, this, this);
mRecognitionClient.connect();
}
}
But according to some of the bug reports I'm getting, there's an exception occurring as follows:
java.lang.NullPointerException
at com.google.android.gms.internal.bh.a(Unknown Source)
at com.google.android.gms.internal.k.f(Unknown Source)
at com.google.android.gms.internal.k$e.onServiceConnected(Unknown Source)
at com.google.android.gms.internal.l.a(Unknown Source)
at com.google.android.gms.internal.k.connect(Unknown Source)
at com.google.android.gms.location.ActivityRecognitionClient.connect(Unknown Source)
at com.myapp.MyService.triggerActivityRecognition(MyService.java:316)
at com.myapp.MyService.onDisconnected(MyService.java:407)
at com.google.android.gms.internal.k.A(Unknown Source)
at com.google.android.gms.internal.k$e.onServiceDisconnected(Unknown Source)
at com.google.android.gms.internal.l$a$a.onServiceDisconnected(Unknown Source)
The disconnection occurs rarely but results in the same stack trace every time.
So if this is being caused by Google Play Services, is there anything I can do to prevent it or is it a bug I need to log with Android?
This is what works for me:
Don't attempt the reconnect with the onDisconnect(), instead do nothing in the onDisconnect()
public void onDisconnected() {
//do nothing here
}
Simply use the client as before, but check if is connected
if (!mRecognitionClient.isConnected()) {
// Client is disconnected, reconnect now
mRecognitionClient.connect();
}
The PlayServices seems to reconnect very nicely.

Categories

Resources