Cocoapods: Pods copy resource script overrides default xcasset bahaviour

Created on 5 Nov 2013  ·  85Comments  ·  Source: CocoaPods/CocoaPods

I have a project with different "themes" that are used for different xcode targets. For the themes I have two xcasset catalogs, one with red graphics and one with green graphics. Inside the bundles the files are named the same (so that I can simply use background.png as image name and get the correct color). Which xcasset that get copied is determined by the target membership (and ultimately by the build step "copy bundle resources").
Since cocoa pods version 0.27 I've noticed that there is a new entry in the copy pods resource script. That will cause my red graphics copied by the standard xcode build step to be replaced with the green graphics copied by the cocoa pods copy resources build step.

moderate confirmed defect

Most helpful comment

I have run into the same problem. In our project we need to support all of these:

  1. shared user asset catalogs
  2. per-target user asset catalos
  3. pods with asset catalogs

I ended up fudging the resource script from Podfile post-install hook.

The downside is that you have to re-run pod install if application's asset catalogs are added or removed. But it almost never happens in our case (YMMV). Pods asset catalogs change more often, so I've put it in the post-install hook, as opposed to a standalone script. It's dirty but it works.

All 85 comments

I can add that as a workaround I just reordered the build steps so that the cocoa pods resources gets copied before the standard xcode build step. That way I get my target dependent resources copied last.

That’s very unfortunate. Are you even using pods that have asset catalogs?

@ulrikdamm Any ideas on how to improve this?

If there is a way to read what files are copied in the copy bundle resources build step, then we could just pick those asset catalogs when building our own. Right now it just looks for xcassets files in the source directory.

Hmm, that’s probably going to be complex. I’ll have to mull this over.

Also seeing this with a similar project setup, and appreciate how hard it is to fix. If you need an example project or any more info, then I'd be happy to send something over.

Same issue here.

Facing the same issue. Has there been a resolution yet on this issue.

Alas not. I think one of you (or others with the same issue) will have to sit down and spend some time playing with Xcode to see if you can find a pragmatic solution that works regardless of CocoaPods.

I am having the same issue. Our current solution has been to delete the .xcasset folder that belongs to any target we are not building for.

I've poking around in the copy resource script and found that the .xcassets part in install_resource() was empty.
I guess it should be handled in that function instead of just copying all files. I'll have a look tonight.

I posted about this problem on my blog, though I did not know it was related to CocoaPods until a commenter pointed it out. He also included a possible solution :) Even though it won't work in my case due to some of the pods having xcassets in them, it may get this bug fix on the right track.

http://matt.coneybeare.me/using-xcode-asset-catalogs-with-multiple-targets/#comment-1213336157

I'm also having this issue. None of the pods I use have any extra xcassets in them. How hard would it be to modify the copy_resources_script.rb so that when it checked if there were any xcassets it only checked if there were xcassets within the pod projects. Then at least for people who dont have pods that include extra xcassets it won't mess up their build. Something as simple as changing this line

