在命令行工具中获取资源路径

问题描述 投票:0回答:3

我正在尝试在 Xcode (8 beta 2) 的命令行工具中获取资源的路径。这是我得到的:

  • 资源 file.xyz 已被拖入项目中,并且目标成员资格与主项目匹配。
  • 在“构建阶段”->“复制文件”下,目标设置为“资源”并且子路径为空。未选中“仅在安装时复制”,file.xyz 列于下表中。
  • 在我的 main.swift 文件中,我有以下代码:

    guard let filePath = Bundle.pathForResource("file",
                                             ofType: "xyz",
                                             inDirectory: "Resources") else{
        fatalError("Could not find file")
    }
    

每次都会触发

fatalError
。有什么想法吗?我知道命令行工具没有应用程序包,这就是为什么资源被复制到资源文件夹中,但我的
inDirectory
论点有点疯狂猜测......感谢您的阅读。

编辑:我的主要目标是从 CLT 访问资源文件(在本例中为文本文件)——我不喜欢这种特定的执行方式,所以如果有替代方法也很棒!

swift xcode command-line
3个回答
2
投票

使用 Xcode 13.2 和 Swift 5,我遇到了同样的问题:我已将 JSON 文件拖到我的命令行工具项目中,但无法直接在我的代码中使用它。由于 CLT 似乎没有 Bundle,所以我找到了解决方法。

我创建了一个仅包含静态 let 属性的结构,其中包含我的 JSON 作为字符串:

struct CategoriesJSON {
    static let string = """
... my JSON is here as plain text ...
"""
}

现在我只需拨打:

CategoriesJSON.string
即可使用它。 我知道这有点难看,但现在我的 JSON 已经在我的项目中了。


0
投票

在最终二进制文件(命令行工具)中包含任意文件的一种方法是让链接器将它们包含在自定义 Mach-O 部分中,并从这些部分中获取它们。

设置起来有点不方便,但如果您的数据难以以字符串形式包含(例如图像或大型 XML 文件),则效果很好。

  • 首先,将您的资源复制到您的项目中。让我们从您的源顶级中说
    Resources/my.data
  • 在 Xcode 中,选择您的项目和目标,然后导航到“构建设置”选项卡。
  • 在链接部分找到
    Other Linker Flags
    条目(在搜索字段中,您可以输入
    OTHER_LDFLAGS
    )。
  • 对于要包含的每个文件,您需要添加四个条目(它们的顺序很重要!):
    • -sectcreate
    • __TEXT
    • 您要用于资源的名称
    • 文件路径,如
      $(SRCROOT)/Resources/my.data

这看起来像这样:

Example of OTHER_LDFLAGS setting in Xcode

当您构建它时,链接器现在会将此文件包含到您的最终可执行文件中。如果文件丢失,您将收到链接器错误。

以下是如何在 Swift 中获取它:

import Foundation

/// Get resource embedded in the executable binary.
///
/// The resource needs to be embedded by the linker using the flag
/// `-sectcreate __TEXT [name] [path to file]`.
func getEmbeddedData(_ name: String) -> Data {
    // All of this because `_mh_execute_header` is a `let` instead of a `var`,
    // and `getsectiondata` does not accept copies of this value.
    // See https://stackoverflow.com/a/49438718/400056
    guard let handle = dlopen(nil, RTLD_LAZY) else {
        fatalError("Cannot get handle to executable")
    }
    defer { dlclose(handle) }

    guard let ptr = dlsym(handle, MH_EXECUTE_SYM) else {
        fatalError("Cannot get symbol '\(MH_EXECUTE_SYM)")
    }
    
    let header = ptr.assumingMemoryBound(to: mach_header_64.self)
    
    var size: UInt = 0
    guard let rawData = getsectiondata(header, "__TEXT", name, &size) else {
        fatalError("Cannot find resource '\(name)'")
    }
    return Data(bytes: rawData, count: Int(size))
}

-2
投票

作为解决方法,您可以使用源文件的绝对路径 例如,如果在 iCloud 驱动器上:

让路径=“/Users/myName/Library/Mobile Documents/com~apple~CloudDocs/myDirectory/file.xyz"

© www.soinside.com 2019 - 2024. All rights reserved.