首页 > 代码库 > 如何在应用中通过邮件输入和输出数据

如何在应用中通过邮件输入和输出数据

这篇文章还可以在这里找到 英语

Load Attachments In Your App!

Load Attachments In Your App!

很多开发者都希望能够通过电子邮件分享他们的应用数据。这对用户用户之间以及设备之间的数据传输来说是一个很方便的方法--它甚至可以为你带来一些新的用户。
幸运的是,在iPhone应用开发里这是很容易实现的 -- 你只需要在Info.plist里设置几个key,并且处理几个回传函数使控制系统可以通过URL引入数据来开启应用。
我们将会在这篇教程里讲解这些是如何实现的。
我们将会由the Scary Bugs项目开始讲解。我们在简单应用教程中开始了这个项目,并且在文件分享教程中对它进行了更新。
如果你还没有这个项目,可以在这里下载。

设定你的Info.plist

我们已经为了支持邮件分享应用数据做了许多准备工作--我们已经写好代码将应用的数据保存了一个独立的副本。
所以下一步需要做的就是设定Info.plist让操作系统知道我们可以处理”Scary Bug 的文件”。具体的操作就是将你的应用注册为可以处理特定UTI,并且将系统不知道的UTI引出。
总的来说,UTI就是代表你的文件的唯一标识符,就如同”com.raywenderlich.scarybugs.sbz”一样。一些常见的文件类型,如”public.jpeg”和”public.html”,还有它们自己的内置UTI。
接下来我们会将应用注册为“可以处理我们自己生成的UTI的应用”,然后我们会将UTI的信息告诉操作系统,比如它所使用的文件扩展名以及它在email编码中所使用的MIME类型。
现在让我们来看看具体怎么操作吧!打开ScaryBugs-Info.plist,并且添加以下条目:
Info.plist Setup for App Documents
你可以从Apple的UTI手册中查到这些值都是什么含义,但是你要注意以下几点:

  • CFBundleDocumentTypes条目的意思是我们的应用支持那个/些UTI作为所有者/编辑器,在我们的应用中,即为com.raywenderlich.scarybugs.sbz UTI。

  • UTExportedTypeDeclaration条目提供了com.raywenderlich.scarybugs.sbz的信息,因为这并不是一个公用的UTI。也就是说,如果任何文件的后缀为.sbz或者它的mime类型为application/scarybugs,那么它就属于这个我们支持的文件类型。

信不信由你,设置这些keys就是我们让操作系统开始传输后缀为.sbz的应用数据所要做的全部准备工作。你可以通过给自己发送一个 sample bug来进行测试。
Emailed Bug Screenshot
如果你想打开Scary Bugs,可以按住附件。如果你这么做了,Scary Bugs就会打开,当然在这里它并不会加载,因为我们还没有加入任何的代码。这就是我们接下来要做的事情。

引入应用数据

当邮件或者其他应用想要给你的应用发送一个文件,可以通过两个方法:通过 application:didFinishLaunchingWithOptions,用 UIApplicationLaunchOptionsURLKey来传递URL,或者通过application:handleOpenURL。
为了理解这些都是在什么时候发生的,你可以看看Oliver Drobnick写的一片非常实用的讲解这些方法在什么时候调用的带图表的文章。
现在让我们开始实现吧--这会很简单,因为我们已经做了很多的准备工作。

将下列改动加入ScaryBugDoc.h:

// After @interface- (BOOL)importFromURL:(NSURL *)importURL;

将下列代码加入ScaryBugDoc.m:

// Add new function- (BOOL)importFromURL:(NSURL *)importURL {
    NSData *zippedData = [NSData dataWithContentsOfURL:importURL];    return [self importData:zippedData];    
}

下列代码加入RootViewController.h:

// After @interface- (void)handleOpenURL:(NSURL *)url;

还有将如下代码加入RootViewController.m:

// New method- (void)handleOpenURL:(NSURL *)url {
    [self.navigationController popToRootViewControllerAnimated:YES];
    ScaryBugDoc *newDoc = [[[ScaryBugDoc alloc] init] autorelease];    if ([newDoc importFromURL:url]) {
        [self addNewDoc:newDoc];       
    }}

最后,将下列代码加入ScaryBugsAppDelegate.m:

// Add at end of application:didFinishLaunchingWithOptionsNSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];if (url != nil && [url isFileURL]) {
        [rootController handleOpenURL:url];                
} // Add new method-(BOOL) application:(UIApplication *)application handleOpenURL:(NSURL *)url { 
    RootViewController *rootController = (RootViewController *) [navigationController.viewControllers objectAtIndex:0];    if (url != nil && [url isFileURL]) {
        [rootController handleOpenURL:url];                
    }     
    return YES;
 }

