Skip to content

Instantly share code, notes, and snippets.

@rupey
Last active January 7, 2016 02:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rupey/fb2277135c1a300b8753 to your computer and use it in GitHub Desktop.
Save rupey/fb2277135c1a300b8753 to your computer and use it in GitHub Desktop.
Capturing customer feedback with a device log on iOS
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#include <asl.h>
@interface FeedbackViewController : UIViewController <MFMailComposeViewControllerDelegate>
@property (nonatomic, strong) IBOutlet UITextView *textView;
@property (nonatomic, strong) NSString *feedbackType;
@end
@implementation FeedbackViewController
- (void)sendMail
{
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:[@"AppName - " stringByAppendingString:self.feedbackType]];
NSArray *toRecipients = @[@"support@yourapp.com"];
[mailer setToRecipients:toRecipients];
// Generate body
NSString *appShortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
NSString *emailBody = [NSString stringWithFormat:@"%@\n\nVersion: %@ (%@)", self.textView.text, appShortVersion, appVersion];
[mailer setMessageBody:emailBody isHTML:NO];
#if !TARGET_IPHONE_SIMULATOR
[mailer addAttachmentData:[self getConsoleLog] mimeType:@"text/plain" fileName:@"application.log"];
#endif
[self presentViewController:mailer animated:YES completion:^{}];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Mail is unavailable"
message:@"Check your device is connected to the Internet and you have set up a Mail account in the Settings app."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(@"Mail cancelled: you cancelled the operation and no email message was queued.");
break;
case MFMailComposeResultSaved:
NSLog(@"Mail saved: you saved the email message in the drafts folder.");
break;
case MFMailComposeResultSent:
NSLog(@"Mail send: the email message is queued in the outbox. It is ready to send.");
break;
case MFMailComposeResultFailed:
NSLog(@"Mail failed: the email message was not saved or queued, possibly due to an error.");
break;
default:
NSLog(@"Mail not sent.");
break;
}
// Remove the mail view
[self dismissViewControllerAnimated:YES completion:^{
if (result == MFMailComposeResultSent)
[self.navigationController popViewControllerAnimated:YES];
}];
}
// Get the app's console log
- (NSData *)getConsoleLog
{
// Create an Apple System Log query.
aslmsg query = asl_new(ASL_TYPE_QUERY);
aslresponse response = asl_search(NULL, query);
// Iterate through the query responses and assemble them into a log string.
NSString* logString = [NSString new];
aslmsg message;
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
while ((message = aslresponse_next(response)) != NULL) {
@autoreleasepool {
NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary];
const char *key, *val;
// Get all the key/value pairs from the response message. We don't really need them all, but it's a little simpler to just get them all in C.
for (int i = 0; (key = asl_key(message, i)) != NULL; i++) {
NSString *keyString = [NSString stringWithUTF8String:(char *)key];
val = asl_get(message, key);
NSString *string = val ? [NSString stringWithUTF8String:val] : @"";
[tmpDict setObject:string forKey:keyString];
}
// Get the key/value pairs that we want and append them to the log string.
NSDate* date = [NSDate dateWithTimeIntervalSince1970:((NSNumber*)tmpDict[@"Time"]).doubleValue];
NSString* dateString = [NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterLongStyle];
logString = [logString stringByAppendingFormat:@"%@ %@\n",dateString, tmpDict[@"Message"]];
}
}
aslresponse_free(response);
#pragma GCC diagnostic pop
}
else {
while ((message = asl_next(response)) != NULL) {
@autoreleasepool {
NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary];
const char *key, *val;
// Get all the key/value pairs from the response message. We don't really need them all, but it's a little simpler to just get them all in C.
for (int i = 0; (key = asl_key(message, i)) != NULL; i++) {
NSString *keyString = [NSString stringWithUTF8String:(char *)key];
val = asl_get(message, key);
NSString *string = val ? [NSString stringWithUTF8String:val] : @"";
[tmpDict setObject:string forKey:keyString];
}
// Get the key/value pairs that we want and append them to the log string.
NSDate* date = [NSDate dateWithTimeIntervalSince1970:((NSNumber*)tmpDict[@"Time"]).doubleValue];
NSString* dateString = [NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterLongStyle];
logString = [logString stringByAppendingFormat:@"%@ %@\n",dateString, tmpDict[@"Message"]];
}
}
asl_free(response);
}
return [logString dataUsingEncoding:NSUTF8StringEncoding];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment