ios程序发布后,收集Crash崩溃信息

iOS平台一套完善的Crash Report解决方案 最开始想iOS和Android都做了,后面尝试了下android上面的崩溃收集,困难程度超出我的想象,也可以说几乎不可能实现像iOS下面一样实用且方便的崩溃收集系统(1.有堆栈等信息,不会产生卡死等副作用。  2.专指jni崩溃,java的崩溃很容易处理)。  这个有一点要反思一下,在困难的地方浪费时间不如把简单的东西做好,那么多赚大钱的游戏也是各种不完美,但是玩家不会在意程序是否牛x,技术是否高 阅读详情

有人想在iOS程序发布之后,收集程序崩溃的信息以便改进程序,今天我给大家介绍个比较实用的方法。

崩溃信息的收集完成后会在沙盒生成txt报告,但是这个crash收集也不能收集所有的程序崩溃信息,例如栈溢出或者对象指针损坏等等,这些崩溃会导致Crash收集的代码不会执行。

废话不多说,先直接讲添加方法,源代码一起奉献;

在appdelegate里的 application:didFinishLoading方法中添加

[[CrashManager sharedInstance] manageCrashes];

当然,你也能设置代理让你的delegate接受崩溃信息,

[[CrashManager sharedInstance] setCrashDelegate:self selector:@selector(notifyException:stackTrace:)];

下面是源代码:CrashManager.h

#import <Foundation/Foundation.h>
#import "SynthesizeSingleton.h"


/**
 * Manages any crashes that occur while the app is running.
 * If a crash occurs while CrashManager is managing crashes, it will write
 * a crash report to a file, allow a user-defined delegate to do some more processing,
 * then let the application finish crashing.
 */
@interface CrashManager : NSObject
{
    /** The full path to the error report that this manager will write to. */
    NSString* errorReportPath;

    /** The delegate to inform when a crash occurs (can be nil). */
    id delegate;

    /** The selector to call on the delegate. */
    SEL callbackSelector;
}

SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(CrashManager);

/**
 * Start managing crashes.
 */
- (void) manageCrashes;

/**
 * Stop managing crashes.
 */
- (void) stopManagingCrashes;

/** The error report's path.
 * Note: If you set this to a value that doesn't start with "/", it will
 *       be expanded to a full path relative to the Documents directory.
 */
@property(readwrite,nonatomic,retain) NSString* errorReportPath;

/** The error report.  If there is no report, this will be nil. */
@property(readonly,nonatomic) NSString* errorReport;

/** If true, there is an error report present. */
@property(readonly,nonatomic) bool errorReportPresent;

/**
 * Delete the error report (if any).
 */
- (void) deleteErrorReport;

/**
 * Set the delegate and selector to call when a crash occurs.
 * The selector must take an NSException* and NSArray* parameter like so: <br>
 * - (void) notifyException:(NSException*) exception stackTrace:(NSArray*) stackTrace <br>
 * stackTrace will be an array of StackTraceEntry.
 *
 * @param delegate The delegate to call.
 * @param selector The selector to invoke.
 */
- (void) setCrashDelegate:(id) delegate selector:(SEL) selector;


@end


然后是CrashManager.m

#import "CrashManager.h"
#include <unistd.h>
#import "StackTracer.h"
#import <UIKit/UIKit.h>
#import "MacAdress.h"
#import "NSString+SHA.h"

/** Maximum number of stack frames to capture. */
#define kStackFramesToCapture 40

/** The default file to store error reports to. */
#define kDefaultReportFilename @"error_report.txt"

/** The exception name to use for raised signals. */
#define kSignalRaisedExceptionName @"SignalRaisedException"


@interface CrashManager (Private)

/**
 * Called automatically to handle an exception.
 *
 * @param exception The exception that was raised.
 * @param stackTrace The stack trace.
 */
- (void) handleException:(NSException*) exception stackTrace:(NSArray*) stackTrace;

/**
 * Called automatically to handle a raised signal.
 *
 * @param signal The signal that was raised.
 * @param stackTrace The stack trace.
 */
- (void) handleSignal:(int) signal stackTrace:(NSArray*) stackTrace;

/**
 * Get the name of a signal.
 *
 * @param signal The signal to get a name for.
 * @return The name of the signal.
 */
