Вскрытие Почты.приложение из внешнего приложения с вложением и темой


Я хотел бы открыть почту.приложение и укажите тему и файл для прикрепления. Я могу сделать и то и другое независимо, но не то и другое.

Чтобы задать тему, я могу просто сформировать mailto: string и nsworkspace openURL.

Для установки приложения я могу использовать

[[NSWorkspace sharedWorkspace] openFile:resolvedPath withApplication:@"Mail"];

Я не знаю эквивалента MFMailComposeViewController iOS для Mac. Какие у меня варианты?

3 3

3 ответа:

Изменить: исходный код, на который он ссылается, был удален, поэтому я скопировал некоторые из них в этот ответ.

Вы можете использовать AppleScript (или Apple Events) для управления почтой.апп. Это имеет то преимущество, что нет ограничений на размер вложений, которые вы можете передавать, и позволяет избежать создания огромных URL-адресов.

В нашем программном обеспечении мы используем следующее для компиляции подходящего AppleScript:

- (NSAppleScript *)script
{
  if (script)
    return script;

  NSDictionary *errorInfo = nil;

  /* This AppleScript code is here to communicate with Mail.app */
  NSString *ourScript =
    @"on build_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                 attachfiles)\n"
    @"  tell application \"Mail\"\n"
    @"    set mailversion to version as string\n"
    @"    set msg to make new outgoing message at beginning of"
    @"      outgoing messages\n"
    @"    tell msg\n"
    @"      set the subject to subj\n"
    @"      set the content to msgbody\n"
    @"      if (sendr is not equal to \"\") then\n"
    @"        set sender to sendr\n"
    @"      end if\n"
    @"      repeat with rec in recip\n"
    @"        make new to recipient at end of to recipients with properties {"
    @"          name: |name| of rec, address: |address| of rec }\n"
    @"      end repeat\n"
    @"      repeat with rec in ccrec\n"
    @"        make new to recipient at end of cc recipients with properties {"
    @"          name: |name| of rec, address: |address| of rec }\n"
    @"      end repeat\n"
    @"      repeat with rec in bccrec\n"
    @"        make new to recipient at end of bcc recipients with properties {"
    @"          name: |name| of rec, address: |address| of rec }\n"
    @"      end repeat\n"
    @"      tell content\n"
    @"        repeat with attch in attachfiles\n"
    @"          make new attachment with properties { file name: attch } at "
    @"            after the last paragraph\n"
    @"        end repeat\n"
    @"      end tell\n"
    @"    end tell\n"
    @"    return msg\n"
    @"  end tell\n"
    @"end build_message\n"
    @"\n"
    @"on deliver_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                   attachfiles)\n"
    @"  set msg to build_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                           attachfiles)\n"
    @"  tell application \"Mail\"\n"
    @"    send msg\n"
    @"  end tell\n"
    @"end deliver_message\n"
    @"\n"
    @"on construct_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                     attachfiles)\n"
    @"  set msg to build_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                           attachfiles)\n"
    @"  tell application \"Mail\"\n"
    @"    tell msg\n"
    @"      set visible to true\n"
    @"      activate\n"
    @"    end tell\n"
    @"  end tell\n"
    @"end construct_message\n";

  script = [[NSAppleScript alloc] initWithSource:ourScript];

  if (![script compileAndReturnError:&errorInfo]) {
    NSLog (@"Unable to compile script: %@", errorInfo);
    [script release];
    script = nil;
  }

  return script;
}

Затем вы можете запускать функции в скрипте, используя код, подобный это

- (NSAppleEventDescriptor *)descriptorForThisProcess
{
  ProcessSerialNumber thePSN = { 0, kCurrentProcess };

  return [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber
                            bytes:&thePSN
                               length:sizeof (thePSN)];
}

