有一段时间没有更新博客了,今天更新一篇关于最近工作中用到的一个功能,先简单描述一下:我们知道,测试人员在测试客户端产品时,当出现问题或者BUG的时候,都得先对页面截图,然后从相册中选择截图,加上一段描述放到TD库或者直接通过邮件发给开发人员,以方便开发人员进行修改,过程繁琐。通过下面功能的介绍,您可以很方便的让测试人员遇到BUG的时候,摇一摇设备,然后自动截图并保存到应用的沙盒之中。截图保存到沙盒之后,您可以自定义一个问题反馈的页面,对问题进行描述(描述可使用第三方平台,如讯飞语音,实现语音录入的效果)之后,将描述信息和页面截图一起发送给开发人员(可以是邮件,也可以是直接发送到后台)。

  下面来看看功能是怎么实现的。

  首先,定义了一个category:ShakeAndCutter

  UIViewController+ShakeAndCutter.h文件源码:

  1. #import <UIKit/UIKit.h>
  2.  
  3. @interface UIViewController (ShakeAndCutter)
  4.  
  5. @end

  UIViewController+ShakeAndCutter.m文件源码:

  1. #import "UIViewController+ShakeAndCutter.h"
  2. #import <QuartzCore/QuartzCore.h>
  3. #import "TestFeedbackViewController.h"
  4.  
  5. @implementation UIViewController (ShakeAndCutter)
  6.  
  7. - (BOOL)canBecomeFirstResponder
  8. {
  9. return YES;
  10. }
  11.  
  12. #pragma mark - 摇一摇动作处理
  13.  
  14. - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
  15. {
  16. NSLog(@"began");
  17. }
  18.  
  19. - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
  20. {
  21. NSLog(@"cancel");
  22. }
  23.  
  24. - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
  25. {
  26. NSLog(@"end");
  27. [self cutterViewToDocument];
  28.  
  29. // 这里是自定义的问题反馈页面,也可以直接跳转到系统邮件发送的页面
  30. TestFeedbackViewController *testFeedbackViewController = [[[TestFeedbackViewController alloc] initWithNibName:@"TestFeedbackViewController" bundle:nil] autorelease];
  31. [self.navigationController pushViewController:testFeedbackViewController animated:YES];
  32. }
  33.  
  34. #pragma mark - 截屏处理
  35.  
  36. - (void)cutterViewToDocument
  37. {
  38. UIWindow *screenWindow = [[UIApplication sharedApplication] keyWindow];
  39.  
  40. UIGraphicsBeginImageContext(screenWindow.frame.size);
  41. [screenWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
  42. UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext();
  43. UIGraphicsEndImageContext();
  44.  
  45. NSData *screenShotPNG = UIImagePNGRepresentation(screenShot);
  46. NSError *error = nil;
  47. [screenShotPNG writeToFile:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"error.png"] options:NSAtomicWrite error:&error];
  48. }
  49.  
  50. @end

  至此,摇一摇和截图功能就已经完成了,那么在应用中怎么使用呢?

  • 对于IOS6.0以上的设备,只需要在项目的pch文件中引进头文件#import "UIViewController+ShakeAndCutter.h"即可(我在IOS6.0.1、IOS6.1.5、IOS7.0.6设备上已经测试过),这样测试工作完成之后,您只需要将这行代码注释或者删除就可以了;
  • 对于IOS6.0以下的设备,在需要实现摇一摇效果的页面,有可能要加入如下代码(手头没有IOS6.0以下的设备,如果大家有的话,帮忙验证一下,非常感谢):

  1.viewDidLoad方法中,添加两行代码:

  1. [[UIApplication sharedApplication] setApplicationSupportsShakeToEdit:YES];
  2. [self becomeFirstResponder];

2.viewDidAppear方法中,添加一行代码:

  1. [self becomeFirstResponder];