if [[ -n "${WRAPPER_EXTENSION}" ]] && [ `xcrun --find actool` ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]```

to this

if [[ -n "${WRAPPER_EXTENSION}" ]] && [ `xcrun --find actool` ] && [ `find Pods -name '*.xcassets' | wc -l` -ne 0 ]

I'm having the same problem on my current project. The project is being built continuously by a jenkins server that cleans the directory and runs pod install on every build, so a more durable solution than editing the Pods-resources.sh script would be preferred.

For those having this issue, and having do delete the same lines everytime you pod install, I created a build phase run script that does it automatically, by using sed.

The lines that the script removes are the ones shown in here.

Go to your build phases, Editor>Add Build Phase>Add Run Script Build Phase.
Paste in the following code:

# Backup the original file
if [ ! -f Pods/Pods-resources.sh.bak ];
then
    cp Pods/Pods-resources.sh Pods/Pods-resources.sh.bak
fi

sed '/if \[\[ -n "\${WRAPPER_EXTENSION}" ]] \&\& \[ `xcrun --find actool` \] \&\& \[ `find \. -name '\''\*\.xcassets'\'' \| wc -l` -ne 0 \]/,/fi\n/d' Pods/Pods-resources.sh > Pods/Pods-resources.sh.temp
sed '/*.xcassets)/,/;;/d' Pods/Pods-resources.sh.temp > Pods/Pods-resources.sh
rm Pods/Pods-resources.sh.temp

_Important_: Move your script above the existing Copy Pods Resources.

screenshot 2014-02-22 15 38 07

This can probably be made shorter by piping the results, but meh.

I just tried out @barksten's workaround. In my particular case, I reordered the "Copy Pods Resources" build phase to occur right before the "Copy Bundle Resources" build phase. The resulting workaround works quite well without having to delete sections of the Pod-resources.sh script file.

Issue has been confirmed by @neonichu

I'm having this issue also.

Another workaround based on @rfsbraz idea. I've basically added @rfsbraz script to my post_install hook. My ruby is pretty basic so I'm just calling the script from ruby. I've also simplified the sed regexes a bit so they are a bit more readable. It might be worth putting into it's own script, but I like having it all contained in the podfile.

I like this because it isn't run everytime you build and automatically removes this for all targets.

post_install do |installer|
  installer.project.targets.each do |target|
    %x~ if [ ! -f Pods/#{target.name}-resources.sh.bak ]; then cp Pods/#{target.name}-resources.sh Pods/#{target.name}-resources.sh.bak; fi ~

    %x~ sed '/WRAPPER_EXTENSION/,/fi\\n/d' Pods/#{target.name}-resources.sh > Pods/#{target.name}-resources.sh.temp ~
    %x~ sed '/*.xcassets)/,/;;/d' Pods/#{target.name}-resources.sh.temp > Pods/#{target.name}-resources.sh ~
    %x~ rm Pods/#{target.name}-resources.sh.temp ~
  end
end

Is pull request #2212 sufficient to fix this? It fixes the issue for my own project, but I could be overlooking something.

I have the same issue

I have the same issue. The project has xcassets. None of the pods have xcassets. I don't get this error building the main target. Instead, I get it building the test target.

@rfsbraz 's solution works as a temporary workaround

I was just bitten by this last night too while re-organizing our project to make better use of xcassets. After several hours of confusion and frustration mis-directed at Xcode, googling finally led me to @coneybeare's blog post from which I found this issue. I've successfully implemented @rfsbraz's workaround in the interim, and look forward to this being properly fixed in CocoaPods.

Thank you all for documenting and diagnosing the problem!

I'm also experiencing this same issue re-organizing assets.

What's the hold up on including @tomdalling's fix for this?

@andrewip To clarify, you are saying that reordering the Copy Pods Resources phase to go above Copy Bundle Resources fixes the issue without having to add @rfsbraz's workaround?

Also having this issue for one of our bigger projects. Could anyone from the CocoaPods core team review @tomdalling's fix?

Same issue here. Reordering of build phases and making Copy Pods Resources to run before Copy Bundle Resources seems to be a working solution. Any pitfalls I haven't noticed?

@yas375 We've done that also, no issues so far.

@yas375 Reordering alone did not solve the problem for us on our Jenkins build machine, the workaround by @rfsbraz also had to be included.

@andrewtheis I'm just curious why reordering doesn't solve the problem on your Jenkins. Does reordering help when you run locally? Have you marked your schemes as Shared in Product -> Scheme -> Manage schemes so they are under the source control system?

@wilmarvh thanks)

I just ran into the same problem with a fairly large and complex project. I can confirm @andrewtheis. Re-ordering doesn't seem to solve the problem for me, even when directly building from Xcode on my development machine. Still trying to find out why it doesn't work for me.

@yas375 Reordering probably doesn't work on the build machine because we manually run actool before xcodebuild (which annoyingly does not compile xcassets). Because of this paths are added to copy bundle resources phase that don't actually exist (or are malformed).

Reordering of build phases also worked for me. Didn't notice any side effects.

Thank you for the workaround, @barksten. That worked for me.
screenshot 2014-09-12 10 36 49

Revising @jinthagerman's approach for 0.34.1

post_install do |installer|
  installer.project.targets.each do |target|
    folder_path = "Pods/Target\\ Support\\ Files/#{target.name}/#{target.name}"
    %x~ if [ ! -f #{folder_path}-resources.sh.bak ]; then cp #{folder_path}-resources.sh #{folder_path}-resources.sh.bak; fi ~

    %x~ sed '/WRAPPER_EXTENSION/,/fi\\n/d' #{folder_path}-resources.sh > #{folder_path}-resources.sh.temp ~
    %x~ sed '/*.xcassets)/,/;;/d' #{folder_path}-resources.sh.temp > #{folder_path}-resources.sh ~
    %x~ rm #{folder_path}-resources.sh.temp ~
  end
end

Hi!
We have a project with multiple targets and custom assets in each one.
The workaround posted by @sammcewan works for me, but it would be great if editing the Pods-Resources.sh script every time I run pod install wasn't necessary

I have a jenkins machine that cleans my repo and builds continuously to generate an IPA for each target. This is a very fragile solution, i mean, i prefer a more reliable solution (As you said @morten-holm) :)

but it would be great if editing the Pods-Resources.sh script every time I run pod install wasn't necessary

@sebastianvarela That’s exactly what the post_install solution is for.

same issue here

I was clearing out my Pods-resources.sh file to fix this issue. However, be very careful when doing this because if any .xcdatamodels are copied from your Pods, it will crash your app due to a changed data model!

Same issue here, swapping the build phases worked for me so I did not bother with the script.

+1 having the same issue, we already had Copy Pods resources before Copy Bundle Resources.

This bites me every time.

The problem is back on the version 0.34.4 even using some of the scripts above.

+1 The script from @rfsbraz fixes it for me in 0.34.4 temporarily. But I have to clean the project before building the other target to get the correct assets loaded

I made some small revisions to @sammcewan and @jinthagerman scripts for both legibility (eliminate repeated "Pods/Target\ Support\ Files/…" strings) and to avoid "no such file" errors related to targets for which no resources script exists. (I'm not a ruby guy so my heredoc shell script effort is a bit kludgy.)

# Fix broken copy-resources phase per https://github.com/CocoaPods/CocoaPods/issues/1546.
post_install do |installer|
    installer.project.targets.each do |target|
        scriptBaseName = "Pods/Target\\ Support\\ Files/#{target.name}/#{target.name}-resources"
        sh = <<EOT
            if [ -f #{scriptBaseName}.sh ]; then
                if [ ! -f #{scriptBaseName}.sh.bak ]; then
                    cp #{scriptBaseName}.sh #{scriptBaseName}.sh.bak;
                fi;
                sed '/WRAPPER_EXTENSION/,/fi\\n/d' #{scriptBaseName}.sh > #{scriptBaseName}.sh.temp;
                sed '/*.xcassets)/,/;;/d' #{scriptBaseName}.sh.temp > #{scriptBaseName}.sh;
                rm #{scriptBaseName}.sh.temp;
            fi;
EOT
        `#{sh}`
    end