- (NSString*) signalName:(int) signal;

/**
 * Store an exception and stack trace to disk.
 * It will be stored to the file specified in reportFilename.
 *
 * @param exception The exception to store.
 * @param stackTrace The stack trace to store.
 */
- (void) storeErrorReport:(NSException*) exception stackTrace:(NSArray*) stackTrace;

@end


/**
 * Install the exception and signal handlers.
 */
static void installHandlers();

/**
 * Remove the exception and signal handlers.
 */
static void removeHandlers();

/**
 * Exception handler.
 * Sets up an appropriate environment and then calls CrashManager to
 * deal with the exception.
 *
 * @param exception The exception that was raised.
 */
static void handleException(NSException* exception);

/**
 * Signal handler.
 * Sets up an appropriate environment and then calls CrashManager to
 * deal with the signal.
 *
 * @param exception The exception that was raised.
 */
static void handleSignal(int signal);



static void installHandlers()
{
    NSSetUncaughtExceptionHandler(&handleException);
    signal(SIGILL, handleSignal);
    signal(SIGABRT, handleSignal);
    signal(SIGFPE, handleSignal);
    signal(SIGBUS, handleSignal);
    signal(SIGSEGV, handleSignal);
    signal(SIGSYS, handleSignal);
    signal(SIGPIPE, handleSignal);
}

