3

I'm new to swift and tried to follow several different tutorials on the internet to make my App run terminal stuff.

I have a checkbox that should enable (through the terminal command) the charging chime (and of course turn it off when unchecked).

EDIT: Updated code, still quite not working:

@discardableResult func shell(_ command: String) -> String { let task = Process() task.launchPath = "/usr/bin/" task.arguments = ["-c", command] let pipe = Pipe() task.standardOutput = pipe task.launch() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String return output } @IBAction func SoundBox(_ sender: NSButton) { if(SoundBox.state == NSControl.StateValue.on){ self.helloLabel.stringValue = "It's On!" shell("say hello") //shell("defaults write com.apple.PowerChime ChimeOnAllHardware -bool true; open /System/Library/CoreServices/PowerChime.app &") } else if(SoundBox.state == NSControl.StateValue.off){ self.helloLabel.stringValue = "It's off!" shell("say hello") //shell("defaults write com.apple.PowerChime ChimeOnAllHardware -bool false; killall PowerChime") } 

New Console output:

 2019-04-12 16:44:54.792282+0200 TerminApp[2985:45592] [General] Couldn't posix_spawn: error 13 2019-04-12 16:44:54.795254+0200 TerminApp[2985:45592] [General] ( 0 CoreFoundation 0x00007fff42444e45 __exceptionPreprocess + 256 1 libobjc.A.dylib 0x00007fff6d07c3c6 objc_exception_throw + 48 2 CoreFoundation 0x00007fff42444c77 +[NSException raise:format:] + 193 3 Foundation 0x00007fff446495e9 -[NSConcreteTask launchWithDictionary:error:] + 4437 4 TerminApp 0x000000010000299b $s9TerminApp14ViewControllerC5shellyS2SF + 635 5 TerminApp 0x000000010000349e $s9TerminApp14ViewControllerC8SoundBoxyySo8NSButtonCF + 1438 6 TerminApp 0x000000010000360c $s9TerminApp14ViewControllerC8SoundBoxyySo8NSButtonCFTo + 60 7 AppKit 0x00007fff3fcf8e80 -[NSApplication(NSResponder) sendAction:to:from:] + 312 8 AppKit 0x00007fff3fd63196 -[NSControl sendAction:to:] + 86 9 AppKit 0x00007fff3fd630c8 __26-[NSCell _sendActionFrom:]_block_invoke + 136 10 AppKit 0x00007fff3fd62fca -[NSCell _sendActionFrom:] + 178 11 AppKit 0x00007fff3fd8fd4f -[NSButtonCell _sendActionFrom:] + 96 12 AppKit 0x00007fff3fd618e5 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2375 13 AppKit 0x00007fff3fd8faa0 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 698 14 AppKit 0x00007fff3fd60322 -[NSControl mouseDown:] + 791 15 AppKit 0x00007fff3fc3c16f -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 5724 16 AppKit 0x00007fff3fb729de -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2295 17 AppKit 0x00007fff3fb71e9f -[NSWindow(NSEventRouting) sendEvent:] + 478 18 AppKit 0x00007fff3fa116c3 -[NSApplication(NSEvent) sendEvent:] + 331 19 AppKit 0x00007fff3f9ffee8 -[NSApplication run] + 755 20 AppKit 0x00007fff3f9ef3f0 NSApplicationMain + 777 21 TerminApp 0x000000010000475d main + 13 22 libdyld.dylib 0x00007fff6e8a13d5 start + 1 ) 
6
  • my 1st guess would be that's caused because you pass the arguments as 1 element of the array so swift treats it as a single argument. I'm no expert in swift though. Try separating your commands and see if it works Commented Apr 12, 2019 at 13:32
  • Have you tried running open /System/Library/CoreServices/PowerChime.app & as a separate command, and not as part of the arguments of defaults as well ? Commented Apr 12, 2019 at 13:52
  • If you want to directly call bash commands without using the argument separation like you did, creating a custom function like in this answer could be a solution. Commented Apr 12, 2019 at 14:12
  • I'm close but something still fails Commented Apr 12, 2019 at 14:44
  • 1
    If you type say hello in Terminal, it works? Did you meant shell("echo say hello")? Also, might want to do ["-l", "-c", command]? Commented Apr 12, 2019 at 15:46

1 Answer 1

2

This is how I do it to start ffmpeg in my app. (ffmpegTask is a Process! instance, declared as an instance property, and prefs.input_uri is a String, coming from user input -It is the URI of an RTSP stream). Hope this helps (the "TemporaryFile" thing is from Ole Begemann's excellent utility):

/* ################################################################## */ /** This starts the ffmpeg task. - returns: True, if the task launched successfully. */ func startFFMpeg() -> Bool { ffmpegTask = Process() // First, we make sure that we got a Process. It's a conditional init. if let ffmpegTask = ffmpegTask { // Next, set up a tempdir for the stream files. if let tmp = try? TemporaryFile(creatingTempDirectoryForFilename: "stream.m3u8") { outputTmpFile = tmp // Fetch the executable path from the bundle. We have our copy of ffmpeg in there with the app. if var executablePath = (Bundle.main.executablePath as NSString?)?.deletingLastPathComponent { executablePath += "/ffmpeg" ffmpegTask.launchPath = executablePath ffmpegTask.arguments = [ "-i", prefs.input_uri, "-sc_threshold", "0", "-f", "hls", "-hls_flags", "delete_segments", "-hls_time", "4", outputTmpFile?.fileURL.path ?? "" ] #if DEBUG if let args = ffmpegTask.arguments, 1 < args.count { let path = ([executablePath] + args).joined(separator: " ") print("\n----\n\(String(describing: path))") } #endif // Launch the task ffmpegTask.launch() #if DEBUG print("\n----\n") #endif return ffmpegTask.isRunning } } } return false } 

Sandboxing is likely to be an issue, depending on where you are calling. ffmpeg doesn't like sandboxes anyway, but I still embed the variant that I build for my app in the same directory as the main app executable.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.