NSAppleScript(source: "do shell script \"sudo chmod 777 '\(appPath.path)'\" with administrator " + "privileges")!.executeAndReturnError(nil)
When I run this code in Xcode, the app gives a alert
But if I run same code in the Apple Scrip app, the app will give a touch id alert.
How can I show a touch id alert when I run this code in the Xcode?
Finally, I found it is impossible to do this. But there is an alternative way.s
guard let shBundlePath = Bundle.main.path(forResource: "chmodHelper", ofType: "sh") else { fatalError("Cannot get the sh file path") }
guard let installerHelperPath = Bundle.main.path(forResource: "installHelper", ofType: "sh") else { fatalError("Cannot get the sh file path") }
let helperToolURL = URL.documents.universalappending(path: "chmodHelper.sh")
if FileManager.default.fileExists(atPath: helperToolURL.universalPath()) {
try FileManager.default.removeItem(at: helperToolURL)
}
try FileManager.default.copyItem(atPath: shBundlePath, toPath: helperToolURL.universalPath())
try setInstallerContent(path: helperToolURL.universalPath())
NSAppleScript(source: "do shell script \"chmod +x '\(installerHelperPath)' && sudo '\(installerHelperPath)'\" with administrator " + "privileges")!.executeAndReturnError(nil)
Run this when the app starts.
And then change the content of the shell file. Then use apple scrip to run it. So you can avoid the alert
Related
I'm trying to write a small app to start/stop and display data from a command line "app" someone else wrote. The command executable is installed in '/usr/local/bin'. It outputs status text data to standardOutput while running. I can execute this "command" from the Terminal.app without issue. From swiftUI code I can successfully execute "built-in" commands like ls. However, when (in swiftUI code) I attempt to execute Process.run WITH the new command it throws the exception 'The file “” doesn’t exist.'
Anyone have any ideas? Thanks in advance!
Here's a code snip:
// NOTE: "installedCommand" is just a placeholder for the actual command.
let task = Process()
let connection = Pipe()
let exeUrl = URL(fileURLWithPath: "/usr/local/bin/installedCommand")
//let exeUrl = URL(fileURLWithPath: "/bin/ls") <--works fine
task.executableURL = exeUrl
task.standardOutput = connection
do
{
try task.run()
}
catch
{
print("Error: \(error.localizedDescription)")
return
}
I have a simple shell script which launches an X11 app. When I execute this shell script form my login shell / terminal xQuartz starts and I get a display. However the process doesn't get a display for xQuartz when running the script from within swift. Any idea how I can get the display?
Also what is the best way to detect if xQuartz is installed? Checking if xterm exists?
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/sh")
let startScriptURL = Bundle.main.url(forResource: "run", withExtension: "sh")
guard let startScriptPath = startScriptURL?.path else {
return
}
process.arguments = [startScriptPath]
do {
try process.run()
} catch let error {
print(error)
}
run.sh:
#!/bin/sh
/opt/X11/bin/xeyes
I figured our how to pass the DISPLAY environment or any environmental variable to Process.
The current environment can be obtained by:
ProcessInfo().environment
So I use now this:
let process = Process()
guard let envDisplay = ProcessInfo().environment["DISPLAY"] else {
print("Please install xQuartz")
return
}
process.environment = ["DISPLAY": envDisplay]
I got the idea from here: Issue launching X11 app via NSTask
I'm writing a sandboxed app in Swift 4 on macOS High Sierra using Xcode 9. My app has a shell script file (say, myscript) copied to the Bundle.main.resourceURL directory when installing. I want to run this shell script using NSUserUnixTask as follows:
if let scriptUrl = URL(string: "myscript", relativeTo: Bundle.main.resourceURL) {
do {
let task = try NSUserUnixTask(url: scriptUrl)
task.execute(withArguments: [ "hello" ])
debugPrint("OK")
} catch let error {
debugPrint(error)
}
} else {
debugPrint("Script not found")
}
// output: "OK"
This gives no error messages and "OK" is correctly displayed. But the myscript script seems to be completely ignored. When I run myscript from Terminal instead, it runs as intended.
The test myscript file looks like:
#!/bin/sh
/usr/bin/osascript -e "tell app \"System Events\" to display dialog \"Message: $1\""
(The is only a test script; the real one calls emacsclient.) The shell script file is set executable (permission 755). Not only this shell script but also any other shell script seems ignored. For example, if the second line is replaced with /usr/bin/printf "\a", it does not beep. I tried many other shell scripts but nothing seems to work.
How can I solve this issue?
EDIT:
I was hasty. The class document says "If the application is sandboxed, then the script must be in the applicationScriptsDirectory folder." Now I want to know how to copy the script file upon installation.
EDIT 2:
I manually copied myscript to ~/Library/Applications Scripts/com.mydomain.myApp/ and then changed the first line of the above Swift codes (if let scriptUrl ...) to
let scriptFolderUrl = try! FileManager.default.url(for: .applicationScriptsDirectory,
in: .userDomainMask, appropriateFor: nil, create: true)
if let scriptUrl = URL(string: "myscript", relativeTo: scriptFolderURL) {
https://tutel.me/c/programming/questions/43741325/swift+3++sandbox++how+to+create+applicationscriptsdirectory+if+it+doesn39t+exist
The script runs. Now I need to figure out how to copy the script to the scripts folder when installing or running the app the first time.
pkamp requested a proper answer. :)
As the class document says, the script must be in the applicationScriptsDirectory folder. This folder is not writable by a sandboxed application, as vadian pointed out. The script (myscript) must be copied manually to the applicationScriptDirectory folder (e.g., ~/Library/Applications Scripts/com.mydomain.myApp/).
After this done, change the first line to the following:
// --------------------------------------------------------
let scriptFolderUrl = try! FileManager.default.url(for: .applicationScriptsDirectory,
in: .userDomainMask, appropriateFor: nil, create: true)
if let scriptUrl = URL(string: "myscript", relativeTo: scriptFolderURL) {
// --------------------------------------------------------
// same below
do {
let task = try NSUserUnixTask(url: scriptUrl)
task.execute(withArguments: [ "hello" ])
debugPrint("OK")
} catch let error {
debugPrint(error)
}
} else {
debugPrint("Script not found")
}
I benefited from this link for the first line.
Im new to developing mac applications. (but I have work a lot for ios)
For start I want to have a window on which there is a button. When user click on the button, it should trigger an action that will run some shell commands inside the folder that the user dragged & dropped inside the app before.
For example
User will drag and drop some folder inside my app and the app should create gemfile inside this folder.
Here is my current version where I run the shell and the first command is cd <pathToFolder> but the output is /usr/bin/cd: line 4: cd: file:///Users/klemen/Downloads/ABCAcura/: No such file or directory
Here is my code:
#IBAction func handleCreateGemfileButton(_ sender: NSButton) {
let pipe = Pipe()
let process = Process()
process.launchPath = "/bin/bash"
process.arguments = ["cd", projectURL.absoluteString]
process.standardOutput = pipe
let file = pipe.fileHandleForReading
process.launch()
if let result = NSString(data: file.readDataToEndOfFile(), encoding: String.Encoding.utf8.rawValue) {
print(result as String)
}
else {
print("error")
}
}
Is there some restrictions. How is it possible to request from user that my app will have access to some of his files?
You should use ~/Downloads/ABCAcura instead of file:///..., file:/// is a protocol (URL) not a path to file.
I am building an installer for an OS X application in Swift 2.0. The installer does little more than take user input, sends it to a server, and builds a desktop shortcut determined by server response. This shortcut (the 'application') opens up another application (FileMaker). As part of the installation process I am installing FileMaker silently using NSTask which runs a shell script executing installer.app on the FileMaker .pkg. This works fine.
I need to determine whether this installation is successful or not in order to progress to the next step in the installer. I can easily get the string response from the terminal, ie "installer: The install was successful," but I dont feel a hard coded string condition is robust enough. Any other possibilities?
n.b. I'm a beginner Swift developer (1 week!) and have only a year of Web Development behind that. ie. I'm blindingly green.
P.S. Ideally I'd be displaying a progress indicator for the FileMaker installation rather than a message, but that'd be overextending myself (further) if it's even possible.
func installFileMaker() {
let fileMakerFileName = "FileMaker Pro 14"
let fileMakerDirectory = "Resources/FileMaker14_MacClient"
// get resource path
let bundle = NSBundle.mainBundle()
let resourcePathResult = bundle.pathForResource(fileMakerFileName, ofType: "pkg", inDirectory: fileMakerDirectory)
if let resourcePath = resourcePathResult {
displayWebViewMessage("Installing Briefcase Now...")
let command = "installer -pkg \"" + resourcePath + "\" -target /"
Utilities.runAsCommandInBackground(command, callback: installUpdateWebviewCallback)
} else {
// error
displayWebViewMessage("Installation error")
}
print("rrr")
}
Runs shell command
static func runAsCommandInBackground(command: String, callback: (((success:Bool, message:String)) -> Void)?) {
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let pipe = NSPipe()
let task = NSTask()
task.launchPath = "/bin/sh"
task.arguments = ["-c", String(format:"%#", command)]
task.standardOutput = pipe
let file = pipe.fileHandleForReading
task.launch()
var result = ""
if let tmpResult = NSString(data: file.readDataToEndOfFile(), encoding: NSUTF8StringEncoding) {
result = tmpResult as String
} else {
// error
}
dispatch_async(dispatch_get_main_queue()) {
print(result)
// Give me a more robust result!!
if let unwrappedCallback = callback {
unwrappedCallback((true, result as String))
}
}
}
}