热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

自己动手写一个Bug管理工具

timg.jpeg##功能非CrashBug在App内可截图添加描述并发送CrashBug在App第二次启动时提取Crashlog添加描述并发送##分析非Crash的Bug
timg.jpeg

##功能

  • 非Crash Bug 在App内可截图添加描述并发送
  • Crash Bug 在App第二次启动时提取Crash log添加描述并发送

##分析
非Crash的Bug:字体不对、颜色不对、数据不对、布局不对。
Crash Bug:系统Crash、处理signal

场景交互:发现非Crash Bug时候摇一摇手机,弹出邮件,图片带入邮件,点击发送即可。有Crash Bug的时候第二次启动App,弹出邮件,Crash log带入邮件,点击发送即可。

需要用到NSSetUncaughtExceptionHandler,MFMailComposeViewController,沙盒,NSFileManager。

##实现
截图的功能,考虑到并不是所有的页面都需要使用所以写在了分类里。需要用的时候直接引入头文件即可。

//这三个方法分别在摇一摇的时候回调用,开始,需要,结束。他们的父类是UIResponsder在UIKit中。
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event{}
-(void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event{}
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{[self screenShot];
}-(void)screenShot
{UIWindow *screen = [[UIApplication sharedApplication] keyWindow];UIGraphicsBeginImageContext(screen.frame.size);[screen.layer renderInContext:UIGraphicsGetCurrentContext()];UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsGetCurrentContext();NSData *screenData = UIImagePNGRepresentation(image);[screenData writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"] atomically:YES];
}

发送邮件的功能,也写在了分类里面,需要用的时候引入即可。

@interface UIViewController (send)//发送邮件的方法,传入标题,描述信息,data, 接收人
-(void)sendMail:(MFMailComposeViewController*)mf andSubject:(NSString*)subject andMessageBody:(NSString*)message andData:(NSData*)data andRecipients:(NSArray*)recipients
{if([MFMailComposeViewController canSendMail]){mf.mailComposeDelegate = self;[mf setSubject:subject];[mf setToRecipients:recipients];[mf addAttachmentData:data mimeType:@"image/jpeg" fileName:@"error"];[mf setMessageBody:message isHTML:YES];[self presentViewController:mf animated:YES completion:nil];}else{[self alertView:@"不能调用邮箱" andDesc:@"请尝试下载App原生邮箱,并配置"];}
}//MFMailComposeViewControllerDelegate的代理方法,可以在这个方法里面写一些回调
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{switch (result) {case MFMailComposeResultSent:[self alertView:@"发送成功" andDesc:nil];self.success();break;case MFMailComposeResultSaved:[self alertView:@"保存成功" andDesc:nil];break;case MFMailComposeResultFailed:self.faild();[self alertView:error.domain andDesc:[NSString stringWithFormat:@"%@",error.userInfo]];break;case MFMailComposeResultCancelled:[self alertView:@"取消发送" andDesc:nil];break;default:[self alertView:@"为什么不发送" andDesc:nil];break;}[self dismissViewControllerAnimated:YES completion:nil];
}

异常捕获

这两个为函数方法,导入类名,直接可调用不用初始化
void CrashExceptionHandler(void)
{NSSetUncaughtExceptionHandler(&ExceptionLog);
}void ExceptionLog(NSException *exception)
{NSDate *date_current = [NSDate date];NSDictionary *dictInfo = [[NSBundle mainBundle]infoDictionary];NSString *name_App = [dictInfo objectForKey:@"CFBundleDisplayName"];NSString *verson_App = [dictInfo objectForKey:@"CFBundleShortVersionString"];NSString *build_App = [dictInfo objectForKey:@"CFBundleVersion"];NSArray *ecp = exception.callStackSymbols;NSString *reason = [exception reason];NSString *name = [exception name];NSString *exceptionInfo = [NSString stringWithFormat:@"\n\n ******************************异常日志****************************** \n时间:%@\nApp名称:%@\nApp版本:%@\nBuild版本:%@\n异常名称:%@\n异常原因:%@\n堆栈信息:%@",date_current,name_App,verson_App,build_App,name,reason,ecp];[CrashHandler saveLog:exceptionInfo andDate:date_current];
#ifdef DEBUGNSLog(@"%@",exceptionInfo);
#else#endif}@implementation CrashHandler
+(void)saveLog:(NSString *)crashLog andDate:(NSDate *)date
{NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)objectAtIndex:0] stringByAppendingString:@"/Crash"];if(![[NSFileManager defaultManager]fileExistsAtPath:path]){[[NSFileManager defaultManager]createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];}NSString *logPath = [path stringByAppendingFormat:@"/%@.log",date];[crashLog writeToFile:logPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
@end

检测Crash log 功能在App打开的第一个页面去调用就好

-(void)crashLog
{NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)objectAtIndex:0] stringByAppendingString:@"/Crash"];NSFileManager *mf = [NSFileManager defaultManager];if(![mf fileExistsAtPath:path]){return;}NSArray *array = [mf contentsOfDirectoryAtPath:path error:nil]; }

