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

Posted

技术标签:

【中文标题】在 Mac 应用程序中嵌入可执行文件【英文标题】:Embed Executable inside Mac Application 【发布时间】:2012-08-17 20:31:13 【问题描述】:

如果您访问/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 会允许吗?

【问题讨论】:

一般来说,只需在构建时将它们作为应用程序包的一部分就可以了。不幸的是,我对问题的应用商店部分一无所知。 @Lvsti 你到底是什么意思?如,我应该在哪里添加可执行文件?我将如何“在构建时使它们成为应用程序包的一部分”?我该怎么称呼它 - setPathLaunch 是什么? 我怀疑应用商店不允许允许此类恶作剧,因为沙盒可能不允许启动外部任务。 Other people have been thinking about this question as well. 【参考方案1】:

如果您想知道,在 Swift 3 中您可以这样做:

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

【讨论】:

【参考方案2】:

只是为了更新和澄清,我发现以下内容适用于 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)")

【讨论】:

【参考方案3】:

好的,所以我开始尝试自己寻找答案。而且,我很高兴地说我想通了!

因此,只需将executable 复制到 Xcode 项目中您想要的任何位置。然后,改变

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

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

还有哒哒!

【讨论】:

感谢您的回答。请问您可以使用这种方法通过 App Store 分发吗?【参考方案4】:

在 Swift 中,您可以这样做:

let bundle = NSbundle.mainBundle()
let task = NSTask()

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

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

【讨论】:

【参考方案5】:

我更新了 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.

【讨论】:

以上是关于在 Mac 应用程序中嵌入可执行文件的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 程序中嵌入外部可执行文件

在 Windows 可执行文件中嵌入 JRE?

SQLite 库可以嵌入(链接)到 Delphi 可执行文件吗?

使用 GCC 在可执行文件中嵌入资源

Mac 命令行中添加命令直接调用可执行文件

理解Unix可执行文件