2011-10-19 46 views
6

Tôi đang viết một ứng dụng iPhone yêu cầu tôi gửi một tệp đính kèm e-mail theo lập trình. Tệp đính kèm là tệp csv mà tôi tạo thông qua mã. Sau đó tôi đính kèm tệp vào email và tệp đính kèm hiển thị trên điện thoại. Tuy nhiên, khi tôi gửi email cho chính mình, tệp đính kèm không xuất hiện trong e-mail. Đây là mã tôi đang sử dụng.Gửi tệp đính kèm iphone qua email theo chương trình

[self exportData]; 

if ([MFMailComposeViewController canSendMail]) 
{ 
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"expenses" ofType:@"csv"]; 
    NSData *myData = [NSData dataWithContentsOfFile:filePath]; 

    MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init]; 

    mailer.mailComposeDelegate = self; 

    [mailer setSubject:@"Vehicle Expenses from myConsultant"]; 

    NSString *emailBody = @""; 
    [mailer setMessageBody:emailBody isHTML:NO]; 

    [mailer addAttachmentData:myData mimeType:@"text/plain" fileName:@"expenses"]; 

    [self presentModalViewController:mailer animated:YES]; 

    [mailer release]; 
} 
else 
{ 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failure" 
                message:@"Your device doesn't support the composer sheet" 
                delegate:nil 
              cancelButtonTitle:@"OK" 
              otherButtonTitles:nil]; 
    [alert show]; 
    [alert release]; 
} 
} 
- (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 dismissModalViewControllerAnimated:YES]; 

Đang được tạo thành công- Tôi đã kiểm tra trong các tệp trình mô phỏng.

- (void) exportData 
{ 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
    NSString *documentsDir = [paths objectAtIndex:0]; 
    NSString *root = [documentsDir stringByAppendingPathComponent:@"expenses.csv"]; 
    NSString *[email protected]"Date,Purpose,Start Odometer,End Odometer, Total Driven, Fees, "; 
    for(int i = 0; i < expenses.count; i++){ 
     VehicleExpense *tempExpense = [expenses objectAtIndex:i]; 
     temp = [temp stringByAppendingString:tempExpense.date]; 
     temp = [temp stringByAppendingString:@", "]; 
     temp = [temp stringByAppendingString:tempExpense.purpose]; 
     temp = [temp stringByAppendingString:@", "]; 
     temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.start_mile]]; 
     temp = [temp stringByAppendingString:@", "]; 
     temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.end_mile]]; 
     temp = [temp stringByAppendingString:@", "]; 
     temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.distance]]; 
     temp = [temp stringByAppendingString:@", "]; 
     temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.fees]]; 
     temp = [temp stringByAppendingString:@", "]; 
    } 
    [temp writeToFile:root atomically:YES encoding:NSUTF8StringEncoding error:NULL]; 
    NSLog(@"got here in export data--- %@", documentsDir); 

} 
+1

Hãy thử đăng nhập myData để xem nó có không trả về không. – EmilioPelaez

+0

Nó là null ... làm thế nào để tôi có được tập tin? Tôi đang chỉnh sửa bài đăng gốc của mình để hiển thị nơi tôi tạo tệp. – coder

+1

Có vẻ như 'filePath = [[NSBundle mainBundle] pathForResource: @" costs "ofType: @" csv "];' không nhận được đường dẫn của tệp bạn đang tìm kiếm. Nếu tôi đúng, phương thức đó chỉ nhận được tài nguyên bên trong thư mục .app của bạn. Tôi khuyên bạn nên lấy đường dẫn giống như cách bạn làm trong phương thức exportData. – EmilioPelaez

Trả lời

11

thử [mailer addAttachmentData:myData mimeType:@"text/csv" fileName:@"expenses.csv"];

Edit: Đây là mã Tôi đang sử dụng trong ứng dụng của tôi:

