I am wondering if it is possible to change the crash message for android?("unfortunately app has stopped") I haven't found anything that says you can(which I don't think you can), I am just making sure by asking on here.
Thanks
You cannot change the system message as stated by #Nuno Gomes but you can suppress the original message and display a message on your own or start some activity.
You can define an exceptionhandler that catches all uncaught exceptions in app class and show a message box from there
public class MyApp extends Application implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler mPreviousUncaughtExceptionHandler;
#Override public void onCreate() {
super.onCreate();
mPreviousUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
#Override
public void uncaughtException(Thread thread, Throwable ex) {
try {
// Do your stuff with the exception
Log.e(Global.LOG_CONTEXT,"LogCat.uncaughtException " + ex, ex);
// show user defined messagebox
} catch (Exception e) {
/* Ignore */
} finally {
// uncomment this to let Android show the default error dialog
// mPreviousUncaughtExceptionHandler.uncaughtException(thread, ex);
}
}
}
the app must be declared in the manifest
<manifest ...>
...
<application
android:name=".MyApp" ...>
</application>
</manifest>
On my android-4.4 i use this code to write a chrash log file
That message is a system message, it's outside the app scope, so no you cannot change it
Related
I want to save the logs generated by my application locally on the android device and view them in an instance of a crash.
Using the "Take Bug Report" under the developer options gives the entire system logs which are irrelevant to me. I am looking only for those logs created by my application when it runs.
Is there any application that does this? Or are there any libraries I could include in my application code to satisfy my requirement?
You may just add firebase to your project, and everything will be done automatically.
Or if need it to be "locally", can use the Thread.UncaughtExceptionHandler to save crash log. Register it when your application onCreate.
private static UncaughtExceptionHandler mDefaultUncaughtExceptionHandler;
public static void registerUncaughtExceptionHandler() {
mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable ex) {
// Save Log
saveLog(ex);
// Throw system
mDefaultUncaughtExceptionHandler.uncaughtException(thread, ex);
}
});
}
private static void saveLog(Throwable exception) {
try {
String stackTrace = Log.getStackTraceString(exception);
// Save it to SharedPreferences or DB as you like
} catch (Exception e) {
}
}
Then can extract the last crash log, submit to your server or display in logcat when app starts.
It is much better to use Third Party libraries such as Firebase Crashlytics or Sentry Crash Report or AppMetrica for crash reports.
just add these libraries and make an account on one of these sites, then you can have a full report of crashes if happen.
but if you want to save the logs on the device, you can refer to this question :
Saving Logcat to a text file in Android Device
You can try this
fun writeLog(context: Context) {
try {
val path = File(context.filesDir, "log_files")
if (!path.exists()) {
path.mkdir()
}
val fileName = "your_filename.txt"
Runtime.getRuntime().exec("logcat -v time -f $fileName")
} catch (e: IOException) {
}
}
Or you can change logcat command based on your requirements: refer to this https://developer.android.com/studio/command-line/logcat
You can check it at data/data/{applicationId}/files/log_files/
Is it possible to auto-restart app after crash using Crashlytics? Unfortunately there is nothing about that topic in docs. I defined my own exception handler which is restarting app, but when i use it crash logs are not sent.
In your custom exception handler you can call Craslytics.logException(exception);.
public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread thread, Throwable exception) {
//you should also log the exception to logcat
Log.e(TAG, "UncaughtException", exception);
try {
//log to crashlytics
Crashlytics.logException(exception);
} catch (Exception e) {
Log.d(TAG, "uncaughtException: Crashlytics not initialized, cannot send logs.");
}
//exit with error code 1 (0 is normal program termination,
//which here is not the case)
System.exit(1);
}
}
One thing worth noting is that Crashlytics.logError(...) logs exceptions as "non-fatal". So I usually wrap them so I can differentiate non-fatal exceptions from actual fatal ones.
So:
Crashlytics.logException(exception);
becomes:
//wrap the original exception to your custom 'fatal' exception type.
FatalException fatalException = new FatalException(originalException);
//log with Crashlytics
Crashlytics.logException(fatalException);
Sample from an open source app here.
I've started to work in a company which has a system with a lot of legacy code. Sometimes we have problems like the application randomly exiting, uncaught exceptions and so on. The compilation works fine and it's hard to know where exactly the error is coming from (either from legacy code or new code), so I'd like to capture exceptions globally in the application and either send them to our servers (best option) or write them to a local file in the device.
Is it possible in Xamarin.Android to write such an interface or method that catches any exception that ever occur in the application and log it to a file? If so, how?
Yes, you can able to handle error globally, by adding some line code in ApplicationStart class, something like below:
[Application(Label = "#string/app_name", Icon = "#drawable/ic_launcher")]
public class ApplicationStart : Application
{
public ApplicationStart(IntPtr handle,
global::Android.Runtime.JniHandleOwnership transfer)
: base(handle, transfer)
{
}
public override void OnCreate()
{
AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironmentOnUnhandledExceptionRaiser;
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += CurrentDomainOnUnhandledException;
base.OnCreate();
}
private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
//you can able to write a code here to write Exeption e to file
Toast.MakeText(ApplicationContext, "Application crashed", ToastLength.Short).Show();
}
private void AndroidEnvironmentOnUnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
{
//if you have set e.Handled = true here then when application crashed at any point at that time device not stoped your app to go more
e.Handled = true;
//you can able to write a code here to write Exeption e to file
Toast.MakeText(ApplicationContext, "Application crashed", ToastLength.Short).Show();
}
}
I tried to start an activity with an implicit intent after an uncaught exception with the unCaughtExceptionHandler. The intent should start an Activity as a Dialog in the same app that has crashed. This corresponds to the example listed in this thread:
Need to handle uncaught exception and send log file
I call the original unCaughtExceptionHandler at the end of my own handler procedure, like this:
public class ThisApplication extends Application
{
Thread.UncaughtExceptionHandler originalUncaughtExceptionHandler;
#Override
public void onCreate ()
{
originalUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException (Thread thread, Throwable e)
{
handleUncaughtException (thread, e);
}
});
super.onCreate();
}
public void handleUncaughtException (Thread thread, Throwable e)
{
e.printStackTrace();
Intent intent = new Intent ();
intent.setAction ("de.mydomain.myapp.action.PROCESS_LOG");
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
if (intent.resolveActivity(getPackageManager()) == null) {
Log.d("ThisApplication","No receiver");
} else {
Log.d("ThisApplication", "Intent start");
startActivity(intent);
}
originalUncaughtExceptionHandler.uncaughtException(thread, e);
}
}
The result is, that after an Exception the standard Dialog is displayed that says something like "Unfortunately App xxx was closed". Behind that Dialog, in the background, I can see my Dialog that should be started with this intent "PROCESS_LOG". So obviously is was started, but the problem is, that after the standard Dialog has been closed, my custom dialog also closes. If I add
android:launchMode="singleInstance"
in the manifest of the dialog activity, the dialog is hidden, too, but it can be activated again when the app is selected from the recent apps menu. This seems to me as if the dialog is not started fully independently from the former app process/task.
Can somebody say what I did wrong?
This is the manifest part of the dialog activity:
<activity
android:name=".ProcessLogActivity"
android:windowSoftInputMode="stateHidden"
android:theme="#style/ProcessLogActivity"
android:process=":report_process"
>
<intent-filter>
<action android:name="de.mydomain.myapp.action.PROCESS_LOG" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The corresponding style:
<style name="ProcessLogActivity" parent="#style/Theme.AppCompat.Light.Dialog">
</style>
This is the Dialog Activity class:
public class ProcessLogActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature (Window.FEATURE_NO_TITLE);
setFinishOnTouchOutside (false);
Log.d("ThisApplication", "Intent received");
setContentView(R.layout.activity_process_log);
}
}
To post a full message (comment is too short), here the full class and configuration:
I tried to use ACRA with the built-in dialog-functionality, but I could not get it work. But the built-in funtionality to show a "Toast" works! So that's why I ask myself where the problem is showing the dialog. I use the following #ReportCrashed Annotation for testing:
#ReportsCrashes(
formUri = "http://yourserver.com/yourscript",
mode = ReportingInteractionMode.NOTIFICATION,
resDialogText = R.string.app_name,
resNotifTickerText = R.string.app_name,
resNotifTitle = R.string.app_name,
resNotifText = R.string.app_name
)
Inside my own Application-Class I use the following initialisation:
public class ThisApplication extends Application {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(this);
configurationBuilder.setBuildConfigClass(BuildConfig.class);
final ACRAConfiguration config;
try {
config = configurationBuilder.build();
ACRA.init(this, config);
} catch (ACRAConfigurationException e) {
e.printStackTrace();
}
}
}
My App uses two different Build flavors and the two build types "Debug" and "Release".
When I throw an unhandled exception the app closes and a dialog is only sometimes displayed for a very short moment (less than half a second) before the whole app is closed without any dialog.
Any ideas?...
EDIT: The above Annotation was the try with a Notification, that also does not work. The notification is also displayed only for a very short moment and then disappears immediately. The dialog Annotation was:
#ReportsCrashes(
formUri = "http://yourserver.com/yourscript",
mode = ReportingInteractionMode.DIALOG,
resDialogText = R.string.app_name
)
This has the effect described above.
The Problem was - at least in the case of the ACRA-Dialog - that it is not working as the app is debugged with the built-in functionality from android studio. So you have to start the app on the android test system (on the debugging device) without support from android studio IDE. When you do that and an exception is thrown, the ACRA-Dialog appears as it should.
I was reading the the Android Publishing docs and they said to remove all Log calls from my code. I have some calls to e.printStackTrace() in my code that can be printed as part of the normal running of my program (ie. if a file does not exist yet).
Should I also remove these calls?
You shouldn't be using e.printStackTrace() directly anyway — doing so will send the info to the Android log without displaying which application (log tag) it came from.
As others have mentioned, continue to catch the Exception in question, but use one of the android.util.Log methods to do the logging. You could log only the message, but not the stack trace, or use verbose logging for the stack trace:
try {
Object foo = null;
foo.toString();
} catch (NullPointerException ex) {
Log.w(LOG_TAG, "Foo didn't work: "+ ex.getMessage());
Log.d(LOG_TAG, Util.stackTraceWriter(ex));
}
You should strip DEBUG or VERBOSE log messages from your production builds. The easiest way is to use ProGuard to remove Log.[dv] calls from your code.
If you allow an Exception to propagate up to the OS then the OS will log it and also pop up a Force Close window, killing your application. If you catch it, then you can prevent your application from being force closed.
If you want your users to have the ability to send you errors that they are getting, then I would log the stack trace. They can then send you the log via an app like Log Collector.
If you want to avoid the possibility of exposing your stack trace information to your users, then catch the exception and don't log it.
I would use Log class for message out put. For logs that you think are important to stay in the app - use Log.i
for errors warning - Log.e Log.w
For you debug Log.d - and that you can turnoff on base on if your application is in debug mode.
http://developer.android.com/reference/android/util/DebugUtils.html
Well printStackTrace() will log it into the OS, causing your andorid (or computer) app to terminate (force close), instead, do something like this:
public void nullPointerExceptionCauser()
{
try
{
Object example = null;
example.toString();
}
catch (Exception e)
{
Logger.log(Level.SEVERE, "Caught Exception: {0}", e.getStackTrace());
}
}
in my modest opinion (I'm not an Android developer)
It should be nice. I don't know the logging options for Android but I'm sure you have some configurable thing to output (or not) your traces.
And if you don't do printStackTrace() Android will not be doing the dirty work of ignoring it.
:)
It's only a good-feeling (style) thing.
If you want to be secure i.e. not allow anyone snooping to read exception logs you can do something like
private void hideExceptionsInReleaseMode()
{
final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
if(!BuildConfig.DEBUG)
{
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException(Thread thread, Throwable ex)
{
defaultHandler.uncaughtException(thread, new RuntimeException("Something went wrong :p"));
}
});
}
}
In order to use printStackTrace in a safer way I would use StringWrite and PrintWriter:
...
catch (final Exception e)
{
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
Log.e("TAG", sw.toString());
}
Or alternatively:
catch (final Exception e)
{
Log.e(TAG, Log.getStackTraceString(e));
}
Use this to remove the logs from release apk
if (BuildConfig.DEBUG) Log.d(TAG, "your meseage");