DEV Community

loading...
Cover image for xcode 12 New Build System warns multiple commands produce Assets.car

xcode 12 New Build System warns multiple commands produce Assets.car

Kyle Foo
Late for church
Updated on ・3 min read

If you are experiencing error with the xcode 12 New Build System as such:

error

In this case, one explanation is that your Copy Resources build phase contains one (or more) .xcassets bundle(s). Xcode won't just copy these bundles, instead it will combine them, convert and optimize their content, and create a file called Assets.car that contains the content of all the assets catalogs in your project.

Yet if you integrate other Pod and some Pods also has an asset catalog, exactly the same thing will happen and a second Assets.car file is created and now Xcode has a problem: Two build steps both say they create an Assets.car file. Which one shall win? Which of these two files shall end up in the final application? And what about other steps that depend on this file? After which of the build steps do they have to run? This is a serious problem that Xcode cannot resolve.

There are a few workaround:

(1) Quick and dirty way is to fallback to Legacy Build System (File -> Workplace Settings). However, this doesn't solve the problem but avoids it. Your App still works but someday Apple decided to end the legacy build system you will be in trouble.

(2) Place disable_input_output_paths: true in Podfile, to skip optimisation and always download resources from Pods cleanly every time, since it is not copying bundled assets during build. Adding extra overhead to build doesn't seem optimal, and leads to bad experience during local App development.

# Podfile
platform :ios, '10.3'
install! 'cocoapods', :disable_input_output_paths => true
Enter fullscreen mode Exit fullscreen mode

(3) Search [CP] Copy Pods Resources in the project build phase. In the output_path list, remove the ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Assets.car entry and add this line to the input_path list as dependency instead. This should pass the build. However this is manual step, every time your CI is doing Pod install, you could still see this entry in the output_path list being generated and failed the build.

Well, you could write a script to automate that:

# Podfile
post_install do |installer|
   project_path = './AdaEmbedFramework.xcodeproj'
   project = Xcodeproj::Project.open(project_path)
   project.targets.each do |target|
    puts target
     if target.name == "AdaEmbedFramework"
         phase = target.shell_script_build_phases.find { |bp| bp.name == '[CP] Copy Pods Resources' }
         if !phase.nil?
            phase.input_paths.push('${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Assets.car')
            phase.output_paths.delete('${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Assets.car')
         end
     end
   end
   project.save(project_path)
end
Enter fullscreen mode Exit fullscreen mode

Yet this is a hacky and how long do you plan to stick this in here and wait for xcode or cocoapod to solve it?

(4) In your library project, open Targets' "Build Phases", create a predefined phase named "Copy Files", then drag your *.xcassets to the new phase.

Then the library won't make Assets.car from *.xcassets files when building, instead, cocoapods copies the *.xcassets to your main project which imports the lib, and the main project builds all *.xcassets into a single Assets.car file.

xcode

This seems to be much elegant, by separating the copying steps into different phases stop xcode New Build system from yelling. Credits to StackoverFlow

Updated: You may encounter App Icon not displayed issue and in-stability with other image assets. Do check if you choose this approach.

(5) The most proper way to resolve this is to identify the Pods that use the deprecated resources in its Podspec, update them to resource_bundles instead. If the Pod does not have a latter version that come with this fix, you might have to Fork the repo and do the fix yourself. This is bearable short term wise, until official fix is done on the Pod. Since you might not know what could break with the resource_bundles patch on its Podspec.

Alt Text

Discussion (2)

Collapse
victory1908 profile image
Vinh Le Khanh • Edited

thanks for the article. I have a development pod which has assets and xib, i have changed spec.resource to spec.resource_bundles. All resources are copied to development pod but can not retrieved using normal way

for xib

super.init(nibName: "SplashViewController",
                   bundle: Bundle(for: SplashViewController.self))
Enter fullscreen mode Exit fullscreen mode

and image

UIImage(named: name, in: Bundle(for: aClass), compatibleWith: nil) 
Enter fullscreen mode Exit fullscreen mode

all 2 above not working. How can we retrieve the resource?

Collapse
korgx9 profile image
Kishvarsho

Thanks it helped a lot
Please change resources_bundle to resource_bundle