- (IBAction) ExportData:(id)sender 
{  
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:kExportFileName]; 

    self.timeRecords = [[NSMutableArray alloc] init]; 
    for (int i=0; i< [self.selectedTimeEntries count]; i++) 
     for (int j=0; j<[[self.selectedTimeEntries objectAtIndex:i] count]; j++) 
      if ([[self.selectedTimeEntries objectAtIndex:i] objectAtIndex:j] == [NSNumber numberWithBool:YES]) 
       [self.timeRecords addObject:[self timeEntriesForDay:[self.uniqueArray objectAtIndex:i] forIndex:j]]; 

    if(!([self.timeRecords count]!=0)) 
    { 
     UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"There are no time entries selected!" message:@"Please select at least one time entry before proceeding" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
     [alert show]; 
     [alert release];   
     return; 
    } 
    NSMutableString *csvLine; 
    NSError *err = nil; 
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; 
    [dateFormatter setDateFormat:@"yyyy-MM-dd"]; 
    NSString *dateString = nil; 
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; 
    [numberFormatter setPositiveFormat:@"###0.##"]; 
    NSString *formattedNumberString = nil; 

    if(![[NSFileManager defaultManager] fileExistsAtPath:filePath])   
    { 
     [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]; 
    } 

    for (timeEntries *timeEntry in self.timeRecords) { 
     csvLine = [NSMutableString stringWithString:timeEntry.client]; 
     [csvLine appendString:@","]; 
     [csvLine appendString:timeEntry.category]; 
     [csvLine appendString:@","]; 
     [csvLine appendString:timeEntry.task]; 
     [csvLine appendString:@","]; 
     dateString = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:timeEntry.date]]; 
     [csvLine appendString:dateString]; 
     [csvLine appendString:@","]; 
     formattedNumberString = [numberFormatter stringFromNumber:timeEntry.duration]; 
     [csvLine appendString:formattedNumberString]; 
     [csvLine appendString:@","]; 
     [csvLine appendString:timeEntry.description]; 
     [csvLine appendString:@"\n"]; 

     if([[NSFileManager defaultManager] fileExistsAtPath:filePath])   
     {  
      NSString *oldFile = [[NSString alloc] initWithContentsOfFile:filePath]; 
      [csvLine insertString:oldFile atIndex:0]; 
      BOOL success =[csvLine writeToFile:filePath atomically:NO encoding:NSUTF8StringEncoding error:&err]; 
      if(success){ 

      } 
      [oldFile release]; 
     } 
    } 
    if (!appDelegate.shouldSendCSV) { 
    self.csvText = csvLine; 
    } 
    if([[NSFileManager defaultManager] fileExistsAtPath:filePath])   
    { 
     [self emailExport:filePath]; 
    } 
    self.selectedTimeEntries =nil; 
    self.navigationController.toolbarHidden = NO; 
} 


- (void)emailExport:(NSString *)filePath 
{ 
    NSLog(@"Should send CSV = %@", [NSNumber numberWithBool:appDelegate.shouldSendCSV]); 
    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init]; 
    picker.mailComposeDelegate = self; 

    // Set the subject of email 
    [picker setSubject:@"My Billed Time Export"]; 

    // Add email addresses 
    // Notice three sections: "to" "cc" and "bcc" 

    NSString *valueForEmail = [[NSUserDefaults standardUserDefaults] stringForKey:@"emailEntry"]; 
    NSString *valueForCCEmail = [[NSUserDefaults standardUserDefaults] stringForKey:@"ccEmailEntry"]; 
    if(valueForEmail == nil || [valueForEmail isEqualToString:@""]) 
    { 
     UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"Please set an email address before sending a time entry!" message:@"You can change this address later from the settings menu of the application!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
     [alert show]; 
     [alert release];   

     return; 
    } 
    else { 
     [picker setToRecipients:[NSArray arrayWithObjects:valueForEmail, nil]]; 
    } 

    if(valueForCCEmail != nil || ![valueForCCEmail isEqualToString:@""]) 
    { 
     [picker setCcRecipients:[NSArray arrayWithObjects:valueForCCEmail, nil]]; 
    } 

    // Fill out the email body text 
    NSString *emailBody = @"My Billed Time Export File."; 

    // This is not an HTML formatted email 
    [picker setMessageBody:emailBody isHTML:NO]; 

    if (appDelegate.shouldSendCSV) { 

    // Create NSData object from file 
    NSData *exportFileData = [NSData dataWithContentsOfFile:filePath]; 

    // Attach image data to the email 
    [picker addAttachmentData:exportFileData mimeType:@"text/csv" fileName:@"MyFile.csv"]; 
    } else { 
     [picker setMessageBody:self.csvText isHTML:NO]; 
    } 
    // Show email view 
    [self presentModalViewController:picker animated:YES]; 

    // Release picker 
    [picker release]; 
} 
+0

