在 CocoaPods 中使用资源包

Bal*_*cze 7 bundle storyboard ios cocoapods swift

我正在制作一个 pod (MySDK) 并希望从CocoaPods生成的单独资源包中加载资产。

但是,我无法让它工作。

这是我尝试加载故事板的方法:

let storyBoard = UIStoryboard(name: "SDK", bundle: Bundle(identifier:"org.cocoapods.SchedJoulesSDK"))
Run Code Online (Sandbox Code Playgroud)

这给出了错误:

'在捆绑包中找不到名为'SDK'的故事板

该捆绑包已添加到 Xcode 中:

我的podspec样子是这样的:

  s.resource_bundles = {
    'MySDK' => ['SDK/*/*.{xib,storyboard,xcassets}']
  }
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Mec*_*cki 20

如果你在 CocoaPods PodSpec 文件中使用resourceresources,你告诉 Cocoapods 这些是你的库将在运行时加载的资源文件。

如果您的库是作为动态框架构建的,则这些文件只是复制到该框架的资源文件夹路径中,一切都会好起来的。然而,如果您的库是作为静态库构建的,则这些将被复制到主应用程序包 ( .app)的资源文件夹中,这可能会出现问题,因为该主应用程序可能已经拥有该名称的资源,或者另一个 Pod 可能拥有该资源同名,在这种情况下,这些文件将相互覆盖。Pod 是作为动态框架构建还是作为静态库构建的,并不是由 PodSpec 指定的,而是由集成您的 Pod 的应用程序在 Podfile 中指定的。

因此,对于具有资源豆荚,强烈建议使用resource_bundles,而不是!

在你的情况下,线条

s.resource_bundles = {
    'MySDK' => ['SDK/*/*.{xib,storyboard,xcassets}'] }
Run Code Online (Sandbox Code Playgroud)

告诉 CocoaPods 创建一个名为MySDK ( MySDK.bundle)的资源包,并将与模式匹配的所有文件放入该资源包中。如果你的 Pod 是作为框架构建的,这个包位于你的框架包的资源文件夹中;如果它是作为静态库构建的,则该包会被复制到主应用程序包的资源文件夹中,如果您将包命名为与 Pod 相同的名称(您不应将其命名为“ MySDK ”,而是“ SchedJoulesSDK ”)。

此包将具有与您的 Pod 相同的标识符,但是当构建动态框架时,您的框架包也将具有该标识符,然后当您通过标识符加载它时,正在加载哪个包是未定义的行为(并且目前外部包总是在我的测试中获胜)。

正确的代码看起来像这样(虽然没有测试):

// Get the bundle containing the binary with the current class.
// If frameworks are used, this is the frameworks bundle (.framework),
// if static libraries are used, this is the main app bundle (.app).
let myBundle = Bundle(for: Self.self)

// Get the URL to the resource bundle within the bundle
// of the current class.
guard let resourceBundleURL = myBundle.url(
    forResource: "MySDK", withExtension: "bundle")
    else { fatalError("MySDK.bundle not found!") }

// Create a bundle object for the bundle found at that URL.
guard let resourceBundle = Bundle(url: resourceBundleURL)
    else { fatalError("Cannot access MySDK.bundle!") }

// Load your resources from this bundle.
let storyBoard = UIStoryboard(name: "SDK", bundle: resourceBundle)
Run Code Online (Sandbox Code Playgroud)

由于resourceBundle不能在运行时更改,因此只创建一次(例如在应用程序启动时或在您的框架初始化时)并将其存储到全局变量(或全局类属性)中是安全的,因此您可以在需要时始终使用它(a bundle 对象也几乎不使用任何 RAM 内存,因为它只封装元数据):

final class SchedJoulesSDK {
    static let resourceBundle: Bundle = {
        let myBundle = Bundle(for: SchedJoulesSDK.self)

        guard let resourceBundleURL = myBundle.url(
            forResource: "MySDK", withExtension: "bundle")
            else { fatalError("MySDK.bundle not found!") }

        guard let resourceBundle = Bundle(url: resourceBundleURL)
            else { fatalError("Cannot access MySDK.bundle!") }

        return resourceBundle
    }()
}
Run Code Online (Sandbox Code Playgroud)

属性是惰性初始化的(这是static let属性的默认值,不需要lazy关键字)并且系统确保这种情况只发生一次,因为let属性一旦初始化就不能更改。请注意,您不能Self.self在该上下文中使用,您需要使用实际的类名。

在您的代码中,您现在可以在需要的地方使用该包:

let storyBoard = UIStoryboard(name: "SDK", 
    bundle: SchedJoulesSDK.resourceBundle)
Run Code Online (Sandbox Code Playgroud)


Mah*_*dra 6

你可以使用像...

s.resource  = "icon.png" //for single file
Run Code Online (Sandbox Code Playgroud)

或者

s.resources = "Resources/*.png" //for png file
Run Code Online (Sandbox Code Playgroud)

或者

s.resources = "Resources/**/*.{png,storyboard}" //for storyboard and png files
Run Code Online (Sandbox Code Playgroud)

或者

s.resource_bundles = {
   "<ResourceBundleName>" => ["path/to/resources/*/**"]
}
Run Code Online (Sandbox Code Playgroud)

  • 这对我有什么帮助? (4认同)