static void removeHandlers()
{
    NSSetUncaughtExceptionHandler(NULL);
    signal(SIGILL, SIG_DFL);
    signal(SIGABRT, SIG_DFL);
    signal(SIGFPE, SIG_DFL);
    signal(SIGBUS, SIG_DFL);
    signal(SIGSEGV, SIG_DFL);
    signal(SIGSYS, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
}

static void handleException(NSException* exception)
{
    removeHandlers();
    
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    
    NSArray* stackTrace = [[StackTracer sharedInstance] generateTraceWithMaxEntries:kStackFramesToCapture];
    [[CrashManager sharedInstance] handleException:exception stackTrace:stackTrace];
    
    [pool drain];
    [exception raise];
}

static void handleSignal(int signal)
{
    removeHandlers();
    
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    
    NSArray* stackTrace = [[StackTracer sharedInstance] generateTraceWithMaxEntries:kStackFramesToCapture];
    [[CrashManager sharedInstance] handleSignal:signal stackTrace:stackTrace];
    
    [pool drain];
    // Note: A signal doesn't need to be re-raised like an exception does.
}


@implementation CrashManager


SYNTHESIZE_SINGLETON_FOR_CLASS(CrashManager);

- (id) init
{
    if(nil != (self = [super init]))
    {
        self.errorReportPath = kDefaultReportFilename;
    }
    return self;
}

- (void) dealloc
{
    [errorReportPath release];
    [super dealloc];
}

- (void) setCrashDelegate:(id) delegateIn selector:(SEL) selectorIn
{
    delegate = delegateIn;
    callbackSelector = selectorIn;
}

- (void) manageCrashes
{
    installHandlers();
}

- (void) stopManagingCrashes
{
    removeHandlers();
}

- (NSString*) errorReportPath
{
    return errorReportPath;
}

- (void) setErrorReportPath:(NSString*) filename
{
    if([filename characterAtIndex:0] != '/')
    {
        NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString* dir = [paths objectAtIndex:0];
        errorReportPath = [[dir stringByAppendingPathComponent:filename] retain];
    }
    else
    {
        errorReportPath = [filename retain];
    }
    
}

- (bool) errorReportPresent
{
    return [[NSFileManager defaultManager] fileExistsAtPath:errorReportPath];
}

- (NSString*) errorReport
{
    NSError *error = nil;
    return [NSString stringWithContentsOfFile:errorReportPath encoding:NSUTF8StringEncoding error:&error];
}

- (void) deleteErrorReport
{
    NSError *error = nil;
    [[NSFileManager defaultManager] removeItemAtPath:errorReportPath error:&error];
    if(nil != error)
    {
        NSLog(@"Warning: %s: Could not delete %@: %@", __PRETTY_FUNCTION__, errorReportPath, error);
    }
}

- (void) handleException:(NSException*) exception stackTrace:(NSArray*) stackTrace
{
    [self storeErrorReport:exception stackTrace:stackTrace];
    [delegate performSelector:callbackSelector withObject:exception withObject:stackTrace];
}

- (void) handleSignal:(int) signal stackTrace:(NSArray*) stackTrace
{
    NSException* exception = [NSException exceptionWithName:kSignalRaisedExceptionName
                                                     reason:[self signalName:signal]
                                                   userInfo:nil];
    [self storeErrorReport:exception stackTrace:stackTrace];
    [delegate performSelector:callbackSelector withObject:exception withObject:stackTrace];
}

- (void) storeErrorReport:(NSException*) exception stackTrace:(NSArray*) stackTrace
{
    NSString* data = [NSString stringWithFormat:@"=============异常崩溃报告=============\n%@\nApp: %@\nVersion: %@\nID: %@\nReason: %@: %@\n%@\n\n\n",
                      [NSDate date],
                      [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"],
                      [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"],
                      [[MacAdress macAdress] sha1],
            [exception name],
                      [exception reason],
                      [[StackTracer sharedInstance] printableTrace:stackTrace]];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:errorReportPath]) {
        NSString *tmp = [NSString stringWithContentsOfFile:errorReportPath encoding:NSUTF8StringEncoding error:nil];
        data = [tmp stringByAppendingFormat:@"%@",data];
    }
    [data writeToFile:errorReportPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}

- (NSString*) signalName:(int) signal
{
    switch(signal)
    {
        case SIGABRT:
            return @"Abort";
        case SIGILL:
            return @"Illegal Instruction";
        case SIGSEGV:
            return @"Segmentation Fault";
        case SIGFPE:
            return @"Floating Point Error";
        case SIGBUS:
            return @"Bus Error";
        case SIGPIPE:
            return @"Broken Pipe";
        default:
            return [NSString stringWithFormat:@"Unknown Signal (%d)", signal];
    }
}

@end



具体错误路径的StackTracer.h

#import <Foundation/Foundation.h>
#import "SynthesizeSingleton.h"


/**
 * Generates and formats stack traces.
 */
@interface StackTracer : NSObject
{
    /** The current application process's name. */
    NSString* processName;
}

/** Make this class into a singleton. */
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(StackTracer);

/**
 * Generate a stack trace with the default maximum entries (currently 40).
 *
 * @return an array of StackTraceEntry.
 */
- (NSArray*) generateTrace;

/**
 * Generate a stack trace with the specified maximum entries.
 *
 * @param maxEntries The maximum number of lines to trace.
 * @return an array of StackTraceEntry.
 */
- (NSArray*) generateTraceWithMaxEntries:(unsigned int) maxEntries;

/**
 * Create an "intelligent" trace from the specified trace.
 * This is designed primarily for stripping out useless trace lines from
 * an exception or signal trace.
 *
 * @param stackTrace The trace to convert (NSArray containing StackTraceEntry).
 * @return An intelligent trace with the useless info stripped.
 */
- (NSArray*) intelligentTrace:(NSArray*) stackTrace;

/**
 * Turn the specified stack trace into a printabe string.
 *
 * @param stackTrace The stack trace to convert (NSArray containing StackTraceEntry).
 * @retun A string representation of the stack trace.
 */
- (NSString*) printableTrace:(NSArray*) stackTrace;

/**
 * Turn the specified stack trace into a condensed printable string.
 * The condensed entries are space separated, and only contain the object class
 * (if any) and the selector call.
 *
 * @param stackTrace The stack trace to convert (NSArray containing StackTraceEntry).
 * @return A condensed string representation of the stack trace.
 */
- (NSString*) condensedPrintableTrace:(NSArray*) stackTrace;

@end





/**
 * A single stack trace entry, recording all information about a stack trace line.
 */
@interface StackTraceEntry: NSObject
{
    unsigned int traceEntryNumber;
    NSString* library;
    unsigned int address;
    NSString* objectClass;
    bool isClassLevelSelector;
    NSString* selectorName;
    int offset;
    NSString* rawEntry;
}
/** This entry's position in the original stack trace. */
@property(readonly,nonatomic) unsigned int traceEntryNumber;

/** Which library, framework, or process the entry is from. */
@property(readonly,nonatomic) NSString* library;

/** The address in memory. */
@property(readonly,nonatomic) unsigned int address;

/** The class of object that made the call. */
@property(readonly,nonatomic) NSString* objectClass;

/** If true, this is a class level selector being called. */
@property(readonly,nonatomic) bool isClassLevelSelector;

/** The selector (or function if it's C) being called. */
@property(readonly,nonatomic) NSString* selectorName;

/** The offset within the function or method. */
@property(readonly,nonatomic) int offset;

/** Create a new stack trace entry from the specified trace line.
 * This line is expected to conform to what backtrace_symbols() returns.
 */
+ (id) entryWithTraceLine:(NSString*) traceLine;

/** Initialize a stack trace entry from the specified trace line.
 * This line is expected to conform to what backtrace_symbols() returns.
 */
- (id) initWithTraceLine:(NSString*) traceLine;

@end




StackTracer.m

#import "StackTracer.h"
#include <execinfo.h>
#include <unistd.h>


/** The maximum number of stack trace lines to use if none is specified. */
#define kDefaultMaxEntries 40

@implementation StackTracer

SYNTHESIZE_SINGLETON_FOR_CLASS(StackTracer);

- (id) init
{
    if(nil != (self = [super init]))
    {
        processName = [[[NSProcessInfo processInfo] processName] retain];
    }
    return self;
}

- (void) dealloc
{
    [processName release];
    [super dealloc];
}

- (NSArray*) generateTrace
{
    return [self generateTraceWithMaxEntries:kDefaultMaxEntries];
}

- (NSArray*) generateTraceWithMaxEntries:(unsigned int) maxEntries
{
    // Get the stack trace from the OS.
    void* callstack[maxEntries];
    int numFrames = backtrace(callstack, maxEntries);
    char** symbols = backtrace_symbols(callstack, numFrames);
    
    // Create StackTraceEntries.
    NSMutableArray* stackTrace = [NSMutableArray arrayWithCapacity:numFrames];
    for(int i = 0; i < numFrames; i++)
    {
        [stackTrace addObject:[StackTraceEntry entryWithTraceLine:[NSString stringWithUTF8String:symbols[i]]]];
    }
    
    // symbols was malloc'd by backtrace_symbols() and so we must free it.
    free(symbols);
    
    return stackTrace;
}

- (NSArray*) intelligentTrace:(NSArray*) stackTrace
{    
    int startOffset = 0;

    // Anything with this process name at the start is going to be part of the
    // exception/signal catching.  We skip that.
    for(int i = startOffset; i < [stackTrace count]; i++)
    {
        StackTraceEntry* entry = [stackTrace objectAtIndex:i];
        if(![processName isEqualToString:entry.library])
        {
            startOffset = i;
            break;
        }
    }
    
    // Beneath that is a bunch of runtime error handling stuff.  We skip this as well.
    for(int i = startOffset; i < [stackTrace count]; i++)
    {
        StackTraceEntry* entry = [stackTrace objectAtIndex:i];
        
        if(0xffffffff == entry.address)
        {
            // Signal handler stack trace is useless up to "0xffffffff 0x0 + 4294967295"
            startOffset = i + 1;
            break;
        }
        if([@"__objc_personality_v0" isEqualToString:entry.selectorName])
        {
            // Exception handler stack trace is useless up to "__objc_personality_v0 + 0"
            startOffset = i + 1;
            break;
        }
    }

    // Look for the last point where it was still in our code.
    // If we don't find anything, we'll just use everything past the exception/signal stuff.
    for(int i = startOffset; i < [stackTrace count]; i++)
    {
        StackTraceEntry* entry = [stackTrace objectAtIndex:i];
        // If we reach the "main" function, we've exhausted the stack trace.
        // Since we couldn't find anything, start from the previously calculated starting point.
        if([@"main" isEqualToString:entry.selectorName])
        {
            break;
        }
        
        // If we find something from our own code, use one level higher as the starting point.
        if([processName isEqualToString:entry.library])
        {
            startOffset = i - 1;
            break;
        }
    }
    
    NSMutableArray* result = [NSMutableArray arrayWithCapacity:[stackTrace count] - startOffset];
    for(int i = startOffset; i < [stackTrace count]; i++)
    {
        StackTraceEntry* entry = [stackTrace objectAtIndex:i];
        // We don't care about intermediate forwarding functions.
        if(![@"___forwarding___" isEqualToString:entry.selectorName] &&
           ![@"_CF_forwarding_prep_0" isEqualToString:entry.selectorName])
        {
            [result addObject:[stackTrace objectAtIndex:i]];
        }
    }
    
    return result;
}


- (NSString*) printableTrace:(NSArray*) stackTrace
{
    NSMutableString* string = [NSMutableString stringWithCapacity:[stackTrace count] * 100];
    for(StackTraceEntry* entry in stackTrace)
    {
        [string appendString:[entry description]];
        [string appendString:@"\n"];
    }
    return string;
}

- (NSString*) condensedPrintableTrace:(NSArray*) stackTrace
{
    NSMutableString* string = [NSMutableString stringWithCapacity:[stackTrace count] * 50];
    bool firstRound = YES;
    for(StackTraceEntry* entry in stackTrace)
    {
        if(firstRound)
        {
            firstRound = NO;
        }
        else
        {
            // Space separated.
            [string appendString:@" "];
        }

        if(nil != entry.objectClass)
        {
            // -[MyClass myMethod:anExtraParameter] or
            // +[MyClass myClassMethod:anExtraParameter]
            NSString* levelPrefix = entry.isClassLevelSelector ? @"+" : @"-";
            [string appendFormat:@"%@[%@ %@]", levelPrefix, entry.objectClass, entry.selectorName];
        }
        else
        {
            // my_c_function
            [string appendFormat:@"%@", entry.selectorName];
        }
    }
    return string;
}

@end



@implementation StackTraceEntry

static NSMutableCharacterSet* objcSymbolSet;

+ (id) entryWithTraceLine:(NSString*) traceLine
{
    return [[[self alloc] initWithTraceLine:traceLine] autorelease];
}

- (id) initWithTraceLine:(NSString*) traceLine
{
    if(nil == objcSymbolSet)
    {
        objcSymbolSet = [[NSMutableCharacterSet alloc] init];
        [objcSymbolSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]];
        [objcSymbolSet formUnionWithCharacterSet:[NSCharacterSet characterSetWithRange:NSMakeRange('!', '~' - '!')]];
    }
    
    if(nil != (self = [super init]))
    {
        rawEntry = [traceLine retain];
        
        NSScanner* scanner = [NSScanner scannerWithString:rawEntry];
        
        if(![scanner scanInt:(int*)&traceEntryNumber]) goto done;
        
        if(![scanner scanUpToString:@" 0x" intoString:&library]) goto done;
        
        if(![scanner scanHexInt:&address]) goto done;
        
        if(![scanner scanCharactersFromSet:objcSymbolSet intoString:&selectorName]) goto done;
        if([selectorName length] > 2 && [selectorName characterAtIndex:1] == '[')
        {
            isClassLevelSelector = [selectorName characterAtIndex:0] == '+';
            objectClass = [[selectorName substringFromIndex:2] retain];
            if(![scanner scanUpToString:@"]" intoString:&selectorName]) goto done;
            if(![scanner scanString:@"]" intoString:nil]) goto done;
        }
        
        if(![scanner scanString:@"+" intoString:nil]) goto done;
        
        if(![scanner scanInt:&offset]) goto done;
        
    done:
        if(nil == library)
        {
            library = @"???";
        }
        if(nil == selectorName)
        {
            selectorName = @"???";
        }
        [library retain];
        [objectClass retain];
        [selectorName retain];
    }
    return self;
}

- (void) dealloc
{
    [rawEntry release];
    [library release];
    [objectClass release];
    [selectorName release];
    [super dealloc];
}

@synthesize traceEntryNumber;
@synthesize library;
@synthesize address;
@synthesize objectClass;
@synthesize isClassLevelSelector;
@synthesize selectorName;
@synthesize offset;

- (NSString*) description
{
    return rawEntry;
}

@end


有想要完整demo工程的,请移步下载。稍后给出链接。


iOS 26 崩溃日志深度指南,如何收集、符号化、定位与监控 本文聚焦 iOS 26 崩溃日志处理,讲解新版系统中可能的 SDK 与 API 崩溃风险,介绍如何用 Xcode + dSYM + KeyMob 捕获、符号化、分析崩溃日志,结合典型案例(如 EXC_BREAKPOINT / URLSession 崩溃)提供实战流程与定位策略。 阅读详情

相关推荐

iOS奔溃分析技巧-crash日志符号化

前言 iOS开发需要不停发版本,开发者要面临线上各种版本的奔溃日志(crash log),解决奔溃问题是移动开发者最日常的工作之一. 在实际的项目开发中,崩溃问题,依赖xcode,依赖于系统记录的崩溃日志或错误堆栈,在本地开发调试阶段,是没有问题的。 如果在发布的线上版本出现崩溃问题,开发者是无法即时准确的取得错误堆栈的,需要获取到crash日志,进行相应处理。 简单的崩溃还好说,复杂的崩...

代码手工艺术家的专栏 2344

C++ 23 的栈踪迹库(stacktrace)

许多编程语言都提供调用栈踪迹回溯的功能,在错误发生的时候,除了报告错误发生的位置,还能输出函数调用栈信息。现在,C++ 也有自己的栈踪迹库了

oRbIt 的专栏 2285

Crash-Manager, 用于记录崩溃事件的iOS库.zip

Crash-Manager, 用于记录崩溃事件的iOS库 重要说明:这个崩溃管理器不处理所有可能的崩溃情况。 有一些( 。如堆栈溢出或者已损坏的对象指针) 崩溃可能导致崩溃管理器失败,并不会记录崩溃。一个更健壮的解决方案在这里是有用的。崩溃管理器用于记录崩溃事件的iOS库。许可证卡尔

iOS异常捕获

前言 在阅读文章之前,建议大家在阅读完此篇文章后可以阅读漫谈iOS Crash收集框架,了解一下原理。 开发iOS应用,解决Crash问题始终是一个难题。Crash分为两种,一种是由EXC_BAD_ACCESS引起的,原因是访问了不属于本进程的内存地址,有可能是访问已被释放的内存;另一种是未被捕获的Objective-C异常(NSException),导致程序向自身发送了SIGABRT信号

sadlike的专栏 1223

拌合楼管理软件开发(十一) 海康威视车牌识别摄像头安装调试,总算是跑通了。

/保存的文件个数这里之所以需要用到委托,直接更新textbox文本中的内容,以及复制picturebox的image会提示不是从齐创建的线程调用。

morsth的博客 4816

C语言——利用矩阵LU分解法求逆、行列式

本章介绍了LU分解法,以及如何利用LU分解法求逆、行列式,针对每个公式、原理、代码进行了详细介绍,希望可以给大家带来帮助。

王元笙 1万+

ios崩溃日志收集_iOS崩溃日志收集与解析

收集crash日志方式1.设备上直接查看路径:设置 -> 隐私 -> 分析 -> 分析数据2.xcode获取设备上信息路径:xcode菜单栏Window -> Devices and Simulators -> 选中设备 -> View Device Logs3.xcode获取发布版本崩溃信息路径:xcode菜单栏Window -> Organizer -...

weixin_39754616的博客 812

基于YOLOv5与海康工业相机的高分辨率实时检测实践

本文详细介绍了基于YOLOv5与海康工业相机的高分辨率实时检测实践,通过优化相机配置、网络传输和YOLOv5模型适配,实现了每秒15帧以上的实时检测性能,缺陷识别准确率高达99.2%。特别适用于电子元件焊接点检测、精密齿轮齿痕检查等对微小缺陷敏感的场景。

weixin_30872499的博客 474

iOS Crash收集与分析详解(基础篇)

前言: 最近测试妹子老是抱怨我偶现的Bug不好复现,我这边出于偷懒(其实是工作很忙)一直再说不能复现Bug的妹子不是好测试,最近闲下来了,正好谈谈Crash的收集和分析。 一、Crash收集 噔噔噔噔~万能的官方文档又出现了,先上地址Understanding and Analyzing Application Crash Reports Crash收集与解析流程图 通过上图我们可以发现Crash的收集主要有两种方式。 1、使用Xcode从设备获取崩溃日志: 如果你把你的手机连接到Mac

feelinghappy的专栏 2729

STM32H750xx【QSPI】轮询方式读写GD25Q64E

本文详细介绍了GD25Q64E其特性、引脚定义及功能说明,重点阐述了在STM32H750平台上通过CubeMX配置QuadSPI接口的步骤,包括时钟设置、参数优化等。文章提供了完整的BSP驱动开发流程,涵盖写使能、四线模式使能、ID读取、解除保护、扇区擦除、整片擦除、页编程和数据读取等关键功能实现,并通过读写测试验证了DummyCycles参数对数据准确性的影响。

honmy18的博客 1422

STM32硬件SPI驱动W5500以太网模块全流程(附避坑指南)

本文详细介绍了如何使用STM32硬件SPI驱动W5500以太网模块,包括开发环境准备、SPI接口配置、网络参数设置及常见问题排查。通过官方驱动移植和实战案例,帮助开发者快速实现以太网通信功能,适用于智能家居、工业控制等物联网应用场景。

weixin_29192141的博客 364

IOS里用宏定义通用单例

程序里经常使用单例,可以做成一个简单的宏作为实现部分,来提高开发效率. MyClass类头文件里定义一个静态函数: + (MyClass*)sharedMyclass; 实现部分:SYNTHESIZE_SINGLETON_FOR_CLASS(MyClass); 定义宏如下: #define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \  \

zhuangyou123的专栏 4060

CloudCompare 二次开发:插件中的 PCL 环境配置与编程

在进行 CloudCompare 的二次开发过程中,我们常常需要使用点云库(Point Cloud Library,简称 PCL)来处理和分析点云数据。在 CloudCompare 的界面中,选中一个点云对象,然后点击菜单栏中的 “插件” -> “MyPluginAction”。插件将对选中的点云对象进行体素滤波处理,并更新显示结果。下面我们将展示一个简单的插件编程示例,该示例使用 PCL 对输入的点云数据进行体素滤波处理。方法进行体素滤波处理,并将结果点云赋值给选中的点云对象。文件并点击 “打开”。

2301_79331387的博客 283

【iOS】崩溃收集和解析

背景 在日常开发中,app难免会发生崩溃。简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较常见的。 获取崩溃信息方式 在iOS中获取崩溃信息的方式有很多,比较常见的是使用友盟、云测、百度等第三方分析工具,或者自己收集崩溃信息并上传公司服务器。 下面列举一些我们常用的崩溃分析方式: 使用友盟、云测、百度等第三方崩溃统计工具。 自己实现应用内崩溃收集,并上传服务器。 Xcode-Devices中直接查看某个设备的崩溃信息。 使用苹果提供的Crash崩

BestpayTech的博客 2089

⑩电子产品拆解分析-家用无线遥控开关433Mhz

①免布线随意贴,装上就能使用解决单线开关烦恼;②遥控配对简单,无线通讯距离长,信号可穿墙;

a6662580的博客 4702

《Python基础教程》内容总览篇(持续更新中)

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为优快云博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理解,而且能够帮助新手快速入门。个人精心开设的《Python基础课程》专栏订阅量接近900,帮助不少同学解决了Bug。

weixin_43178406的博客 35万+

一文读懂iOS中的Crash捕获、分析以及防治

对于iOS端开发,定位和解决Crash毕竟两个流程,首先是根据线索来分析和定位问题,得到一个大概的猜想,之后按照自己的猜想去提供外部条件,来尝试复现问题,如果问题能够成功复现并复原与线程问题相似的堆栈现场,则基本完成了90%的工作,剩下的10%才是修复此问题。对于crash比例极低的,例如没有版本相关性的,对我们的应用影响极小的,我们可以通过去做AB实验尝试去修复。2.bad_access的排查途径有哪些?3.什么情况下会产生bad_access?

黑码哥的技术博客 2万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

iOS crash崩溃日志总结

引言 当游戏运行崩溃(也叫闪退)时,iOS系统生成对应的*.crash崩溃日志并保存在设备上。这份崩溃日志通常包含游戏闪退时当时运行的每个线程的堆栈调用信息,我们通过分析这些信息,定位游戏闪退发生的代码位置和异常类型。默认情况下,崩溃日志的堆栈调用信息是一堆16进制的内存地址和偏移量数字组成,如图 并不具有可读性。需要将其导入到Xcode,通过对应的dSYM文件和游戏包体,才能将这些数字转化成游戏代码里的调用方法名和所在文件的行数,如图, 从而生成我们可以分析的具体堆栈调用信息。 一、如何获取崩溃日志。

justbeme的专栏 1576

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

iOS Crash收集与分析

一、收集crash 1、使用Xcode从设备获取崩溃日志: 如果你把你的手机连接到Mac,并选择Xcode->Windows->Device and Simulator,然后点击View Device Logs,你会看到手机上会有好多Log,其中Type为Crash的就是崩溃的Log,如下图: 2、通过设备直接获取崩溃日志 1)打开设置->隐私->分析->分析数据,...

