MFMailComposeViewController canSendMail始终返回false

时间:2019-01-24 15:25:58

标签: ios objective-c iphone mfmailcomposeviewcontroller ios12

我正在尝试在iOS应用程序上使用MFMailComposeViewController发送电子邮件。

我有一个在iPhone默认邮件应用程序中配置的Gmail帐户。但是每当我尝试发送电子邮件时,我都会得到MFMailComposeViewController canSendMail为假,因此,我的代码无法使用给定的抄送和附件打开邮件应用程序

#import <MessageUI/MessageUI.h>
#import "RNMail.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>

@implementation RNMail
{
    NSMutableDictionary *_callbacks;
}

- (instancetype)init
{
    if ((self = [super init])) {
        _callbacks = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (dispatch_queue_t)methodQueue
{
    return dispatch_get_main_queue();
}

+ (BOOL)requiresMainQueueSetup
{
    return YES;
}

RCT_EXPORT_MODULE()

RCT_EXPORT_METHOD(mail:(NSDictionary *)options
                  callback: (RCTResponseSenderBlock)callback)
{
    if ([MFMailComposeViewController canSendMail])
    {
        MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
        mail.mailComposeDelegate = self;
        _callbacks[RCTKeyForInstance(mail)] = callback;

        if (options[@"subject"]){
            NSString *subject = [RCTConvert NSString:options[@"subject"]];
            [mail setSubject:subject];
        }

        bool *isHTML = NO;

        if (options[@"isHTML"]){
            isHTML = [options[@"isHTML"] boolValue];
        }

        if (options[@"body"]){
            NSString *body = [RCTConvert NSString:options[@"body"]];
            [mail setMessageBody:body isHTML:isHTML];
        }

        if (options[@"recipients"]){
            NSArray *recipients = [RCTConvert NSArray:options[@"recipients"]];
            [mail setToRecipients:recipients];
        }

        if (options[@"ccRecipients"]){
            NSArray *ccRecipients = [RCTConvert NSArray:options[@"ccRecipients"]];
            [mail setCcRecipients:ccRecipients];
        }

        if (options[@"bccRecipients"]){
            NSArray *bccRecipients = [RCTConvert NSArray:options[@"bccRecipients"]];
            [mail setBccRecipients:bccRecipients];
        }

        if (options[@"attachment"] && options[@"attachment"][@"path"] && options[@"attachment"][@"type"]){
            NSString *attachmentPath = [RCTConvert NSString:options[@"attachment"][@"path"]];
            NSString *attachmentType = [RCTConvert NSString:options[@"attachment"][@"type"]];
            NSString *attachmentName = [RCTConvert NSString:options[@"attachment"][@"name"]];

            // Set default filename if not specificed
            if (!attachmentName) {
                attachmentName = [[attachmentPath lastPathComponent] stringByDeletingPathExtension];
            }

            // Get the resource path and read the file using NSData
            NSData *fileData = [NSData dataWithContentsOfFile:attachmentPath];

            // Determine the MIME type
            NSString *mimeType;

            /*
             * Add additional mime types and PR if necessary. Find the list
             * of supported formats at http://www.iana.org/assignments/media-types/media-types.xhtml
             */
            if ([attachmentType isEqualToString:@"jpg"]) {
                mimeType = @"image/jpeg";
            } else if ([attachmentType isEqualToString:@"png"]) {
                mimeType = @"image/png";
            } else if ([attachmentType isEqualToString:@"doc"]) {
                mimeType = @"application/msword";
            } else if ([attachmentType isEqualToString:@"ppt"]) {
                mimeType = @"application/vnd.ms-powerpoint";
            } else if ([attachmentType isEqualToString:@"html"]) {
                mimeType = @"text/html";
            } else if ([attachmentType isEqualToString:@"csv"]) {
                mimeType = @"text/csv";
            } else if ([attachmentType isEqualToString:@"pdf"]) {
                mimeType = @"application/pdf";
            } else if ([attachmentType isEqualToString:@"vcard"]) {
                mimeType = @"text/vcard";
            } else if ([attachmentType isEqualToString:@"json"]) {
                mimeType = @"application/json";
            } else if ([attachmentType isEqualToString:@"zip"]) {
                mimeType = @"application/zip";
            } else if ([attachmentType isEqualToString:@"text"]) {
                mimeType = @"text/*";
            } else if ([attachmentType isEqualToString:@"mp3"]) {
                mimeType = @"audio/mpeg";
            } else if ([attachmentType isEqualToString:@"wav"]) {
                mimeType = @"audio/wav";
            } else if ([attachmentType isEqualToString:@"aiff"]) {
                mimeType = @"audio/aiff";
            } else if ([attachmentType isEqualToString:@"flac"]) {
                mimeType = @"audio/flac";
            } else if ([attachmentType isEqualToString:@"ogg"]) {
                mimeType = @"audio/ogg";
            } else if ([attachmentType isEqualToString:@"xls"]) {
                mimeType = @"application/vnd.ms-excel";
            }

            // Add attachment
            [mail addAttachmentData:fileData mimeType:mimeType fileName:attachmentName];
        }

        UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];

        while (root.presentedViewController) {
            root = root.presentedViewController;
        }
        [root presentViewController:mail animated:YES completion:nil];
    } else {
        callback(@[@"not_available"]);
    }
}

#pragma mark MFMailComposeViewControllerDelegate Methods

- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
    NSString *key = RCTKeyForInstance(controller);
    RCTResponseSenderBlock callback = _callbacks[key];
    if (callback) {
        switch (result) {
            case MFMailComposeResultSent:
                callback(@[[NSNull null] , @"sent"]);
                break;
            case MFMailComposeResultSaved:
                callback(@[[NSNull null] , @"saved"]);
                break;
            case MFMailComposeResultCancelled:
                callback(@[[NSNull null] , @"cancelled"]);
                break;
            case MFMailComposeResultFailed:
                callback(@[@"failed"]);
                break;
            default:
                callback(@[@"error"]);
                break;
        }
        [_callbacks removeObjectForKey:key];
    } else {
        RCTLogWarn(@"No callback registered for mail: %@", controller.title);
    }
    UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    while (ctrl.presentedViewController && ctrl != controller) {
        ctrl = ctrl.presentedViewController;
    }
    [ctrl dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark Private

static NSString *RCTKeyForInstance(id instance)
{
    return [NSString stringWithFormat:@"%p", instance];
}

@end

iOS版本:12.1.2

我想知道MFMailComposeViewController上是否有任何最近的变化,这是否导致了这种情况?

我已经配置了邮件帐户,并且可以正常工作。因此,它不是已经发布的任何问题的重复

1 个答案:

答案 0 :(得分:2)

MFMailComposeViewController直接链接到Apple的邮件应用程序。只有在安装和配置了Apple的邮件应用程序后,它才会返回true。

如果要打开Gmail(或已安装的任何默认应用),则需要使用mailto://方案

这是我执行mailto部分的功能-包括从html到纯文本的荒谬的简单转换!

请注意mailto://不支持附件或html内容。

/// Send email using mailto
/// - Parameters:
///   - to: array of email addresses
///   - subject: subject
///   - body: body
///   - isHtml: isHtml (only <br/> and <br /> are supported)
/// - Returns: true if sent
    func sendByURL(to:[String],subject:String,body:String, isHtml:Bool) -> Bool {
        
        
        var txtBody = body
        if isHtml {
            txtBody = body.replacingOccurrences(of: "<br />", with: "\n")
            txtBody = txtBody.replacingOccurrences(of: "<br/>", with: "\n")
            if txtBody.contains("/>") {
                print("Can't send html email with url interface")
                return false
            }
        }

        let toJoined = to.joined(separator: ",")
        guard var feedbackUrl = URLComponents.init(string: "mailto:\(toJoined)") else {
            return false
        }
                 

        var queryItems: [URLQueryItem] = []
        queryItems.append(URLQueryItem.init(name: "SUBJECT", value: subject))
        queryItems.append(URLQueryItem.init(name: "BODY",
                                            value: txtBody))
        feedbackUrl.queryItems = queryItems
        
        if let url = feedbackUrl.url {
//            This is probably an unnecessary check
//            You do need to add 'mailto' to your LSApplicationQuerySchemes for the check to be allowed
//            <key>LSApplicationQueriesSchemes</key>
//            <array>
//                <string>mailto</string>
//            </array>
            if UIApplication.shared.canOpenURL(url){
                UIApplication.shared.open(url)
                return true
            }
        }
        
        return false
     
    }