50

TestFlightHockeyAppなど、iOSにはiOSクラッシュレポートライブラリがたくさんあります。サービスに依存したくない場合でも、PLCrashReporterなどのライブラリを使用できます。これらのライブラリのバインドは、パブリックAPIが通常、いくつかの初期化メソッドを持つ2つのクラスで構成されているため、かなり簡単です。

ただし、TestFlightを使用しようとすると、後でアプリケーションでHockeyAppを使用しようとすると、アプリがランダムにクラッシュし始めました。結局のところ、これ度か報告され ている既知の問題ですが、Xamarinはそれについて警告していません。比較的あいまいであり、難しい方法であることがわかりました。

すべてのiOSクラッシュレポーターがMonoがnull参照例外をキャッチするのを防ぐことを学びました。

try {
    object o = null;
    o.GetHashCode ();
} catch {
    // Catch block isn't called with crash reporting enabled.
    // Instead, the app will crash.
}

なぜこれが起こるのですか?Xamarin開発者のRolfを引用すると、

null参照例外は、実際には最初はSIGSEGV信号です。通常、monoランタイムはこれを処理し、nullreference例外に変換して、実行を続行できるようにします。問題は、SIGSEGV信号がObjCアプリでは非常に悪いことであるため(マネージコードの外部で発生した場合)、クラッシュレポートソリューションはクラッシュとして報告します(そしてアプリを強制終了します)-これはMonoTouchがチャンスを得る前に発生しますSIGSEGVを処理するため、MonoTouchがこれについてできることは何もありません。

多くの人が、クラッシュの原因になることを知らずに、MonoTouchアプリでTestFlightを使用していると確信しています。
皮肉ではないですか?

クラッシュレポートライブラリがMonoTouchアプリをクラッシュさせないようにするにはどうすればよいですか?

4

2 に答える 2

57

これを入れてください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


それはどのように機能しますか?

私はロルフの提案に従いました:

考えられる解決策の1つは、monoがすべてのSIGSEGVシグナルを処理できるようにすることです(技術的に言えば、クラッシュレポートライブラリはSIGSEGVシグナルを処理しないか、monoのハンドラーにチェーンして単独で処理しないようにする必要があります)。monoがSIGSEGVシグナルがマネージコードからのものではないと判断した場合(つまり、非常に悪いことが起こった場合)、SIGABORTシグナルを生成します(クラッシュレポートライブラリはすでにクラッシュとして処理および処理する必要があります)。ご存知のとおり、これはクラッシュレポートライブラリで実行する必要があります。

そして、LandonFullerのObjectiveCの実装:

#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;
}

MonoTouch から呼び出す方法の参照ポイントとしてBansheeソースコードを使用しました。sigaction

それが役に立てば幸い!

于 2013-01-24T10:40:33.727 に答える
4

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 ();
}
于 2017-02-23T16:21:51.603 に答える