3.viewDidDisappear方法中,添加一行代码:

  1. [self resignFirstResponder];

  当然,以上的功能,您也可以实现其他的效果:比如说用户问题的反馈等等,具体可以根据应用的需求而定。

  

  这里,再附上发送到邮件功能的示例代码:

  MailViewController.h文件源码:

  1. #import <UIKit/UIKit.h>
  2. #import <MessageUI/MessageUI.h>
  3. #import<MessageUI/MFMailComposeViewController.h>
  4.  
  5. @interface MailViewController : UIViewController<MFMailComposeViewControllerDelegate,
  6. MFMessageComposeViewControllerDelegate>
  7. {
  8. UIButton *shareToMailButton;
  9. }
  10.  
  11. @end

  MailViewController.m文件源码:

  1. #import "MailViewController.h"
  2. #import "Constants.h"
  3.  
  4. @interface MailViewController ()
  5.  
  6. @end
  7.  
  8. @implementation MailViewController
  9.  
  10. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  11. {
  12. self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  13. if (self) {
  14. // Custom initialization
  15. }
  16. return self;
  17. }
  18.  
  19. - (void)viewDidLoad
  20. {
  21. [super viewDidLoad];
  22. // Do any additional setup after loading the view.
  23.  
  24. self.title = @"Bug反馈";
  25.  
  26. shareToMailButton = [self buttonWithFrame:CGRectMake(, , , ) action:@selector(btnClicked:) withTag:];
  27. [shareToMailButton setTitle:@"Bug反馈" forState:UIControlStateNormal];
  28. }
  29.  
  30. - (void)didReceiveMemoryWarning
  31. {
  32. [super didReceiveMemoryWarning];
  33. // Dispose of any resources that can be recreated.
  34. }
  35.  
  36. #pragma mark - 自定义方法
  37.  
  38. - (void)btnClicked:(id)sender
  39. {
  40. UIButton *btnSender = (UIButton *)sender;
  41.  
  42. switch (btnSender.tag)
  43. {
  44. case : // 分享到邮箱
  45. {
  46. [self showMailPicker];
  47. break;
  48. }
  49. default:
  50. break;
  51. }
  52. }
  53.  
  54. /*******************************************************************************
  55. * 方法名称:buttonWithFrame:action:
  56. * 功能描述:初始化页面按钮,并添加到页面视图
  57. * 输入参数:
  58. * 输出参数:
  59. ******************************************************************************/
  60. - (UIButton *)buttonWithFrame:(CGRect)frame action:(SEL)action withTag:(int)tag
  61. {
  62. UIImage *buttonBackgroundImage = [[UIImage imageNamed:@"button_background.png"] stretchableImageWithLeftCapWidth: topCapHeight:];
  63. UIImage *disabledButtonBackgroundImage = [[UIImage imageNamed:@"button_background_disabled.png"] stretchableImageWithLeftCapWidth: topCapHeight:];
  64.  
  65. UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
  66. button.frame = frame;
  67. [button setBackgroundImage:buttonBackgroundImage forState:UIControlStateNormal];
  68. [button setBackgroundImage:disabledButtonBackgroundImage forState:UIControlStateDisabled];
  69. [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  70. [button setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled];
  71. [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
  72. button.tag = tag;
  73. [self.view addSubview:button];
  74.  
  75. return button;
  76. }
  77.  
  78. - (void)showMailPicker
  79. {
  80. Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));
  81.  
  82. if (mailClass !=nil)
  83. {
  84. if ([mailClass canSendMail])
  85. {
  86. [self displayMailComposerSheet];
  87. }
  88. else
  89. {
  90. UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@""message:@"设备不支持邮件功能" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
  91. [alert show];
  92. [alert release];
  93. }
  94. }
  95. else
  96. {
  97.  
  98. }
  99.  
  100. }
  101.  
  102. - (void)displayMailComposerSheet
  103. {
  104. MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
  105.  
  106. // 设置picker的委托方法,完成之后会自动调用成功或失败的方法
  107. picker.mailComposeDelegate = self;
  108. // 添加主题
  109. [picker setSubject:@"Bug反馈"];
  110. // 添加收件人
  111. NSArray *toRecipients = [NSArray arrayWithObject:@"279352257@qq.com"];
  112. // 说明:也可以添加多个收件人,代码如下所示:
  113. // NSArray *toRecipients = [NSArray arrayWithObjects:@"one@qq.com",@"two@qq.com",nil];
  114. // 添加抄送
  115. // NSArray *ccRecipients = [NSArray arrayWithObjects:@"second@qq.com",@"third@qq.com", nil];
  116. // 添加密送
  117. // NSArray *bccRecipients = [NSArray arrayWithObject:@"fourth@qq.com"];
  118.  
  119. [picker setToRecipients:toRecipients];
  120. // [picker setCcRecipients:ccRecipients];
  121. // [picker setBccRecipients:bccRecipients];
  122. // 发送图片附件(其他格式的附件,可以都先转化称NSData类型,然后设置相应的mimeType即可,如txt类型为@"text/txt",doc类型为@"text/doc",pdf类型为@"file/pdf"等等)
  123. NSData *myData = [NSData dataWithContentsOfFile:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"error.png"]];
  124. [picker addAttachmentData:myData mimeType:@"image/jpeg" fileName:@"error.png"];
  125. NSString *emailBody = [NSString stringWithFormat:@"<p>文字没有全部显示</p>"];
  126.  
  127. // 直接在HTML代码中写入图片的地址
  128. // NSString *emailBody = [NSString stringWithFormat:@"<img src='http://p2.so.qhimg.com/t0130e3288d86929b97.jpg' /><p>我分享了图片</p>"];
  129.  
  130. [picker setMessageBody:emailBody isHTML:YES];
  131. [self presentModalViewController:picker animated:YES];
  132. [picker release];
  133. }
  134.  
  135. - (void)mailComposeController:(MFMailComposeViewController*)controller
  136. didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
  137. {
  138. switch (result)
  139. {
  140. case MFMailComposeResultCancelled:
  141. NSLog(@"Result: Mail sending canceled"); // 邮件发送取消
  142. break;
  143. case MFMailComposeResultSaved:
  144. NSLog(@"Result: Mail saved"); // 邮件保存成功
  145. break;
  146. case MFMailComposeResultSent:
  147. NSLog(@"Result: Mail sent"); // 邮件发送成功
  148. break;
  149. case MFMailComposeResultFailed:
  150. NSLog(@"Result: Mail sending failed"); // 邮件发送失败
  151. break;
  152. default:
  153. NSLog(@"Result: Mail not sent");
  154. break;
  155. }
  156. [self dismissModalViewControllerAnimated:YES];
  157. }
  158.  
  159. - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
  160. {
  161. NSLog(@"messageComposeViewController");
  162. }
  163.  
  164. @end