end

Is this going to get fixed in CocoaPods?

:exclamation: All, please realise that the real problem is that the Xcode assets tool actool did not support merging of compiled assets and as such it was impossible to have assets from multiple targets end-up in the same compiled archive (i.e. assets from a user project _and_ from a pods target). Therefore the default resources script finds all assets and compiles them into one. See https://github.com/CocoaPods/CocoaPods/pull/1427#issuecomment-26978591.

If someone can figure out a way to make this scenario work, then please let us know.

PS: Not sure if this was different at the time, but man actool does mention ‘updates […] assets catalog`, but not sure if they mean a compiled archive, nor do I see any options that seem to perform any updating.

@alloy One might argue that although actool has this merging problem, the best solution is not to simply combine all asset catalogues into one. I would guess that the most common use case of xcassets is that a user has multiple targets in their application that need their own asset catalogue and therefore their own xcassets file. However, these catalogues may differ in content, where some images may not be needed for certain targets. For example, a background image is needed for targets A and B but not for target C, in which case CocoaPods will grab this image from either A or B and insert it into C's target, therefore placing an image where there should not be one.

It could simply be stated that CocoaPods cannot support third party libraries that require xcassets and users should import these libraries directly into their project rather than blindly copying all resources into the compiled target, thus _defeating the entire purpose_ of asset catalogues and targets.

@dinglebox Yes, that’s completely right, as such the current solution is to disable/change the resources script for your project. In the future we’ll switch to frameworks for all dependencies and this problem will finally go away (see #2272).

Any news on this? What is the correct script to use for multilpe targets and xcassets? I'm using Cocoapods 0.35.0.

Edit: @zygoat 's works for now! After pasting it has been indented wrong by Xcode which fired an error, correcting indents fixed the script.

Above mentioned scripts are nice workarounds until further. Below modifications make them work if there are spaces in target.name:

folder_path = "\"Pods/Target Support Files/#{target.name}/#{target.name}\""

or

scriptBaseName = "\"Pods/Target Support Files/#{target.name}/#{target.name}-resources\""

Cheers :)

Same issue on version 0.36.0.beta.2 :(
screen shot 2015-02-03 at 15 55 05

I have the same issue. Moving the Copy Bundle Resources to the end of the list works only if the project is cleaned first. I noticed it is only an issue with assets which are referenced but not copied to the project. I added the problematic asset again, this time I copied it and it works fine.
I just started using pods. To be honest, I don't know why it is not a major issue for most people

I had the same issue and found a workaround as follow.
Since the Pods' copy resource script copies incorrect image files, we should move the Copy Bundle Resources build phrase after the Copy Pods Resources build phrase so that any incorrect image file copied by Pods will be replaced with the correct ones. Unfortunately (or not), Xcode checks if the files are modified before copying them, so the trick only works if we clean the project before each build. Thus, we have to make Xcode think that the image files have been modified to force it to copy them. We can do that by adding a New Run Script Phrase and touch all the files we want Xcode to copy with the script find SomeDirectory -name "*.xcassets" -exec touch {} \+;. Remember to replace SomeDirectory with the directory that contains your xcassets files.

screen shot 2015-02-24 at 12 11 11 pm

Any news on this issue? @fabiopelosin

@T-Pham nice touch! It works like a charm.
I hope it will be officially fixed soon

Any updates?

I'll try to work on a proper solution soon.

Hi! Any news?

Well when I said "soon" in my yesterday's comment, I only meant "probably next week or so", not "right away in the next hours" :smile:

The idea we want to implement is to stop managing assets with the pod-resources.sh script. Instead we will:

  • add a reference to each pod's xcassets to the user's project (inside that Pods/ group we already add for xcconfig files) at integration time (when you run pod install)
  • add those xcassets to the appropriate app's targets (according to what is configured in your Podfile)
  • then let Xcode do the job of selecting the proper xcasset catalogs for us according to the target being built

It would be greatly appreciated if you guys could at least provide sample projects (ideally ones suited for unit tests / integration specs) for the various configurations you encountered, so we can directly use them as non-regression specs to test this future new way to integrate assets.

Re-ordering the Copy Pods Resources phase didn't work here (I suspect because one of our pods contains .xcassets) so I ended up using @zygoat's solution, which seems to work!

@AliSoftware that sounds fancy! In case it helps any w/ testing, the pod we're installing that contains .xcassets is: https://github.com/AgileBits/onepassword-app-extension

@taberrr Thx! That's actually the one I'm using for testing that too. :wink:

Feel free to test out the ali-xcassets-1546 branch of CocoaPods to check it with your project. That's still WIP because I still need to add specs/unit tests to ensure I didn't break anything, and cleanup some code when one removes a pod, but this branch should be pretty close to working by now.

@AliSoftware Awesome, man! Love me some 1Password. Your branch is looking good over here, I just used it to install CocoaPods on a quick test project:

````` [!] Please close any current Xcode sessions and useSkap.xcworkspace` for this project from now on.

  • User targets being integrated: ["Skap"]
  • Pod Targets = ["Pods-Skap-1PasswordExtension", "Pods-Skap-AFNetworking"]

    • Adding /Volumes/Mac/Documents/Skap/Pods/1PasswordExtension/1Password.xcassets to user project

    • Adding 1Password.xcassets to targets ["Skap"]

      ==> User project dirty? true```

      ``````

