Unhandled exception handling in iOS and Android with Xamarin.

Unhandled exceptions are hard to catch and log, and you must do it to be able to handle the errors in your app. One approach is to use Xamarin.Insights but you always want to be able to just log into a file and then access that file locally.

The code below is what we use right now and it has helped us a lot, especially the unobserved task exceptions that are just silent, i.e. they do not crash the app, but you still want to handle the exceptions.

// In MainActivity
protected override void OnCreate(Bundle bundle)
{
	base.OnCreate(bundle);  
	
	AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
	TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException;  
	
	Xamarin.Forms.Forms.Init(this, bundle);  
	DisplayCrashReport();  
	
	var app = new App();  
	LoadApplication(app);
}  

‪#‎region‬ Error handling
private static void TaskSchedulerOnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs unobservedTaskExceptionEventArgs)
{
	var newExc = new Exception("TaskSchedulerOnUnobservedTaskException", unobservedTaskExceptionEventArgs.Exception);
	LogUnhandledException(newExc);
}  

private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
	var newExc = new Exception("CurrentDomainOnUnhandledException", unhandledExceptionEventArgs.ExceptionObject as Exception);
	LogUnhandledException(newExc);
}  

internal static void LogUnhandledException(Exception exception)
{
	try
	{
		const string errorFileName = "Fatal.log";
		var libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // iOS: Environment.SpecialFolder.Resources
		var errorFilePath = Path.Combine(libraryPath, errorFileName);  
		var errorMessage = String.Format("Time: {0}\r\nError: Unhandled Exception\r\n{1}",
		DateTime.Now, exception.ToString());
		File.WriteAllText(errorFilePath, errorMessage);  
		
		// Log to Android Device Logging.
		Android.Util.Log.Error("Crash Report", errorMessage);
	}
	catch
	{
		// just suppress any error logging exceptions
	}
}  

/// <summary>
// If there is an unhandled exception, the exception information is diplayed 
// on screen the next time the app is started (only in debug configuration)
/// </summary>
[Conditional("DEBUG")]
private void DisplayCrashReport()
{
	const string errorFilename = "Fatal.log";
	var libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
	var errorFilePath = Path.Combine(libraryPath, errorFilename);

	if (!File.Exists(errorFilePath))
	{
		return; 
	}
	
	var errorText = File.ReadAllText(errorFilePath);
	new AlertDialog.Builder(this)
		.SetPositiveButton("Clear", (sender, args) =>
		{
			File.Delete(errorFilePath);
		})
		.SetNegativeButton("Close", (sender, args) =>
		{
			// User pressed Close.
		})
		.SetMessage(errorText)
		.SetTitle("Crash Report")
		.Show();
} 

‪#‎endregion‬  

//iOS: Different than Android. Must be in FinishedLaunching, not in Main.
// In AppDelegate
public override bool FinishedLaunching(UIApplication uiApplication, NSDictionary options)
{
	AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
	TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException;  
	...
}  

/// <summary>
// If there is an unhandled exception, the exception information is diplayed 
// on screen the next time the app is started (only in debug configuration)
/// </summary>
[Conditional("DEBUG")]
private static void DisplayCrashReport()
{
	const string errorFilename = "Fatal.log";
	var libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Resources);
	var errorFilePath = Path.Combine(libraryPath, errorFilename);

	if (!File.Exists(errorFilePath))
	{
		return;
	}
	
	var errorText = File.ReadAllText(errorFilePath);
	var alertView = new UIAlertView("Crash Report", errorText, null, "Close", "Clear") { UserInteractionEnabled = true };
	alertView.Clicked += (sender, args) =>
	{
		if (args.ButtonIndex != 0)
		{
			File.Delete(errorFilePath);
		}
	};
	alertView.Show();
}

4 thoughts on “Unhandled exception handling in iOS and Android with Xamarin.

Leave a reply to milenppavlov Cancel reply