How to use images asset catalog in cocoapod library for iOS

て烟熏妆下的殇ゞ 提交于 2019-11-29 01:09:20

At least as of version 1.0.1 of Cocoapods, image asset catalogs are supported.

In my Swift code, I used:

public static var GoogleIcon:UIImage {
    let bundle = NSBundle(forClass: self)
    Log.msg("bundle: \(bundle)")
    return UIImage(named: "GoogleIcon", inBundle: bundle,compatibleWithTraitCollection: nil)!
}

In my pod spec, I used:

s.resources = "SMCoreLib/Assets/*.xcassets"

When I build using the simulator, the .car file does show up in the Framework:

cd /Users/<snip>/SMCoreLib.framework 
ls
Assets.car  Info.plist  SMCoreLib

Well, image asset catalogs are not supported via pods - just include a resource bundle that contains your image files in your podspec like so:

s.subspec 'Resources' do |resources|
    resources.resource_bundle = {'MyBundle' => ['Resources/**/*.{png}']}

end

and access the images safely from the pod like that:

+(NSBundle *)getResourcesBundle
{
    NSBundle *bundle = [NSBundle bundleWithURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"MyBundle" withExtension:@"bundle"]];
    return bundle;
}


+(UIImage *)loadImageFromResourceBundle:(NSString *)imageName
{
    NSBundle *bundle = [MyClass getResourcesBundle];
    NSString *imageFileName = [NSString stringWithFormat:@"%@.png",imageName];
    UIImage *image = [UIImage imageNamed:imageFileName inBundle:bundle compatibleWithTraitCollection:nil];
    return image;
}

That solves all issues of handling images/resources within a cocoapod.

Swift 3 version

private func getImageFromBundle(name: String) -> UIImage {
   let podBundle = Bundle(for: YourClass.self)
   if let url = podBundle.url(forResource: "YourClass", withExtension: "bundle") {
      let bundle = Bundle(url: url)
      return UIImage(named: name, in: bundle, compatibleWith: nil)!
   }
   return UIImage()
}

if you are using swift.

class func loadImage(name: String) -> UIImage? {
    let podBundle = NSBundle(forClass: MyClass.self)
    if let url = podBundle.URLForResource("MyBundleName", withExtension: "bundle") {
        let bundle = NSBundle(URL: url)
        return UIImage(named: name, inBundle: bundle, compatibleWithTraitCollection: nil)
    }
    return nil
}

In you podspec do like this

s.resources = 'RootFolder/**/*.{lproj,storyboard,xcdatamodeld,xib,xcassets,json}'

Only this works for me (Swift 3 & Swift 4)

public struct ImagesHelper {
  private static var podsBundle: Bundle {
    let bundle = Bundle(for: YourClass.self)
    return Bundle(url: bundle.url(forResource: "YourClass",
                                  withExtension: "bundle")!)!
  }

  private static func imageFor(name imageName: String) -> UIImage {
    return UIImage.init(named: imageName, in: podsBundle, compatibleWith: nil)!
  }

  public static var myImage: UIImage {
    return imageFor(name: "imageName")
  }
}

Then use it as below:

ImagesHelper.myImage

As in the @Chris Prince's answer, don't forget to update your podspec file like:

s.resource_bundles = {
  'YourClass' => ['YourPodName/*/Assets.xcassets']
}

I can't still get it to work, with none of the solutions above. I have an Assets.xcassets file in my Pod.

And inside my Pod classes i would like to access images from the Assets

Specified like this:

s.resource_bundles = {
     'SWDownloadPlayButton' => ['SWDownloadPlayButton/Assets/Assets.xcassets']
}

With this helper:

public struct ImagesHelper {
    private static var podsBundle: Bundle {
        let bundle = Bundle(for: SWDownloadPlayButton.self)
        return Bundle(url: bundle.url(forResource: "SWDownloadPlayButton",
                                      withExtension: "bundle")!)!
    }

    private static func imageFor(name imageName: String) -> UIImage {
        return UIImage.init(named: imageName, in: podsBundle, compatibleWith: nil)!
    }

    public static var download_icon: UIImage {
        return imageFor(name: "download_icon")
    }
}

But whatever i do inside my Pod classes (not in the example project)...like this

 var centerImage: UIImage = ImagesHelper.download_icon.withRenderingMode(.alwaysTemplate) {
        didSet {
            updateImage()
        }
    }

I still get a nil on the centerImage

You can access images from pods by using their bundle id

 NSBundle * bundle = [NSBundle bundleWithIdentifier:@"bundle id of your pod"];
UIImage * image = [UIImage imageNamed:@"imageName" inBundle:bundle compatibleWithTraitCollection:nil];

Add your .xcassets file within the resources in your pod spec, and use the following UIImage init:

extension UIImage {
    convenience init?(podAssetName: String) {
        let podBundle = Bundle(for: ConfettiView.self)

    /// A given class within your Pod framework
    guard let url = podBundle.url(forResource: "CryptoContribute",
                                  withExtension: "bundle") else {
        return nil

    }

    self.init(named: podAssetName,
              in: Bundle(url: url),
              compatibleWith: nil)
    }
 }

My own solution to the issue with CocoaPods. Instead of mucking with UIImage, I added a method to Bundle instead. The method attempts to locate an inner bundle of a given name, but falls back to the original bundle. This allows the code to work in both the application code using pods, as well as the pod code itself.

extension Bundle {

    /**
     Locate an inner Bundle generated from CocoaPod packaging.

     - parameter name: the name of the inner resource bundle. This should match the "s.resource_bundle" key or
       one of the "s.resoruce_bundles" keys from the podspec file that defines the CocoPod.
     - returns: the resource Bundle or `self` if resource bundle was not found
    */
    func podResource(name: String) -> Bundle {
        guard let bundleUrl = self.url(forResource: name, withExtension: "bundle") else { return self }
        return Bundle(url: bundleUrl) ?? self
    }
}

Then in the viewDidLoad method or wherever else you have your image setting code, put something like this, where "ClassFromPod" refers to a Swift class from a CocoaPod, and "ResourceName" is the name of the inner bundle within the pod (you should be able to see the bundles using Xcode project navigator in "Pods/Projects" -- embedded bundles have a LEGO icon and have a "bundle" suffix.)

super.viewDidLoad()
let bundle = Bundle(for: ClassFromPod.self).podResource(name: "ResourceName")
img1 = UIImage(named: "FancyBase", in: bundle, compatibleWith: nil)
img2 = UIImage(named: "FancyHandle", in: bundle, compatibleWith: nil)

As you can see, the UIImage API remains the same, only the bundle being used is different depending on what it finds at runtime.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!