'iOS: How to add Assets folder inside a Framework and how to access them in code?

I create an iOS app and added a framework to it. The generated framework doesn't have an assets folder like the generate Single View App. So I made an Assets folder inside the framework folder and drag and drop it to xcode, choose the target as my framework.

I tried using the asset but the asset doesn't show up. Can show one show me how to correctly do this? is it possible to create an assets folder inside a framework?

I am very new to iOS so any guidance would be much appreciated. Thanks in advance.



Solution 1:[1]

Add Asset catalog to framework target as usual via New File... > Resources, but to get resource from such asset it needs to specify bundle explicitly, as in below example...

Assuming that ImageProvider is in framework target, the code could be

public class ImageProvider {
    // convenient for specific image
    public static func picture() -> UIImage {
        return UIImage(named: "picture", in: Bundle(for: self), with: nil) ?? UIImage()
    }

    // for any image located in bundle where this class has built
    public static func image(named: String) -> UIImage? {
        return UIImage(named: named, in: Bundle(for: self), with: nil)
    }
}

of course you can name such class anyhow.

backup

Solution 2:[2]

Here's how I do it.

First of all, here's how you can create a Bundle to hold your assets like images.

First, create a new target: Navigate to main Xcode menu, File => New => Target. Choose the "macOS tab" then from "Framework & Library" select "Bundle".

Give it your desired name and hit Finish. You should see the bundle in your project folder.

Second, Configuration changes in build settings of Bundle: Go to Build Settings on your bundle target and change the Base SDK to be iOS.

Third, Add images: Add your images to the Bundle directly, no need to add an assets folder. Just drag and drop.

Fourth, build the bundle: Choose your bundle as a destination and choose the generic iOS device and hit Command + B

Fifth, the .bundle will appear in your products folder under your project folder. Right-click on it and view it in Finder and then drag and drop it inside of your main project folder.

Finally, here's how I'd access the assets inside of your bundle.

// Empty UIImage array to store the images in it.
var images = [UIImage]()

let fileManager = FileManager.default
let bundleURL = Bundle.main.bundleURL
let assetURL = bundleURL.appendingPathComponent("MyBundle.bundle") // Bundle URL
do {
  let contents = try fileManager.contentsOfDirectory(at: assetURL,
 includingPropertiesForKeys: [URLResourceKey.nameKey, URLResourceKey.isDirectoryKey],
 options: .skipsHiddenFiles)
  for item in contents { // item is the URL of everything in MyBundle imgs or otherwise.

      let image = UIImage(contentsOfFile: item.path) // Initializing an image
      images.append(image!) // Adding the image to the icons array
  }
}
catch let error as NSError {
  print(error)
}

You will have the .plist file inside of your bundle, therefore, I suggest you handle this by a simple condition to check if the file name is Info.plist don't create an image out of it.

Here's how I handled it in a very trivial way.

    let fileManager = FileManager.default
    let bundleURL = Bundle.main.bundleURL
    let assetURL = bundleURL.appendingPathComponent("Glyphs.bundle")
    do {
      let contents = try fileManager.contentsOfDirectory(at: assetURL, includingPropertiesForKeys: [URLResourceKey.nameKey, URLResourceKey.isDirectoryKey], options: .skipsHiddenFiles)
      for item in contents {
        let imageName = item.lastPathComponent
        if imageName != "Info.plist" {
          let image = UIImage(contentsOfFile: item.path)
          icons.append(image!)
        }
      }
    }
    catch {
      //print(error)
      showAlert(withTitle: "Error", message: "Can't get the icons.")
    }

Solution 3:[3]

I had the same problem. scenario:

  1. our framework will be consumed iOS/OSX
  2. a lot of PNGs inside Framework
  3. we want pngs in iOSApp && MacOs
  4. let's assume out framework project and target is "MyCustomFramework.framework" (usual yellow icon..) already in our app

-

func filePathInFrameworkBundle(name: String)->String{

    let myBundlePath  = Bundle.main.bundlePath

    #if  os(iOS)

    let inMyFW = myBundlePath +
        "/Frameworks" +
    "/MyCustomFramework.framework"

    #elseif os(OSX)
    let inMyFW = myBundlePath +
        "/Contents/Frameworks" +
        "/MyCustomFramework.framework" + "/Versions/A/Resources"

    #else
    #endif

    let pathInBundle = inMyFW+"/"+name
    return pathInBundle
}

Now You can use THIS path in usual image loading calls.

Solution 4:[4]

For SwiftUI use:

  1. Add an Asset catalog to your framework project (eg, "Media.xcassets").
  2. Add a resource, like a Color Set. Let's say you name your color "Thunder".
  3. Create a file in your framework called "Color+Extensions.swift" (or whatever you like).
  4. Inside this file do:
    import SwiftUI

    private class LocalColor {
      // only to provide a Bundle reference
    }

    public extension Color {
        static var thunder: Color {
            Color("Thunder", bundle: Bundle(for: LocalColor.self))
        }
    }

I imagine this works for other asset types as well.

In the project which is using your framework, once you have added the import for your framework, you should be able to just use the color normally:

    Rectangle().foregroundColor(.thunder)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Hassan ElDesouky
Solution 3 ingconti
Solution 4 P. Ent