这些都不难理解,但是要注意几点。
首先,我们在ScaryBugDoc中加入了一个方法来将文件从URL引入。从系统中传给我们的这个URL实际上我们应用的目录中的文件的副本。所以我们用NSData来读取它,并将它传给之前写好的importData方法。
在RootViewController中,我们弹回到root view controller(除非我们是在detail view的某处),生成一个新的文件,并从给定的URL引入文件。
在ScaryBugsAppDelegate中,在能够接收到我们需要的URL的地方,如果这是一个文件URL(而不是队列字符串,我们也许以后会有专门的教程讲解),我们会通知root view controller现在可以进行引入了。
现在编译并且运行你的应用吧,如果一切顺利的话,你应该可以打开邮件的附件并且看到引入的应用的bug!
Imported Bug

输出应用数据

引入数据是比较难的部分 -- 输出数据将会简单很多。
在EditBugViewController.h中进行如下改动:

// Add to the top of the file#import <MessageUI/MessageUI.h>// Modify EditBugViewController to have two new protocols: UIActionSheetDelegate and MFMailComposeViewControllerDelegate@interface EditBugViewController : UIViewController <UITextFieldDelegate, RateViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIAlertViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate> {

然后在EditBugViewController.m中进行如下改动:

// Replace exportTapped with the following:- (void)exportTapped:(id)sender { 
    UIActionSheet *actionSheet = [[[UIActionSheet alloc]
                                   initWithTitle:@"" 
                                   delegate:self 
                                   cancelButtonTitle:@"Cancel" 
                                   destructiveButtonTitle:nil 
                                   otherButtonTitles:@"Export via File Sharing", @"Export via Email", nil] autorelease];    [actionSheet showInView:self.view];
 }// Add new methods- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {     if (buttonIndex == actionSheet.firstOtherButtonIndex + 0) {         [DSBezelActivityView newActivityViewForView:self.navigationController.navigationBar.superview withLabel:@"Exporting Bug..." width:160];   
        [_queue addOperationWithBlock: ^{
            BOOL exported = [_bugDoc exportToDiskWithForce:FALSE];            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                [DSBezelActivityView removeViewAnimated:YES];                if (!exported) {
                    UIAlertView *alertView = [[[UIAlertView alloc] 
                                               initWithTitle:@"File Already Exists!" 
                                               message:@"An exported bug with this name already exists.  Overwrite?" 
                                               delegate:self 
                                               cancelButtonTitle:@"Cancel" 
                                               otherButtonTitles:@"Overwrite", nil] autorelease];                    [alertView show];                }
            }];        }]; 
     } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 1) {         [DSBezelActivityView newActivityViewForView:self.navigationController.navigationBar.superview withLabel:@"Exporting Bug..." width:160];   
        [_queue addOperationWithBlock: ^{
            NSData *bugData = [_bugDoc exportToNSData];            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                [DSBezelActivityView removeViewAnimated:YES];                if (bugData != nil) {
                    MFMailComposeViewController *picker = [[[MFMailComposeViewController alloc] init] autorelease];                    [picker setSubject:@"My Scary Bug"];                    [picker addAttachmentData:bugData mimeType:@"application/scarybugs" fileName:[_bugDoc getExportFileName]];                    [picker setToRecipients:[NSArray array]];                    [picker setMessageBody:@"Check out this scary bug!  You‘ll need a copy of ScaryBugs to view this file, then tap and hold to open." isHTML:NO];                    [picker setMailComposeDelegate:self];                    [self presentModalViewController:picker animated:YES];                    
                }             }];        }]; 
     } }- (void)mailComposeController:(MFMailComposeViewController *)controller
		  didFinishWithResult:(MFMailComposeResult)result
						error:(NSError *)error {
    [self dismissModalViewControllerAnimated:YES];}

在这里我们改变了输出按键弹出窗口询问用户希望通过之前一样的文件分享还是电子邮件来输出。
如果用户选择通过邮箱分享文件,我们会使用MFMailComposeViewController来生成一个邮件信息,并且加入含有bug数据的附件。是不是很简单?
我们开始测试前的最后一件事情:右键单击Frameworks,选择”AddExisting Framework…”,并从下拉列表中选择”MessageUI.framework”。
下面就编译运行你的应用吧,你应该已经可以通过邮件自动的从应用输出一个“Scary Bug”了!
Emailing Bug

来点好玩的!

如果你已经做了这么多,何不来点更好玩的?
通过应用来生成一个Scary Bug,然后把它用邮件发送给我,邮箱地址在上图的截图中,我会把它加入这片教程!让我们看看我们都制造了什么恐怖的生物!:]
更新: 这是一个由Alex Hedley发来的不怎么恐怖bug!:]

何去何从?

这里 就是我们这个教程系列到目前为止的代码。
我的计划是Scary Bugs应用就这么多了,但是谁知道呢,也许我会再增加点什么。
同时,如果你有什么问题,评论,或者你想分享你觉得什么bug最恐怖,请让我知道!:]

另外一篇文章也不错:

http://blog.spritebandits.com/2011/12/14/importing-csv-data-file-into-an-ios-app-via-email-attachment/
http://blog.spritebandits.com/2011/12/21/importing-csv-data-file-into-an-ios-app-via-email-attachment-part-2/