- (BOOL)doHandler:(NSString *)handler
       forMessage:(NSAttributedString *)messageBody
      headers:(NSDictionary *)messageHeaders
{
  NSMutableString *body = [NSMutableString string];
  NSDictionary *errorInfo = nil;
  NSAppleEventDescriptor *target = [self descriptorForThisProcess];
  NSAppleEventDescriptor *event
    = [NSAppleEventDescriptor appleEventWithEventClass:'ascr'
                           eventID:kASSubroutineEvent
                      targetDescriptor:target
                          returnID:kAutoGenerateReturnID
                     transactionID:kAnyTransactionID];
  NSAppleEventDescriptor *params = [NSAppleEventDescriptor listDescriptor];
  NSAppleEventDescriptor *files = [NSAppleEventDescriptor listDescriptor];
  NSString *tmpdir = NSTemporaryDirectory ();
  NSString *attachtmp = nil;
  NSFileManager *fileManager = [NSFileManager defaultManager];
  NSString *sendr = @"", *subj = @"";
  NSAppleEventDescriptor *recip
    = [self recipientListFromString:[messageHeaders objectForKey:@"To"]];
  NSAppleEventDescriptor *ccrec
    = [self recipientListFromString:[messageHeaders objectForKey:@"Cc"]];
  NSAppleEventDescriptor *bccrec
    = [self recipientListFromString:[messageHeaders objectForKey:@"Bcc"]];
  unsigned numFiles = 0;
  NSUInteger length = [messageBody length];
  NSUInteger pos = 0;
  NSRange range;

  if ([messageHeaders objectForKey:@"Subject"])
    subj = [messageHeaders objectForKey:@"Subject"];
  if ([messageHeaders objectForKey:@"Sender"])
    sendr = [messageHeaders objectForKey:@"Sender"];

  /* Find all the attachments and replace them with placeholder text */
  while (pos < length) {
    NSDictionary *attributes = [messageBody attributesAtIndex:pos
                           effectiveRange:&range];
    NSTextAttachment *attachment
      = [attributes objectForKey:NSAttachmentAttributeName];

    if (attachment && !attachtmp) {
      /* Create a temporary directory to hold the attachments (we have to do this
     because we can't get the full path from the NSFileWrapper) */
      do {
    attachtmp = [tmpdir stringByAppendingPathComponent:
                  [NSString stringWithFormat:@"csmail-%08lx",
                    random ()]];
      } while (![fileManager createDirectoryAtPath:attachtmp
                       withIntermediateDirectories:NO
                                        attributes:nil
                                             error:NULL]);
    }

    if (attachment) {
      NSFileWrapper *fileWrapper = [attachment fileWrapper];
      NSString *filename = [attachtmp stringByAppendingPathComponent:
                 [fileWrapper preferredFilename]];
      NSURL *url = [NSURL fileURLWithPath:filename isDirectory:NO];

      [fileWrapper writeToURL:url
                      options:NSFileWrapperWritingAtomic
          originalContentsURL:nil
                        error:NULL];

      [body appendFormat:@"<%@>\n", [fileWrapper preferredFilename]];

      [files insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:filename]
              atIndex:++numFiles];

      pos = range.location + range.length;

      continue;
    }

    [body appendString:[[messageBody string] substringWithRange:range]];

    pos = range.location + range.length;
  }

  /* Replace any CF/LF pairs with just LF; also replace CRs with LFs */
  [body replaceOccurrencesOfString:@"\r\n" withString:@"\n"
    options:NSLiteralSearch range:NSMakeRange (0, [body length])];
  [body replaceOccurrencesOfString:@"\r" withString:@"\n"
    options:NSLiteralSearch range:NSMakeRange (0, [body length])];

  [event setParamDescriptor:
    [NSAppleEventDescriptor descriptorWithString:handler]
         forKeyword:keyASSubroutineName];
  [params insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:sendr]
           atIndex:1];
  [params insertDescriptor:recip atIndex:2];
  [params insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:subj]
           atIndex:3];
  [params insertDescriptor:ccrec atIndex:4];
  [params insertDescriptor:bccrec atIndex:5];
  [params insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:body]
           atIndex:6];
  [params insertDescriptor:files atIndex:7];

  [event setParamDescriptor:params forKeyword:keyDirectObject];

  if (![[self script] executeAppleEvent:event error:&errorInfo]) {
    NSLog (@"Unable to communicate with Mail.app.  Error was %@.\n",
       errorInfo);
    return NO;
  }

  return YES;
}

- (BOOL)deliverMessage:(NSAttributedString *)messageBody
           headers:(NSDictionary *)messageHeaders
{
  return [self doHandler:@"deliver_message"
          forMessage:messageBody
         headers:messageHeaders];
}

- (BOOL)constructMessage:(NSAttributedString *)messageBody
         headers:(NSDictionary *)messageHeaders
{
  return [self doHandler:@"construct_message"
          forMessage:messageBody
         headers:messageHeaders];
}

Метод -constructMessage:headers:, приведенный выше, заставит Mail открыть новое электронное письмо со всем уже заполненным, в то время как метод -deliverMessage:headers: создасти отправит электронное письмо одним ударом.

NSString* subject = @"mail subject";
NSString* body = @"mail body";
NSString* to = @"recipient@example.org";

NSString *encodedSubject = [NSString stringWithFormat:@"SUBJECT=%@", [subject stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *encodedBody = [NSString stringWithFormat:@"BODY=%@", [body stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *encodedTo = [to stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *encodedURLString = [NSString stringWithFormat:@"mailto:%@?%@&%@", encodedTo, encodedSubject, encodedBody];
NSURL *mailtoURL = [NSURL URLWithString:encodedURLString];

[[NSWorkspace sharedWorkspace] openURL:mailtoURL];

Это можно сделать довольно легко с помощью AppleScript, "интересная" часть заключается в том, как вызвать AppleScript из вашего приложения. Этот док должен дать вам то, что вам нужно: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ScriptingBridgeConcepts/Introduction/Introduction.html

Хорошая часть AppleScript заключается в том, что вы можете использовать редактор сценариев, чтобы узнать, как вы хотите управлять внешним приложением, а затем закодировать его в приложении, как только это будет сделано.