weixin_37543822的博客 343

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

如何符号化iOS系统的Crash日志

介绍如何获取Crash日志并符号化日志

专注于苹果IOS开发和最新资讯 3038

教你如何对ios崩溃(crash)日志做符号化

一、场景         客户端的开发流程都相似,如android,搞ios开发就要不停地发版本,随之而来的就是各种版本的崩溃日志(称为crash log)。如果不能好好地管理,那么开发人员很快就会在crash log和版本的海洋里迷失方向。解决崩溃问题是移动应用开发者最日常的工作之一。如果是开发过程中遇到的崩溃,可以根据重现步骤调试,但线上版本就无能为力了。         国内,一

Weiguang_123的专栏 2万+

iOS崩溃crash大解析

前言 iOS崩溃是让iOS开发人员比较头痛的事情,app崩溃了,说明代码写的有问题,这时如何快速定位到崩溃的地方很重要。调试阶段是比较容易找到出问题的地方的,但是已经上线的app并分析崩溃报告就比较麻烦了。 之前我总是找到一个改一个,并靠别人测试重现来找出问题的地方,这样往往比较耗费时间。而且比较难找到原因的时候每次都是到网上找各种资源搜索,解决了之后也没有认真分析原因及收集,时间长了

fishmai的专栏 1531