IOS中摇一摇实现截屏(可实现问题反馈的功能)的更多相关文章

  1. iOS 中对各种视图的截屏以及分享

    1.一个第三方的工具,主要是对表视图.滚动视图.视图的扩展,用法也很简单 image = [tableview screenshot]; 2.然后将截的图片分享出去,在分享的时候,因为多个地方用到了截 ...

  2. iOS开发 代码 或 <Home+Power>截屏

      1. 截屏的两种简单方法, 注意这两种截图方法,都必须在视图完全加载完成后才能截图,即在 viewDidAppear 方法之后截屏,否则无法得到想要的截屏效果 (1) 利用绘图方法 renderI ...

  3. iOS开发之如何修改Mac截屏保存路径

    如何修改Mac截屏保存路径   MAC OS X系统默认的截图路径是桌面文件夹,默认的截图格式是 PNG 图片格式,如何自定义设置呢? 截图保存路径 打开终端(Terminal)并输入如下命令: de ...

  4. react native 中实现个别页面禁止截屏

    这里主要用到了原生模块,下面贴出FlagSecureModule.java的代码 package com.studyproj.flagsecure; import android.util.Log; ...

  5. IOS 上架要求视频及屏幕截屏

    客户提供上架的资料 1.IOS 上架要求视频演示,录制一段视频,上传到优酷,需要url连接. 2.手机截屏,每个尺寸5张.5s/6/6p *5=15张.截屏图片分辨率. iPhone4s手机 3.5I ...

  6. IOS中调用系统的电话、短信、邮件、浏览功能

    iOS开发系列--通讯录.蓝牙.内购.GameCenter.iCloud.Passbook系统服务开发汇总 2015-01-13 09:16 by KenshinCui, 26990 阅读, 35 评 ...

  7. IOS中实现图片点击全屏预览

    //// ViewController.m// XWZoomImageView//// Created by xiao on 15/11/13.// Copyright © 2015年 xiao. A ...

  8. iOS中正确的截屏姿势

    昨天写了个用到截屏功能的插件,结果问题不断,今天终于解决好了,把debug过程中所有尝试过的截屏方法都贴出来吧- 第一种 这是iOS 3时代开始就被使用的方法,它被废止于iOS 7.iOS的私有方法, ...

  9. iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏)

    iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏) 2017.03.16 12:18* 字数 52 阅读 563评论 4喜欢 2 1. 截取屏幕尺寸大小的图片并保存至相册 ...