No need for any additional fancy shell scripts! 👍Now I just need to remember to re-install after you've merged it!

So I wrote a script to delete all those lines which are pointed out by Lukapple.Paste the code to run Script in the xcode project after Target Dependencies.

echo "run script to remove Pods-resources.sh"
file_name="${PROJECT_DIR}/Pods/Target Support Files/Pods/Pods-resources.sh"
function remove_wrapper_extensions {cat "$1" | awk 'BEGIN { suppress_output = 0; } /^if \[\[ -n/ { suppress_output = 1; } (!suppress_output) { print $0; } /^fi$/ { suppress_output = 0; }' > "${1}.1"}
function remove_case_statement {cat "$1" | awk 'BEGIN { suppress_output = 0; } /\s*\*\.xcassets\)$/ { suppress_output = 1; } (!suppress_output) { print $0; } /;;/ && (suppress_output) { suppress_output = 0; }' > "${1}.2"}
remove_wrapper_extensions "$file_name"
remove_case_statement "${file_name}.1"
rm "${file_name}"
rm "${file_name}.1"
mv "${file_name}.1.2" "$file_name"
chmod +x "${file_name}"

As a temporary fix, you can easily fix the Pods-resources.sh script generated by CocoaPods. I don't have the time to dig into the CocoaPods source but I guess this could be an approach to fixing the underlying problem.