iOS崩溃日志crash logs追踪以及调试方法

iOS崩溃日志crash logs追踪以及调试方法          在IOS程序开发和以及在真机运行程序时,经常会遇到程序crash的情况,从哪里可以获得crash的日志文件,以便更好的分析程序崩溃的原因,让应用更加完美。          在真机运行程序出现crash状况时,机器会自动产生log文件,它包含了在程序crash之前正在做什么的信息。在pc上对手机或者ipad设备进行同

1172

iOS应用的crash日志的分析基础

Outline 如何获得crash日志 如何解析crash日志 如何分析crash日志      1. iOS策略相关      2. 常见错误标识      3. 代码bug 一、如何获得crash日志 当一个iOS应用程序崩溃时,系统会创建一份crash日志保存在设备上。这份crash日志记录着应用程序崩溃时的信息,通常包含着每个执行线程的栈调用信息(低内存闪退日志

JasonLee的专栏 5万+

查看iOS Crash logs的方法(程序崩溃)

一、如何获得crash日志 当一个iOS应用程序崩溃时,系统会创建一份crash日志保存在设备上。这份crash日志记录着应用程序崩溃时的信息,通常包含着每个执行线程的栈调用信息(低内存闪退日志例外),对于开发人员定位问题很有帮助。 如果设备就在身边,可以连接设备,打开Xcode - Window - Devices,在左侧面板中选择你的设备  然后选择Device Logs(可

zhongmin_li的博客 1508

iOS崩溃调试的使用和技巧总结

在iOS开发调试过程中以及上线之后,程序经常会出现崩溃的问题。简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较常见的。 现在网上有很多关于解析崩溃信息的博客,但是大多质量参差不齐,或者有些细节没有注意到。今天写一篇博客总结一下我对崩溃调试的使用和技巧,如果有哪些错误或遗漏,还请指点,谢谢! 获取崩溃

Junyan_Jaya的博客 384
上一篇: AMR文件分析
下一篇: amr编码
JackHu
博客等级 码龄17年 4粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值