Tôi chỉ thử điều đó và nó không giúp được gì. – coder

0

Vấn đề này đã được rằng tôi đã không nhìn vào thích hợp đặt cho tập tin. Cảm ơn @EmilioPalesz.

Dưới đây là đoạn code tôi cần:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
NSString *documentsDir = [paths objectAtIndex:0]; 
NSString *root = [documentsDir stringByAppendingPathComponent:@"expenses.csv"] 

NSData *myData = [NSData dataWithContentsOfFile:root]; 
2

Danut Pralea 's answer là rất tốt, tuy nhiên các mã có vẻ là quá dài đối với một ai đó tìm kiếm một cách đơn giản -gửi tập tin đính kèm qua email programatically .

Các Gist

Tôi tỉa câu trả lời của mình để đưa ra chỉ các bit quan trọng, cũng như refactored nó như vậy:

MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init]; 
mailComposer.mailComposeDelegate = self; 

mailComposer.subject = @"Sample subject"; 

mailComposer.toRecipients = @[@"[email protected]", @"[email protected]", ...]; 
mailComposer.ccRecipients = @[@"[email protected]", @"[email protected]", ...]; 

[mailComposer setMessageBody:@"Sample body" isHTML:NO]; 

NSData *fileData = [NSData dataWithContentsOfFile:filePath]; 
[mailComposer addAttachmentData:fileData 
         mimeType:mimeType 
         fileName:fileName]; 

[self presentViewController:mailComposer animated:YES completion:nil]; 

Đó là về cơ bản các ý chính của nó, điều này là đủ như nó là. Ví dụ: nếu bạn đặt mã này vào hành động của nút, nó sẽ hiển thị một màn hình soạn email với các trường tương ứng được điền sẵn, cũng như có tệp bạn muốn đính kèm vào email.

Đọc thêm

Khung

Các MFMailComposeViewController là dưới khung MessageUI, vì vậy sử dụng nó, nhập khẩu (nếu bạn đã chưa xong) Khung như vậy:

#import <MessageUI/MessageUI.h> 

Kiểm tra khả năng thư

Bây giờ, khi bạn chạy mã nguồn và bạn chưa thiết lập tài khoản thư trên thiết bị của mình, (không chắc chắn hành vi là gì trên trình mô phỏng), mã này sẽ làm hỏng ứng dụng của bạn. Dường như nếu tài khoản thư chưa được thiết lập, việc thực hiện [[MFMailComposeViewController alloc] init] sẽ vẫn dẫn đến số mailComposer là số không, causing the crash.Khi answer trong câu hỏi liên quan khẳng định:

Bạn nên kiểm tra là MFMailComposeViewController có thể gửi email của bạn ngay trước khi gửi

Bạn có thể làm điều này bằng cách sử dụng phương pháp canSendMail như vậy:

if (![MFMailComposeViewController canSendMail]) { 
    [self openCannotSendMailDialog]; 
    return; 
} 

Bạn có thể đặt quyền này trước khi thực hiện [[MFMailComposeViewController alloc] init] để bạn có thể thông báo cho người dùng ngay lập tức.

Xử lý cannotSendMail

Nếu canSendMail lợi nhuận sai sự thật, theo Apple Dev Documents, có nghĩa rằng thiết bị không được cấu hình để gửi thư. Điều này could mean có thể người dùng chưa thiết lập tài khoản Thư của họ. Để giúp người dùng với điều đó, bạn có thể cung cấp cho open the Mail app và thiết lập tài khoản của họ. Bạn có thể làm điều này như sau:

NSURL *mailUrl = [NSURL URLWithString:@"message://"]; 
if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) { 
    [[UIApplication sharedApplication] openURL:mailUrl]; 
} 

Bạn có thể sau đó thực hiện openCannotSendMailDialog như vậy:

