如何防止iOS崩溃记者崩溃MonoTouch应用程序?

Dan*_*mov 50 c# crash-reports xamarin.ios ios testflight

iOS中有很多iOS崩溃报告库,包括TestFlightHockeyApp.如果您不想依赖服务,您仍然可以使用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.
}
Run Code Online (Sandbox Code Playgroud)

为什么会这样?引用Xamarin开发人员Rolf,

空引用异常实际上是SIGSEGV信号.通常单声道运行时处理它并将其转换为空引用异常,允许继续执行.问题是在ObjC应用程序中SIGSEGV信号是一件非常糟糕的事情(当它发生在托管代码之外时),因此任何崩溃报告解决方案都会将其报告为崩溃(并杀死应用程序) - 这在MonoTouch获得机会之前发生处理SIGSEGV,因此MonoTouch无法做到这一点.

我相信很多人在MonoTouch应用程序中使用TestFlight而不知道它会导致崩溃.
这不具讽刺意味吗?

如何使崩溃报告库不会崩溃MonoTouch应用程序?

Dan*_*mov 58

把它放进去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 ();
}
Run Code Online (Sandbox Code Playgroud)

EnableCrashReporting ()FinishedLaunching方法的开头调用.如果需要,
将此调用包含在#if !DEBUG指令中.


它是如何工作的?

我遵循了罗尔夫的建议:

一种可能的解决方案是允许mono处理所有SIGSEGV信号(从技术上讲,崩溃报告lib应该不处理SIGSEGV信号,或者它应链接到mono的处理程序而不是自己进行任何处理).如果mono确定SIGSEGV信号不是来自托管代码(即发生了非常糟糕的事情),它将引发一个SIGABORT信号(崩溃报告库应该已经处理并视为崩溃).您可以理解,这是必须在崩溃报告库中完成的事情.

兰登富勒的目的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;
}
Run Code Online (Sandbox Code Playgroud)

我使用Banshee源代码作为如何sigaction从MonoTouch 调用的参考点.

希望能帮助到你!