J'ai une bibliothèque de cocoapod qui contient des actifs dans 2 formats:
mon fichier podspec
contient la définition du groupe de ressources:
s.resource_bundle = {'SparkSetup' => ['Resources/**/*.{xcassets,storyboard}']}
et j'ai une cible distincte dans le projet pod pour créer un ensemble de ressources en utilisant ces fichiers + un fichier plist pour cet ensemble.
lorsque j’utilise le pod dans un projet d’application, je peux voir les fichiers de storyboard/xcassets se trouvant dans la cible du pod et je peux accéder et exécuter le storyboard facilement, mais les images référencées dans le storyboard (dans le fichier .xcassets) sont: introuvable dans l'exécution (mais affiché correctement dans IB).
L'erreur que je reçois est:
Could not load the "spinner" image referenced from a nib in the bundle with identifier "(null)"
Je vois un fichier bundle dans le répertoire products . Pour instancier des VC dans le story-board que j'utilise:
+(NSBundle *)getResourcesBundle
{
NSBundle *bundle = [NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:@"SparkSetup" withExtension:@"bundle"]];
return bundle;
}
+(UIStoryboard *)getSetupStoryboard
{
UIStoryboard *setupStoryboard = [UIStoryboard storyboardWithName:@"setup" bundle:[SparkSetupMainController getResourcesBundle]];
return setupStoryboard;
}
ce qui semble bien fonctionner pour trouver le storyboard, mais pas pour trouver des images dans les .xcassets du même paquet.
Qu'est-ce que je fais mal? Comment puis-je référencer des images de ce storyboard/code et être capable d'intégrer ce pod d'interface utilisateur dans n'importe quelle application?
Merci!
À partir de la version 1.0.1 de Cocoapods, les catalogues de ressources d’image sont pris en charge.
Dans mon code Swift, j'ai utilisé:
public static var GoogleIcon:UIImage {
let bundle = NSBundle(forClass: self)
Log.msg("bundle: \(bundle)")
return UIImage(named: "GoogleIcon", inBundle: bundle,compatibleWithTraitCollection: nil)!
}
Dans mes spécifications de pod, j'ai utilisé:
s.resources = "SMCoreLib/Assets/*.xcassets"
Lorsque je construis en utilisant le simulateur, le fichier .car apparaît apparaît dans le Framework:
cd /Users/<snip>/SMCoreLib.framework
ls
Assets.car Info.plist SMCoreLib
Eh bien, les catalogues de ressources d’image ne sont pas pris en charge via les pods. Il suffit d’inclure un ensemble de ressources contenant vos fichiers image dans votre podspec, comme suit:
s.subspec 'Resources' do |resources|
resources.resource_bundle = {'MyBundle' => ['Resources/**/*.{png}']}
end
et accédez aux images en toute sécurité depuis le pod comme ça:
+(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;
}
Cela résout tous les problèmes de traitement des images/ressources au sein d'un cocoapode.
Version Swift 3
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()
}
si vous utilisez 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
}
Seulement ça marche pour moi (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")
}
}
Puis utilisez-le comme ci-dessous:
ImagesHelper.myImage
Comme dans la réponse de @Chris Prince , n'oubliez pas de mettre à jour votre fichier podspec comme suit:
s.resource_bundles = {
'YourClass' => ['YourPodName/*/Assets.xcassets']
}
En toi podspec fais comme ça
s.resources = 'RootFolder/**/*.{lproj,storyboard,xcdatamodeld,xib,xcassets,json}'
Je n'arrive toujours pas à le faire fonctionner, aucune des solutions ci-dessus… .. J'ai un fichier Assets.xcassets dans mon pod.
Et dans mes cours de pod, je voudrais accéder aux images des atouts
Spécifié comme ceci:
s.resource_bundles = {
'SWDownloadPlayButton' => ['SWDownloadPlayButton/Assets/Assets.xcassets']
}
Avec cette aide:
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")
}
}
Mais quoi que je fasse dans mes classes de pods (pas dans le projet d'exemple) ... comme ceci
var centerImage: UIImage = ImagesHelper.download_icon.withRenderingMode(.alwaysTemplate) {
didSet {
updateImage()
}
}
J'ai toujours un zéro au centreImage
Ajoutez votre fichier .xcassets
dans les ressources de votre spécification de pod et utilisez l'init UIImage suivant:
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)
}
}
Ma propre solution au problème avec CocoaPods. Au lieu de nettoyer avec UIImage, j'ai ajouté une méthode à Bundle. La méthode tente de localiser un groupe interne d'un nom donné, mais revient au groupe d'origine. Cela permet au code de fonctionner à la fois dans le code de l'application à l'aide de pods, ainsi que dans le code de pod lui-même.
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
}
}
Ensuite, dans la méthode viewDidLoad
ou partout où vous avez votre code de réglage d’image, mettez quelque chose comme ceci, où "ClassFromPod" fait référence à une classe Swift d’un CocoaPod, et "ResourceName" est le nom du paquet interne dans le être capable de voir les paquets en utilisant le navigateur de projet Xcode dans "Pods/Projects" - les paquets incorporés ont une icône LEGO et ont un suffixe "paquet".)
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)
Comme vous pouvez le constater, l'API UIImage reste la même, seul le bundle utilisé est différent en fonction de ce qu'il trouve au moment de l'exécution.