以上代码均为局部代码,具体代码请移步github

##为什么要写

###此处废话,可忽略

最近找工作面技术的时候经常会聊到App中bug的处理,我前公司Web端业务繁重领导并不太关心App,只有一个全局的异常捕获还是我软磨硬泡加进去的。我只有实话实说,告诉他我们的Bug统计平台,又胡诌一些个人意见可加入第三方Bug管理工具(OneAPM,Bugly)。这并不是满意的答案,他们的Bug是自己写的工具,所以我只能继续求职中。

我们前公司的Bug管理用过禅道、OSChina、Jira。(经历过四个技术总监)

  • 禅道
    我们之前的测试老大用公司服务器搭建的,中规中矩,我觉得很好用啊,配合着jekins还能去看后台的日志。
  • OSChina
    第三个技术总监用的,省事,拿过来直接用就好,不用搭建服务器什么的。
  • jira
    第四任技术总监搭建的,功能最为强大,正版的jira很贵,我们用的破解版。

以上都有着完整的项目管理系统,包括了任务安排,Bug追踪系统等等,日常工作够用了。当有Bug的时候测试人员需要在手机上手动截图,将图片导入PC后再上传平台上,再由平台发给对应的开发人员。如果有崩溃的Bug还要想着复现,握着数据线插,拿着手机走来走去,是不是很麻烦。所以写了一个小工具,关于信号量的异常捕获,有待日后完善,见笑了。

转:https://juejin.im/post/59db05d5f265da065c5ebed4



推荐阅读
  • 尽管在WPF中工作了一段时间,但在菜单控件的样式设置上遇到了一些基础问题,特别是关于如何正确配置前景色和背景色。 ... [详细]
  • 在AngularJS中,有时需要在表单内包含某些控件,但又不希望这些控件导致表单变为脏状态。例如,当用户对表单进行修改后,表单的$dirty属性将变为true,触发保存对话框。然而,对于一些导航或辅助功能控件,我们可能并不希望它们触发这种行为。 ... [详细]
  • 本文介绍了如何使用 Python 的 Pyglet 库加载并显示图像。Pyglet 是一个用于开发图形用户界面应用的强大工具,特别适用于游戏和多媒体项目。 ... [详细]
  • 本文探讨了互联网服务提供商(ISP)如何可能篡改或插入用户请求的数据流,并提供了有效的技术手段来防止此类劫持行为,确保网络环境的安全与纯净。 ... [详细]
  • 本文深入探讨了WPF框架下的数据验证机制,包括内置验证规则的使用、自定义验证规则的实现方法、错误信息的有效展示策略以及验证时机的选择,旨在帮助开发者构建更加健壮和用户友好的应用程序。 ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • 管理UINavigationController中的手势返回 - Managing Swipe Back Gestures in UINavigationController
    本文介绍了如何在一个简单的闪存卡片应用中实现平滑的手势返回功能,以增强用户体验。 ... [详细]
  • Kubernetes Services详解
    本文深入探讨了Kubernetes中的服务(Services)概念,解释了如何通过Services实现Pods之间的稳定通信,以及如何管理没有选择器的服务。 ... [详细]
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • 本文介绍了在Visual C++环境中通过编程实现鼠标移动及点击的具体方法,包括获取鼠标当前位置、移动鼠标至指定位置并执行点击等操作。 ... [详细]
  • 本文详细介绍了如何在Java Swing中使用`JButton.registerKeyboardAction()`方法来为按钮设置键盘快捷键,并提供了多个实用的代码示例。 ... [详细]
  • Flutter 核心技术与混合开发模式深入解析
    本文深入探讨了 Flutter 的核心技术,特别是其混合开发模式,包括统一管理模式和三端分离模式,以及混合栈原理。通过对比不同模式的优缺点,帮助开发者选择最适合项目的混合开发策略。 ... [详细]
  • 在尝试启动Java应用服务器Tomcat时,遇到了org.apache.catalina.LifecycleException异常。本文详细记录了异常的具体表现形式,并提供了有效的解决方案。 ... [详细]
  • Spring Boot使用AJAX从数据库读取数据异步刷新前端表格
      近期项目需要是实现一个通过筛选选取所需数据刷新表格的功能,因为表格只占页面的一小部分,不希望整个也页面都随之刷新,所以首先想到了使用AJAX来实现。  以下介绍解决方法(请忽视 ... [详细]
  • 本文介绍了如何通过 AJAX 发送请求到后端控制器,并将返回的 JSON 数据解析后在前端页面上显示。具体步骤包括发送 AJAX 请求、解析 JSON 字符串和遍历数据。 ... [详细]
author-avatar
我不是古哥
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有