随机推荐

  1. java.lang.NoClassDefFoundError: Could not initialize class com.demo.jdbc.utils.MyJdbcUtils

    jdbc编写工具类的过程中测试失败, 出现如下错误:   原因:初始化的过程中执行静态代码块的过程中出现错误, 也就是说, 加载配置文件错误: 没有加载到指定路径的配置文件. 我的MyJdbcUtil ...

  2. [CXF REST标准实战系列] 一、JAXB xml与javaBean的转换(转)

    转自:[CXF REST标准实战系列] 一.JAXB xml与javaBean的转换 文章Points: 1.不认识到犯错,然后得到永久的教训. 2.认识JAXB 3.代码实战 1.不认识到犯错,然后 ...

  3. yaml语法三大规则

    规则一:缩进 yaml使用一个固定的缩进风格表示数据层结构关系,Saltstack需要每个缩进级别由两个空格组成.一定不能使用tab键 规则二:冒号 yaml:  mykey: my_value  每 ...

  4. MVC公司架构介绍-事件机制

  5. asp.net core mvc视频A:笔记4-1.数据验证

    开发建议:永远不要相信客户端提交过来的数据!!! 前端数据验证定位:提高用户体验,仅此而已! 后端数据验证定位:保证系统安全与数据完整!!! 实例:用户登录验证 定义一个用户登录类 在用户登录类基础上 ...

  6. pycurl 学习笔记--getinfo 函数

    通过 pycurl.Curl 对象的 getinfo 函数,可以获取到响应的如下信息: (参考: http://curl.haxx.se/libcurl/c/curl_easy_getinfo.htm ...

  7. Spring中的内部Bean

    简介 当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,可以在 <property/> ...

  8. Oracle学习笔记之二,Oracle 11g体系结构

    Oracle 11g体系结构概述 实例(Instance),是指一组Oracle后台进程以及在服务器中分配的共享内存区域: 数据库(Database),是由基于磁盘的数据文件.控制文件.日志文件.参数 ...

  9. 【Android】3.13 路径规划功能

    分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 一.简介 线路规划支持以下功能: 公交信息查询:可对公交详细信息进行查询: 公交换乘查询:根据起.终点,查询策 ...

  10. 黑客编程教程(三)Windows 网络协议

    首先介绍一下网络协议:网络协议是网络上所有设备之间通信规则的集合,他定义了通信时信息必须采用的格式和这些格式的意义.大多数 网络协议都采用分层体系结,每一层都建立在他的下层之上,向他的上一层提供服务, ...