- (void)openCannotSendMailDialog 
{ 
    UIAlertController *alert = 
     [UIAlertController alertControllerWithTitle:@"Error" 
              message:@"Cannot send mail." 
           preferredStyle:UIAlertControllerStyleAlert]; 

    NSURL *mailUrl = [NSURL URLWithString:@"message://"]; 
    if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) { 
     [alert addAction: 
     [UIAlertAction actionWithTitle:@"Open Mail" 
            style:UIAlertActionStyleDefault 
           handler:^(UIAlertAction * _Nonnull action) { 
      [[UIApplication sharedApplication] openURL:mailUrl]; 
     }]]; 

     [alert addAction: 
     [UIAlertAction actionWithTitle:@"Cancel" 
            style:UIAlertActionStyleCancel 
           handler:^(UIAlertAction * _Nonnull action) { 

     }]]; 

    } else { 
     [alert addAction: 
     [UIAlertAction actionWithTitle:@"OK" 
            style:UIAlertActionStyleCancel 
           handler:^(UIAlertAction * _Nonnull action) { 

     }]]; 

    } 

    [self presentViewController:alert animated:YES completion:nil]; 
} 

Mime loại

Nếu như tôi, bạn quên/không chắc chắn mà mimeType sử dụng , here là tài nguyên bạn có thể sử dụng. Có lẽ hầu hết, text/plain là đủ, nếu tệp bạn đang đính kèm chỉ là văn bản thuần túy hoặc image/jpeg/image/png cho hình ảnh.

Đại biểu

Như bạn có thể nhận thấy, Xcode ném chúng tôi một lời cảnh báo về dòng sau:

mailComposer.mailComposeDelegate = self; 

Điều này là do chúng ta chưa thiết lập ourself để phù hợp với các giao thức thích hợp và thực hiện phương thức ủy nhiệm của nó. Nếu bạn muốn nhận sự kiện dù thư đã bị hủy bỏ, lưu, gửi hoặc thậm chí thất bại trong việc gửi, bạn cần phải thiết lập lớp học của bạn để phù hợp với các giao thức MFMailComposeViewControllerDelegate, và xử lý các following events:

  • MFMailComposeResultSent
  • MFMailComposeResultSaved
  • MFMailComposeResultCancelled
  • MFMailComposeResultFailed

Theo Apple Dev Documents (tôi nhấn mạnh):

Bộ điều khiển chế độ xem thư soạn không bị loại bỏ tự động. Khi người dùng chạm vào các nút để gửi email hoặc hủy giao diện, trình điều khiển chế độ xem thư soạn thư sẽ gọi phương thức mailComposeController:didFinishWithResult:error: của người được ủy quyền. Việc triển khai phương pháp đó của bạn phải loại bỏ trình điều khiển chế độ xem một cách rõ ràng.

Với điều này trong tâm trí, sau đó chúng tôi có thể thực hiện các phương pháp đại biểu như vậy:

- (void)mailComposeController:(MFMailComposeViewController *)controller 
      didFinishWithResult:(MFMailComposeResult)result 
         error:(NSError *)error 
{ 
    switch (result) { 
     case MFMailComposeResultSent: 
      // Mail was sent 
      break; 
     case MFMailComposeResultSaved: 
      // Mail was saved as draft 
      break; 
     case MFMailComposeResultCancelled: 
      // Mail composition was cancelled 
      break; 
     case MFMailComposeResultFailed: 
      // 
      break; 
     default: 
      // 
      break; 
    } 

    // Dismiss the mail compose view controller. 
    [controller dismissViewControllerAnimated:YES completion:nil]; 
} 

Kết luận

Mã cuối cùng có thể trông giống như vậy:

- (void)openMailComposerWithSubject:(NSString *)subject 
        toRecipientArray:(NSArray *)toRecipientArray 
        ccRecipientArray:(NSArray *)ccRecipientArray 
         messageBody:(NSString *)messageBody 
        isMessageBodyHTML:(BOOL)isHTML 
       attachingFileOnPath:(NSString)filePath 
          mimeType:(NSString *)mimeType 
{ 
    if (![MFMailComposeViewController canSendMail]) { 
     [self openCannotSendMailDialog]; 
     return; 
    } 

    MFMailComposeViewController *mailComposer = 
     [[MFMailComposeViewController alloc] init]; 
    mailComposer.mailComposeDelegate = self; 

    mailComposer.subject = subject; 

    mailComposer.toRecipients = toRecipientArray; 
    mailComposer.ccRecipients = ccRecipientArray; 

    [mailComposer setMessageBody:messageBody isHTML:isHTML]; 

    NSData *fileData = [NSData dataWithContentsOfFile:filePath]; 
    NSString *fileName = filePath.lastPathComponent; 
    [mailComposer addAttachmentData:fileData 
          mimeType:mimeType 
          fileName:fileName]; 

    [self presentViewController:mailComposer animated:YES completion:nil]; 
} 

