This is the 11th day of my participation in the August More Text Challenge

When creating third-party libraries for iOS, it is sometimes necessary to carry image resources or multilingual files. Once you hand over your third-party libraries, you can reference them through CocoaPods, Swift Package Manager, Carthage, etc., or you can put source and resource files directly into the main project.

In many cases, how should we manage these resource files, in order to correctly read the resource file?

The Bundle of the resource file

First, we should put the resource files into a special Bundle for unified management and access.

When making libraries that support CocoaPods, you can specify the name of the Bundle and the corresponding resource path using resource_bundles in the library name. Podspec file:

s.resource_bundles = {
  'name'= > ['Resource file path 1'.'Resource file path 2'.'Resource file path 3']},Copy the code

The path to a resource file can be several things:

  1. File path, specifying a specific file;
  2. Directory, specifying all files contained in that directory;
  3. Contains wildcard characters*To specify a class of files, such asThe path / *. JsonRepresents all JSON files in the specified path,The path / / *. * * mRepresents all the directories under this directory and its subdirectories.mFile;

When creating libraries that support Carthage and Swift Package Manager, you can search for ways to set the Bundle name of the resource file, respectively.

Path to the resource file Bundle

When a user uses a third-party library, the Bundle of the third-party library’s resource file is located in a different location depending on how the user uses it:

  1. When directly linked to the application, the Bundle of the third-party library resource file is inBundle.main.resourceURLDirectory;
  2. When used by the framework, the Bundle of the third-party library resource file is in the Bundle directory of the third-party library. In this case, you need to obtain the Bundle corresponding to the library from a class in the third-party library, i.eBundle(for: BundleToken.self);
  3. When used in the command line tool, the Bundle of the third-party library resource file is inBundle.main.bundleURLUnder.

Next, the path URL of the complete resource file Bundle can be obtained from the path and name of the Bundle of the resource file, and then the Bundle of the resource file can be initialized through the URL.

SwiftMessages

When you read the SwiftMessages source code, you see the following code that handles all cases of retrieving resource files. We can also use it directly when making third-party libraries.

import Foundation

private class BundleToken {}

extension Bundle {
    // This is copied method from SPM generated Bundle.module for CocoaPods support
    static func sm_frameworkBundle(a) -> 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)}}Copy the code

When loading the image, you can use:

UIImage(named: rawValue, in: Bundle.sm_frameworkBundle(), compatibleWith: nil)
Copy the code