Bootstrap

制作第三方库时,我们的资源到底在哪?

在制作 iOS 的第三方库时,有时需要携带图片资源或者多语言文件。当把制作好的第三方库移交出去之后,用户可以通过 、,等方式来引用库,也可能把源文件和资源文件直接放到主工程当中。

在多种情况下,我们应该如何管理这些资源文件,才能正确的读取到资源文件呢?

资源文件的 Bundle

首先,我们应该将资源文件放到一个专门的 Bundle 中,方便统一管理和读取。

当制作的库支持 时,可以在 文件中,通过 来指定 Bundle 的名称和对应的资源路径:

s.resource_bundles = {
  '库名' => [
    '资源文件的路径1',
    '资源文件的路径2',
    '资源文件的路径3',
    ]
}

资源文件的路径可有几种情况:

制作支持 和 的库时,可以分别搜索一下设置资源文件的 Bundle 名称的方法。

资源文件 Bundle 的路径

在用户使用第三方库时,根据使用的方式不同,第三方库的资源文件的 Bundle 所处的位置也不同:

接下来,通过资源文件的 Bundle 所在的路径和名称,就可以得出完整的资源文件 Bundle 的路径 URL,然后通过 URL 初始化资源文件的 Bundle。

SwiftMessages 中的做法

在阅读 源码时,看到下面代码,处理了获取资源文件的所有情况。我们在制作第三方库时,也可以直接使用。

import Foundation

private class BundleToken {}

extension Bundle {
    // This is copied method from SPM generated Bundle.module for CocoaPods support
    static func sm_frameworkBundle() -> Bundle {

        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: BundleToken.self).resourceURL,

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

        let bundleNames = [
            // For Swift Package Manager
            "SwiftMessages_SwiftMessages",

            // For Carthage
            "SwiftMessages",
        ]

        for bundleName in bundleNames {
            for candidate in candidates {
                let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
                if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
                    return bundle
                }
            }
        }

        // Return whatever bundle this code is in as a last resort.
        return Bundle(for: BundleToken.self)
    }
}