在Mac应用程序中嵌入可执行文件

4

如果你进入/usr/bin目录,你会看到数百个可执行文件或者可执行文件的链接。

我的应用程序(一个在Xcode中用Obj-C编写的Mac应用程序)依赖于其中一些可执行文件。不幸的是,这些可执行文件必须手动安装 - 我必须检查它们,然后提示用户安装它们。

我的代码如下:

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/usr/bin/executable"];

NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];

[task setArguments:[NSArray arrayWithObjects:sender, target, nil]];
[task launch];

我想知道是否可以将可执行文件复制到我的应用程序中的某个位置,然后从那里调用它。这样,用户就不必自己获取它了。

这种做法在Mac App Store上是否允许?


通常情况下,在构建应用程序时将它们作为应用程序包的一部分,并且你便可以使用它们。很遗憾,我不知道关于App Store 的问题。 - Lvsti
@Lvsti 你具体是什么意思?我的意思是,我应该在哪里添加可执行文件?如何在构建时将它们作为应用程序包的一部分?以及我应该如何调用它 - setPathLaunch 是什么? - citruspi
我怀疑这种恶作剧在应用商店中是不被允许的,因为沙盒很可能不允许启动外部任务。其他人也在思考这个问题 - Michael Dautermann
5个回答

1

如果你有疑问,在Swift 3中你可以这样做:

let bundle = Bundle.main
let task = Process()
let path = bundle.path(forResource: "executableName", ofType: "")
task.launchPath = path

1

仅供更新和澄清,我发现以下代码适用于Xcode 11和Swift 5。

首先,将所需的可执行文件(在我的情况下是pandoc)拖放到我的Xcode项目中。我将其放置在名为“bin”的组/文件夹中。

确保选择了我希望包含可执行文件的目标!

然后使用以下代码:

let task = Process()
let bundle = Bundle.main
let execURL = bundle.url(forResource: "pandoc", withExtension: nil)
guard execURL != nil else {
    print("Pandoc executable could not be found!")
    return 
}
task.executableURL = execURL!
task.arguments = ["--version"]
do {
    try task.run()
    print("Pandoc executed successfully!")
} catch {
    print("Error running Pandoc: \(error)")
}

0

我更新了hbowie的答案,以返回从shell接收到的值作为字符串:

func safeShell(_ strExecutable:String, _ arrArguments:Array<String>) throws -> String {
        
        let task = Process()
        let pipe = Pipe()
        let bundle = Bundle.main
        let execURL = bundle.url(forResource: strExecutable, withExtension: nil)
        
        //no point in going on if we can't find the program
        guard execURL != nil else {
            print("\(strExecutable) executable could not be found!")
            return ""
        }
        
        task.executableURL = execURL!
        task.arguments = arrArguments
        task.standardOutput = pipe
        task.standardError = pipe
        //task.arguments = ["-c", command]
        //task.executableURL = URL(fileURLWithPath: "/bin/zsh") //<--updated

        do {
            try task.run() //<--updated
        }
        catch{ throw error }
        
        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        let output = String(data: data, encoding: .utf8)!
        
        return output
    }
    
}

使用示例:

let strOutput = try myAppManager.safeShell("pandoc", ["--version"])
print(strOutput)

返回:

pandoc 2.16.2
Compiled with pandoc-types 1.22.1, texmath 0.12.3.2, skylighting 0.12.1,
citeproc 0.6, ipynb 0.1.0.2
User data directory: /Users/stevesuranie/Library/Containers/MartianTribe.MD2HTML/Data/.local/share/pandoc
Copyright (C) 2006-2021 John MacFarlane. Web:  https://pandoc.org
This is free software; see the source for copying conditions. There is no
warranty, not even for merchantability or fitness for a particular purpose.

0

好的,所以我开始自己尝试操作来找到答案。很高兴地说,我终于弄清楚了!

所以,只需将可执行文件复制到你想要的任何位置的Xcode项目中。然后,更改

[task setLaunchPath:@"/usr/bin/executable"];

[task setLaunchPath:[[NSBundle mainBundle] pathForResource:@"executable" ofType:@""]];

完成了!


谢谢你的回答。请问你能否通过这种方法在应用商店上分发呢? - ADB

0
在Swift中,你可以这样做:
let bundle = NSbundle.mainBundle()
let task = NSTask()

task.launchPath = bundle.pathForResource("executableName", ofType: "")

确保捆绑的可执行文件位于目录树的顶层,而不是像 /lib 这样的子目录中,否则可能无法正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接