Episode #62

Mailing Logs

10 minutes
Published on April 11, 2013

This video is only available to subscribers. Get access to this video and 572 others.

In this episode we continue with our example from last week's logging episode, and discuss how you can retrieve your logs out in the field. We use a pod called SSZipArchive to zip up the files as well as MFMailComposeViewController to enable testers to send us detailed logs of what is happening in the app.

Episode Links

Zipping up the logs

We need to find the directory for the logs first, so we create a couple of helper methods:

- (NSString *)cachesDirectory {
    return NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
}

- (NSString *)logsDirectory {
    return [[self cachesDirectory] stringByAppendingPathComponent:@"Logs"];
}

With the directory well known, we can now zip up all of the text files in the directory:

- (NSData *)zipLogs {
    NSString *logsDir = [self logsDirectory];
    NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDir error:nil];
    NSPredicate *textFilePredicate = [NSPredicate predicateWithFormat:@"self ENDSWITH '.txt'"];
    files = [files filteredArrayUsingPredicate:textFilePredicate];

    NSString *logZipPath = [logsDir stringByAppendingPathComponent:@"logs.zip"];
    if ([[NSFileManager defaultManager] fileExistsAtPath:logZipPath]) {
        [[NSFileManager defaultManager] removeItemAtPath:logZipPath error:nil];
    }

    NSMutableArray *inputFiles = [NSMutableArray array];
    for (NSString *file in files) {
        [inputFiles addObject:[logsDir stringByAppendingPathComponent:file]];
    }

    [SSZipArchive createZipFileAtPath:logZipPath withFilesAtPaths:inputFiles];
    NSData *zipData = [NSData dataWithContentsOfFile:logZipPath];
    [[NSFileManager defaultManager] removeItemAtPath:logZipPath error:nil];
    return zipData;
}

Sending the email with an attachment

We first need to check if the device can even send mail. This is important because not all devices have mail accounts set up. Once we've verified this, we can zip up the logs asynchronously, set up the default values for the email, and present the composer.

- (IBAction)mailLogs:(id)sender {
    if (![MFMailComposeViewController canSendMail]) {
        [[[UIAlertView alloc] initWithTitle:@"Can't send email"
                                    message:@"Please set up your mail account first"
                                   delegate:nil
                          cancelButtonTitle:@"OK"
                          otherButtonTitles:nil] show];
        return;
    }

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSData *zipFileData = [self zipLogs];

        dispatch_async(dispatch_get_main_queue(), ^{
            MFMailComposeViewController *mailVC = [[MFMailComposeViewController alloc] init];
            [mailVC setSubject:@"Application Logs"];
            [mailVC setToRecipients:@[@"email@example.com"]];
            [mailVC setMessageBody:@"Please find the attached logs" isHTML:NO];
            [mailVC addAttachmentData:zipFileData
                             mimeType:@"application/zip"
                             fileName:@"logs.zip"];

            [mailVC setMailComposeDelegate:self];

            [self presentViewController:mailVC animated:YES completion:nil];
        });
    });
}