正在生成 resource_bundle_accessor,类型 'Bundle' 没有成员 'module'

Generating resource_bundle_accessor, Type 'Bundle' has no member 'module'

有时Xcode无法确定Bundle中的module参数。

Type 'Bundle' has no member 'module'

我的调查表明,SPM 会在一个名为 resource_bundle_accessor 的文件中为此 属性 自动生成模块扩展(有时),例如:

import class Foundation.Bundle

private class BundleFinder {}

extension Foundation.Bundle {
    /// Returns the resource bundle associated with the current Swift module.
    static var module: Bundle = {
        let bundleName = "ABUIKit_ABStyleKit"

        let candidates = [
            // Bundle should be present here when the package is linked into an App.
            Bundle.main.resourceURL,

            // Bundle should be present here when the package is linked into a framework.
            Bundle(for: BundleFinder.self).resourceURL,

            // For command-line tools.
            Bundle.main.bundleURL,
        ]

        for candidate in candidates {
            let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
            if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
                return bundle
            }
        }
        fatalError("unable to find bundle named ABUIKit_ABStyleKit")
    }()
}

但有时不会。为什么会这样,我怎样才能让它自动工作再次(无需手动实施。)

这两种情况都发生在 Xcode 12 beta.3

更新

有时显示:

'module' is inaccessible due to 'internal' protection level

它根本不显示文件。

SPM 生成 resource_bundle_accessor 仅当相应的目标包含 resources 作为参数时,如:

    .target(
        name: "ChenzookKit",
        dependencies: ["Apollo"],
        resources: [.process("Resources")] // <- `copy` or `process` doesn't really matter 
    ),

此外,请注意它应该是一个有效的资源路径。

和❗️

项目必须实际包含Resources目标目录中!

和❗️❗️

不要忘记构建 (cmd+b) 代码来创建 .module

Bundle.module 只有在 Package.swift 文件中的 resources 不为空时才会由 SwiftPM 生成 指定的资源实际存在.

所以有两个可能的原因它可能不适合你:

  1. 您没有在 Package.swift 中指定任何 resources。像这样修复:
.target(
    name: "MyLibrary",
    dependencies: [
        /* your dependencies */
    ],
    resources: [
        .copy("JsonData"),
        .process("Assets.xcassets"),
    ]
),
  1. 指定的路径不存在或为空。

    通过检查您是否确实将资源放在 中进行修复 Sources/MyLibrary 目录。一个常见的错误是将它们放在 直接到 Sources 或不同的目标子文件夹。

好的,我找到了解决方案,所以 Swift 实际上生成了 Bundle.module 文件

documentation explicitly states that you have to put your Resources under the folder <project_root>/Sources/<MyTarget>/ since SPM scopes resources by target. The target definition looks then like this for my repo SHSearchBar(比较Github上的文件结构):

// swift-tools-version:5.3
import PackageDescription


    targets: [
        .target(
            name: "SHSearchBar",
            resources: [.copy("Resources")]
        )
    ]

目标文件夹:<project_root>/Sources/SHSearchBar
资源文件夹:<project_root>/Sources/SHSearchBar/Resources

顺便说一下,要从命令行构建一个 iOS 包,您可以使用此命令使用 iOS 14 SDK:

swift build -Xswiftc "-sdk" -Xswiftc "\`xcrun --sdk iphonesimulator --show-sdk-path\`" -Xswiftc "-target" -Xswiftc "x86_64-apple-ios14.0-simulator"

为了让我的小 post 完整,我还想提一下,使用 Bundle.module 方法的包可以集成到 运行 on iOS < 14 也是因为生成的扩展名不包含任何新的 API

如果您看到这样的错误:

Error: found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target

Type 'Bundle' has no member 'module'

然后查看以下五个条件:

1. 检查 Package.swift 的第一行是否声明使用 swift-tools-version:5.3 或更高版本。

// swift-tools-version:5.3

2. 检查目标文件夹下的资源文件夹。例如,

Sources/MyTarget/Resources
Tests/MyTargetTests/Resources

3. 检查您是否已经添加了至少一项资源。例如,

Tests/MyTargetTests/Resources/paginatedLabels.json

4. 检查您是否通过使用 Xcode.

打开文件 Package.swift 来打开包

5. 检查 Package.swift 文件是否声明了资源元素,如下所示:

.testTarget(
    name: "MyTargetTests",
    dependencies: ["MyTarget"],
    resources: [
        .process("Resources")
    ]
),

此时,编译器合成了一个文件resource_bundle_accessor.swift,内容如下:

extension Foundation.Bundle {
    static var module: Bundle = {
...

检查文件是否确实已合成:

# is the bundle being synthesized when you build?
find ~/Library/Developer/Xcode/DerivedData* -iname resource_bundle_accessor.swift

要从包中加载资源,请使用 Bundle.module,例如

UIImage(named: "share", in: Bundle.module, compatibleWith: nil)

找到包包目录的路径:

MODULE=MyModuleName && find -E ~/Library/Developer/Xcode/DerivedData -regex ".*$MODULE_$MODULE.bundle"

检查软件包是否包含特定资源,例如图片:

# I’m building for iPhone 12 (@3x). Is share@3x.png inside the bundle?
find ~/Library/Developer/Xcode/DerivedData* -iname Assets.car -exec xcrun --sdk iphoneos assetutil --info {} \; | grep -E "share.*png"

这是一个使用自定义目录的示例:

targets: [
    .target(
        name: "Kit",
        dependencies: [],
        path: "sources/main",
        resources: [
            .process("resources")
        ]
    ),

其中目录是:

Kit/
├── sources/
│   └── main/
│       ├── SourceFile.swift
│       └── resources/
│           └── file.json
└── Package.swift

如果一切都失败并且您怀疑有错误,请检查 bug database for SPM

您还可以通过使用 static let:

创建 class 来公开捆绑包
public class YourPackageBundle {
   public static let yourPackageBundle = Bundle.module
}

然后您可以在 public classes 中访问它并使用它:

public init(backgroundImage: Image? = nil,
            logoImage: Image? = nil,
            userIconImage: Image? = nil,
            userTextFieldPlaceholder:String = NSLocalizedString("global_username", bundle: YourPackageBundle.yourPackageBundle, comment: "User placeholder text")