- (void)openCannotSendMailDialog 
{ 
    UIAlertController *alert = 
     [UIAlertController alertControllerWithTitle:@"Error" 
              message:@"Cannot send mail." 
           preferredStyle:UIAlertControllerStyleAlert]; 

    NSURL *mailUrl = [NSURL URLWithString:@"message://"]; 
    if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) { 
     [alert addAction: 
     [UIAlertAction actionWithTitle:@"Open Mail" 
            style:UIAlertActionStyleDefault 
           handler:^(UIAlertAction * _Nonnull action) { 
      [[UIApplication sharedApplication] openURL:mailUrl]; 
     }]]; 

     [alert addAction: 
     [UIAlertAction actionWithTitle:@"Cancel" 
            style:UIAlertActionStyleCancel 
           handler:^(UIAlertAction * _Nonnull action) { 

     }]]; 

    } else { 
     [alert addAction: 
     [UIAlertAction actionWithTitle:@"OK" 
            style:UIAlertActionStyleCancel 
           handler:^(UIAlertAction * _Nonnull action) { 

     }]]; 

    } 

    [self presentViewController:alert animated:YES completion:nil]; 
} 

- (void)mailComposeController:(MFMailComposeViewController *)controller 
      didFinishWithResult:(MFMailComposeResult)result 
         error:(NSError *)error 
{ 
    NSString *message; 
    switch (result) { 
     case MFMailComposeResultSent: 
      message = @"Mail was sent."; 
      break; 
     case MFMailComposeResultSaved: 
      message = @"Mail was saved as draft."; 
      break; 
     case MFMailComposeResultCancelled: 
      message = @"Mail composition was cancelled."; 
      break; 
     case MFMailComposeResultFailed: 
      message = @"Mail sending failed."; 
      break; 
     default: 
      // 
      break; 
    } 

    // Dismiss the mail compose view controller. 
    [controller dismissViewControllerAnimated:YES completion:^{ 
     if (message) { 
      UIAlertController *alert = 
       [UIAlertController alertControllerWithTitle:@"Confirmation" 
                message:message 
             preferredStyle:UIAlertControllerStyleAlert]; 

      [alert addAction: 
      [UIAlertAction actionWithTitle:@"OK" 
             style:UIAlertActionStyleCancel 
            handler:^(UIAlertAction * _Nonnull action) { 

      }]]; 

      [self presentViewController:alert animated:YES completion:nil]; 
     } 
    }]; 
} 

Với thao tác nút trông giống như:

- (IBAction)mailButtonTapped:(id)sender 
{ 
    NSString *reportFilePath = ... 
    [self openMailComposerWithSubject:@"Report Files" 
        toRecipientArray:mainReportRecipientArray 
        ccRecipientArray:subReportRecipientArray 
          messageBody:@"I have attached report files in this email" 
        isMessageBodyHTML:NO 
        attachingFileOnPath:reportFilePath 
          mimeType:@"text/plain"];  
} 

tôi loại đi quá nhiệt tình ở đây, nhưng bạn có thể, với một hạt muối, lấy và sử dụng đoạn code tôi được đăng ở đây. Tất nhiên có một nhu cầu để thích nghi nó với yêu cầu của bạn, nhưng đó là vào bạn. (Tôi cũng đã sửa đổi câu trả lời này từ mã nguồn đang hoạt động của mình, vì vậy có thể có lỗi ở đâu đó, vui lòng bình luận nếu bạn tìm thấy một :))

+0

@Shebuka Trong bản chỉnh sửa được đề xuất của bạn, nếu mailComposer là bản được loại bỏ, không nên là '[controller dismissView ...' thay vì '[self dismissView ...'? – Keale

+1

có, và tôi đang sử dụng 'bộ điều khiển', nhưng tài liệu chính thức của táo sử dụng' tự ... https://developer.apple.com/documentation/messageui/mfmailcomposeviewcontroller?language=objc Liệt kê 3 – Shebuka

+0

@ Shebuka Vâng, đó là kỳ dị. Tôi đã mở liên kết và chắc chắn tôi đã thấy mã mẫu bằng cách sử dụng '[tự bỏ qua ...'. Phiên bản [Swift] (https://developer.apple.com/documentation/messageui/mfmailcomposeviewcontroller) sử dụng 'controller.dismiss ...' mặc dù. – Keale

Các vấn đề liên quan