如何防止iOS崩溃报告器崩溃MonoTouch应用程序
本文关键字:崩溃 MonoTouch 应用程序 报告 iOS 何防止 | 更新日期: 2023-09-27 17:55:31
iOS中有很多iOS崩溃报告库,包括TestFlight和HockeyApp。如果你不想依赖服务,你仍然可以使用PLCrashReporter这样的库。绑定这些库相当简单,因为它们的公共 API 通常由几个具有多个初始化方法的类组成。
但是,当尝试在我们的应用程序中使用TestFlight以及后来的HockeyApp时,我们的应用程序开始随机崩溃。事实证明,这是一个多次报告的已知问题,但 Xamarin 没有警告它,它相对模糊,我们很难找到它。
我们了解到,所有 iOS 崩溃报告器都会阻止 Mono 捕获空引用异常:
try {
object o = null;
o.GetHashCode ();
} catch {
// Catch block isn't called with crash reporting enabled.
// Instead, the app will crash.
}
为什么会这样?引用Xamarin开发人员Rolf的话,
空引用异常实际上首先是SIGSEGV信号。通常 单声道运行时处理此问题并将其转换为空引用异常, 允许继续执行。问题是SIGSEGV信号是一个 在 ObjC 应用程序中非常糟糕的事情(当它发生在托管代码之外时),所以 任何崩溃报告解决方案都会将其报告为崩溃(并杀死应用程序) - 这发生在MonoTouch有机会处理SIGSEGV之前,所以有 MonoTouch对此无能为力。
我敢肯定,许多人在MonoTouch应用程序中使用TestFlight,却不知道它会导致崩溃。
是不是很讽刺?
如何使崩溃报告库不会使MonoTouch应用程序崩溃?
把它放在AppDelegate.cs
:
[DllImport ("libc")]
private static extern int sigaction (Signal sig, IntPtr act, IntPtr oact);
enum Signal {
SIGBUS = 10,
SIGSEGV = 11
}
static void EnableCrashReporting ()
{
IntPtr sigbus = Marshal.AllocHGlobal (512);
IntPtr sigsegv = Marshal.AllocHGlobal (512);
// Store Mono SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, IntPtr.Zero, sigbus);
sigaction (Signal.SIGSEGV, IntPtr.Zero, sigsegv);
// Enable crash reporting libraries
EnableCrashReportingUnsafe ();
// Restore Mono SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, sigbus, IntPtr.Zero);
sigaction (Signal.SIGSEGV, sigsegv, IntPtr.Zero);
Marshal.FreeHGlobal (sigbus);
Marshal.FreeHGlobal (sigsegv);
}
static void EnableCrashReportingUnsafe ()
{
// Run your crash reporting library initialization code here--
// this example uses HockeyApp but it should work well
// with TestFlight or other libraries.
// Verify in documentation that your library of choice
// installs its sigaction hooks before leaving this method.
var manager = BITHockeyManager.SharedHockeyManager;
manager.Configure (HockeyAppId, null);
manager.StartManager ();
}
在方法的开头调用EnableCrashReporting ()
FinishedLaunching
。
如果需要,请将此调用包装在#if !DEBUG
指令中。
它是如何工作的?
我听从了罗尔夫的建议:
一种可能的解决方案是允许单声道处理所有SIGSEGV信号 (从技术上讲,崩溃报告库不应该处理 SIGSEGV 信号,或者它应该链接到单声道的处理程序而不做 任何处理本身)。如果单声道确定SIGSEGV信号 不是来自托管代码(即发生了非常糟糕的事情),它会 发出 SIGABORT 信号(崩溃报告库应该已经 处理并被视为崩溃)。如您所知,这是一件事情 这必须在崩溃报告库中完成。
以及Landon Fuller的目标C实现:
#import <signal.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/* Save Mono's signal handler actions */
struct sigaction sigbus_action, sigsegv_action;
sigaction(SIGBUS, NULL, &sigbus_action);
sigaction(SIGSEGV, NULL, &sigsegv_action);
// Enable the crash reporter here. Ie, [[PLCrashReporter sharedReporter] enableCrashReporterAndReturnError:],
// or whatever is the correct initialization mechanism for the crash reporting service you're using
/* Restore Mono's signal handlers */
sigaction(SIGBUS, &sigbus_action, NULL);
sigaction(SIGSEGV, &sigsegv_action, NULL);
return YES;
}
我使用Banshee源代码作为如何从MonoTouch调用sigaction
的参考点。
希望对您有所帮助!
从 Xamarin.iOS 10.4 开始,现在有一种受支持的方法来执行此操作:
static void EnableCrashReporting ()
{
try {
} finally {
Mono.Runtime.RemoveSignalHandlers ();
try {
EnableCrashReportingUnsafe ();
} finally {
Mono.Runtime.InstallSignalHandlers ();
}
}
}
static void EnableCrashReportingUnsafe ()
{
// Run your crash reporting library initialization code here--
// this example uses HockeyApp but it should work well
// with TestFlight or other libraries.
// Verify in documentation that your library of choice
// installs its sigaction hooks before leaving this method.
// Have in mind that at this point Mono will not handle
// any NullReferenceExceptions, if there are any
// NullReferenceExceptions on any thread (not just the current one),
// then the app will crash.
var manager = BITHockeyManager.SharedHockeyManager;
manager.Configure (HockeyAppId, null);
manager.StartManager ();
}