Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

swift - Using AppleScript with Apple Events in macOS - Script not working

We need to use a AppleScript to create an outgoing email message in macOS. The script works fine in the Script Editor. Using the code recommended by DTS https://forums.developer.apple.com/message/301006#301006 no results, warnings or errors. Same result with sample script from the forum. Need Swift and Apple Events expertise here. Thanks!

import Foundation
import Carbon
class  EmailDoc: NSObject {

    var script: NSAppleScript = { 
        let script = NSAppleScript(source: """


            set theSubject to "Some Subject"
            set theContent to "Some content of the email"
            set recipientName to "Some Name"
            set recipientAddress to "someone@example.com"

            tell application "Mail"

                # Create an email
                set outgoingMessage to make new outgoing message with properties {subject:theSubject, content:theContent, visible:true}

                # Set the recipient
                tell outgoingMessage
                    make new to recipient with properties {name:recipientName, address:recipientAddress}

                    # Send the message
                    send

                end tell
            end tell
            """  
            )!  
        let success = script.compileAndReturnError(nil)  
        assert(success)  
        return script  
    }() 

    // Script that is referenced by DTS at https://forums.developer.apple.com/message/301006#301006
    // that goes with runScript method below  -- runs with no results

    /*var script: NSAppleScript = {  
     let script = NSAppleScript(source: """

     on displayMessage(message)  
     tell application "Finder"  
     activate  
     display dialog message buttons {"OK"} default button "OK"  
     end tell  
     end displayMessage  
     """  
     )!  
     let success = script.compileAndReturnError(nil)  
     assert(success)  
     return script  
     }() */

    @objc
    func runScript() {

        let parameters = NSAppleEventDescriptor.list()  
        parameters.insert(NSAppleEventDescriptor(string: "Hello Cruel World!"), at: 0)  

        let event = NSAppleEventDescriptor(  
            eventClass: AEEventClass(kASAppleScriptSuite),  
            eventID: AEEventID(kASSubroutineEvent),  
            targetDescriptor: nil,  
            returnID: AEReturnID(kAutoGenerateReturnID),  
            transactionID: AETransactionID(kAnyTransactionID)  
        )  
        event.setDescriptor(NSAppleEventDescriptor(string: "displayMessage"), forKeyword: AEKeyword(keyASSubroutineName))  
        event.setDescriptor(parameters, forKeyword: AEKeyword(keyDirectObject))  

        var error: NSDictionary? = nil  
        _ = self.script.executeAppleEvent(event, error: &error) as NSAppleEventDescriptor?  

        print ("runScript",self.script)

        }
    }


See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem with this code — which is an incredibly un-obvious problem, mind you —?is that you're using code meant to run a script handler (a method or subroutine) to try to run the full script. One of the oddnesses of Obj-C's AppleScript classes is that there is no easy way to run a script with parameters, so the workaround is to enclose the code to be executed within a script handler, and use an Apple Event that calls that handler. To make your code work, you'll do something like the following...

First, change the script so that the code is in a handler:

var script: NSAppleScript = { 
    let script = NSAppleScript(source: """

    -- This is our handler definition
    on sendMyEmail(theSubject, theContent, recipientName, recipientAddress, attachmentPath)
        tell application "Mail"

            -- Create an email
            set outgoingMessage to make new outgoing message ?
            with properties {subject:theSubject, content:theContent, visible:true}

            -- Set the recipient
            tell outgoingMessage
                make new to recipient ?
                with properties {name:recipientName, address:recipientAddress}

                make new attachment with properties {file name:POSIX file attachmentPath}

               -- Mail.app needs a moment to process the attachment, so...
               delay 1

               -- Send the message
               send 
            end tell
        end tell
    end sendMyEmail
    """  
    )!  

Then alter the Apple Event you construct so that it passes the parameters and calls the handler we just defined:

func runScript() {
    let parameters = NSAppleEventDescriptor.list()  
    parameters.insert(NSAppleEventDescriptor(string: "Some Subject"), at: 0)  
    parameters.insert(NSAppleEventDescriptor(string: "Some content of the email"), at: 0)  
    parameters.insert(NSAppleEventDescriptor(string: "Some Name"), at: 0)  
    parameters.insert(NSAppleEventDescriptor(string: "someone@example.com"), at: 0)  
    parameters.insert(NSAppleEventDescriptor(string: attachmentFileURL.path), at: 0)  

    let event = NSAppleEventDescriptor(  
        eventClass: AEEventClass(kASAppleScriptSuite),  
        eventID: AEEventID(kASSubroutineEvent),  
        targetDescriptor: nil,  
        returnID: AEReturnID(kAutoGenerateReturnID),  
        transactionID: AETransactionID(kAnyTransactionID)  
    )  

    // this line sets the name of the target handler
    event.setDescriptor(NSAppleEventDescriptor(string: "sendMyEmail"), forKeyword: AEKeyword(keyASSubroutineName))

    // this line adds the parameter list we constructed above  
    event.setDescriptor(parameters, forKeyword: AEKeyword(keyDirectObject))  

    var error: NSDictionary? = nil  
    _ = self.script.executeAppleEvent(event, error: &error) as NSAppleEventDescriptor?  

    print ("runScript",self.script)

    }
}

If you don't need to pass parameters, you could run the script directly using script.executeAndReturnError(&error), but if you need to pass parameters, you'll need to use this 'handler' approach.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...