4

我有一个使用HockeyApp进行崩溃报告的LaunchAgent 。现在我注意到HockeyApp没有报告未捕获的异常,就像它们在普通的 macOS 应用程序中一样。

例如:

- (void)upperCaseString:(NSString *)aString withReply:(void (^)(NSString *))reply {
    NSArray *array = [NSArray array];
    reply([array objectAtIndex:23]);
}

永远不会到达NSUncaughtExceptionHandler,但控制台记录:

<NSXPCConnection: 0x7fe97dc0f110> connection from pid 44573: Warning: Exception caught during invocation of received message, dropping incoming message and invalidating the connection.

问题是如何使用HockeyApp报告未处理的异常。

4

1 回答 1

2

问题:

XPC 似乎有自己的@try @catch 块,它在方法中捕获未处理的异常,记录异常,然后记录调用-[NSXPCConnection interruptionHandler]

此问题在rdar://48543049下报告给 Apple 。

注意:这些不是复制和过去的解决方案,请仔细评估您的崩溃报告框架。我链接到PLCrashReporter的实现细节。

解决方案 A:

@try @catch 块

- (void)upperCaseString:(NSString *)aString withReply:(void (^)(NSString *))reply {
    @try {
        NSArray *array = [NSArray array];
        reply([array objectAtIndex:23]);
    } @catch (NSException *exception) {
        NSUncaughtExceptionHandler *handler = NSGetUncaughtExceptionHandler();
        if (handler) {
            handler(exception);
        }
    }
}

讨论

HockeyApp使用PLCrashReporter进行崩溃报告。PLCrashReporter注册一个NSUncaughtExceptionHandler代码)。所以上面的代码会将异常转发给PLCrashReporter异常处理程序并终止(代码)XPC。

Mattie建议再次@throw异常,以触发内部 XPC @catch块以及可能的内部清理和日志记录。这是要考虑的事情。特别是如果您在连接的 LaunchAgent/Server 端有自interruptionHandler定义NSXPCConnection

现在我支持不再扔它,因为我的XPC 是完全无状态的,只要崩溃就可以了。

解决方案 A的缺点是通过 XPC 公开的每个方法都需要这个@try @catch 块

解决方案 B:

使用NSProxy捕获所有未处理异常的a NSXPCConnection exportObject

@interface LOUncaughtExceptionHandlerProxy : NSProxy {
    NSObject *_object;
}
@end

@implementation LOUncaughtExceptionHandlerProxy

- (instancetype)initWithObject:(NSObject *)object
{
    NSParameterAssert(object);
    _object = object;
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    return [_object methodSignatureForSelector:selector];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    @try {
        [invocation invokeWithTarget:_object];
    } @catch (NSException *exception) {
        NSUncaughtExceptionHandler *handler = NSGetUncaughtExceptionHandler();
        if (handler) {
            handler(exception);
        }
    }
}

@end

NSXPCListener侦听器中设置:

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
    XPC *exportedObject = [XPC new];
    LOUncaughtExceptionHandlerProxy *proxy = [[LOUncaughtExceptionHandlerProxy alloc] initWithObject:exportedObject];
    newConnection.exportedObject = proxy;
    newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
    [newConnection resume];
    return YES;
}

解决方案 A 的所有细节都适用于解决方案B。

解决方案 Z:

在 macOS 上可以使用ExceptionHandling.framework ,它的问题在BITCrashExceptionApplication.h中有很好的概述。

讨论

如果框架没有移植到 iOS,这绝不是一个好兆头。另请注意Matties评论:

我与 Apple 的交互直接表明 ExceptionHandling.framework 不再受支持。而且,根据我在 Crashlytics 上工作的经验,它存在一些基本的互操作性问题,超出了引用的标题中指出的问题。

于 2019-03-03T09:22:49.007 回答