# Pods/Target\ Support\ Files/Pods/Pods-resources.sh
  ...
  install_resource()
  {
    case $1 in
    ...
    *.xcassets)
-       XCASSET_FILES="${PODS_ROOT}/$XCASSET_FILES '$1'"
+       XCASSET_FILES="$XCASSET_FILES '$1'"
        ;;
        ...

Does 0.36.1 or 0.36.2 change any of this? Is the above still the best solution?

Still seeing this problem with 0.36.3.

@AliSoftware Your branch seemed to fix our issues. Do you expect it to go into, say, a 0.36.4 release?

@AliSoftware I may have spoke too soon, actually. It looks like running pod install using your branch results in a new duplicate reference to my .xcdatamodeld file being added to the Xcode project each time.

@irace You mean that the first time you run pod install you got your pod's .xcdatamodel file added and present only once, but if you re-run pod install you got it added again?

@AliSoftware That seems to be the case, yes.

Any news on this? Can't run the project properly without to do clean before. I tried to use the fix proposed by @T-Pham but I'm not sure if I set it correctly. Maybe something is wrong with my project path.

Considering the commit message that closed this, should this issue be reopened until a fix is confirmed?

None of the scripts seem to be working for me. I am meant to be uploading an app to Apple today but the iPad target ignores its assets folder so has no app icon.

Is there an updated Cocoapods version that has this fix in?

Is someone have any news? Can't use pods because of this bug.

Same error for me

You're welcome to test and see if master fixes your problem, https://github.com/CocoaPods/guides.cocoapods.org/blob/gemfile/source/using/a-gemfile.html.md

A bit of update: We will provide a fix in an upcoming release, that won't properly fix this #1546 (white-label apps, a.k.a multiple xcassets in various targets in the user's project), but that will fix cases for pods with xcassets.

The matter at hand with the current 1546 issue is way more complex that we first imagined, and will require a more complex approach. I already tried a bunch of ideas in the past month, sadly those refactoring and trials failed to cover every use case, so we still need to decide which way we'll be going from there to fix 1546 with a better, proper solution.

Is swapping the build phase order still a reliable fix? Does the order get reset when pod install is run?

This wasn't meant to be closed.

So it looks like 0.36.4 fixed the issue for me for using Watch Extension and CocoaPods.

Still having this issue in 0.37.1. Fixed it reordering the build phases and adding @T-Pham 's script phase: find ${PROJECT_DIR} -name "*.xcassets" -exec touch {} \+; before the Copy Bundle Resources phase

Used to be an issue previously but hasn't been an issue since upgrading to 0.37.1 (was on 0.34 previously with a manual workaround to the Pods-resources.sh file)

My work was abandoned because it couldn't work at all with
configuration-dependent pods so didn't fit all the cases
Le mer. 9 sept. 2015 à 22:40, Rafael Nobre [email protected] a
écrit :

@AliSoftware https://github.com/AliSoftware any news on this? Your
approach looked fine as actool should only try to compile user assets with
the right target ownership. I have a white-label project idea stalled
because of this one, I may contribute a sample project of my use case if
you need it.


Reply to this email directly or view it on GitHub
https://github.com/CocoaPods/CocoaPods/issues/1546#issuecomment-139039324
.

I see. I realized that your efforts tried to fix assets coming from Pods, while the issue with multiple assets in user targets being broken is just a side effect of the current pods-resources script, am I right on these conclusions? What would be the simplest work-around to allow this white label use case to work?

I have run into the same problem. In our project we need to support all of these:

  1. shared user asset catalogs
  2. per-target user asset catalos
  3. pods with asset catalogs

I ended up fudging the resource script from Podfile post-install hook.

The downside is that you have to re-run pod install if application's asset catalogs are added or removed. But it almost never happens in our case (YMMV). Pods asset catalogs change more often, so I've put it in the post-install hook, as opposed to a standalone script. It's dirty but it works.

This issue has been inactive for a long time and will be closed because we want to move forward with a clean slate after our 1.0 release. If you believe this is still relevant, please retest with the 1.0 release candidate and comment with a reproducible project in order for this to become actionable again. Thanks!

Same error in pod 1.7.5.
I tested and found is cocoapods.
a coment in Pods-{{TARGET}}-resources.sh

# Find all other xcassets (this unfortunately includes those of path pods and other targets).

What is the solution?

Was this page helpful?
0 / 5 - 0 ratings