Cocoapods: resource_bundles have wrong BuildableName before opening Xcode

Created on 13 Aug 2018  路  9Comments  路  Source: CocoaPods/CocoaPods

Report

What did you do?

I have a development pod that includes a resource_bundle with same name as the Cocoapod (or even a different name):
Candy.podspec:

s.name = 'Candy'
...
s.resource_bundle = {
  'Candy' => [
    'Assets/**/*.*'
  ]
}

pod install
Build using command line tools without opening the project in Xcode.

What did you expect to happen?

The resource bundle BuildableName is as expected (e.g. Candy.bundle).
demo.xcworkspace/xcuserdata/dick.xcuserdatad/UserInterfaceState.xcuserstate:

<BuildableReference
    BuildableIdentifier = "primary"
    BlueprintIdentifier = "B97EC5452B757418871ECAD2EE9818B8"
    BuildableName = "Candy.bundle"
    BlueprintName = "Candy-Candy"
    ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>

What happened instead?

The resource bundle buildableName is not as expected (e.g. Candy-Candy.bundle)
demo.xcworkspace/xcuserdata/dick.xcuserdatad/UserInterfaceState.xcuserstate:

<BuildableReference
   BuildableIdentifier = "primary"
   BlueprintIdentifier = "B97EC5452B757418871ECAD2EE9818B8"
   BlueprintName = "Candy-Candy"
   ReferencedContainer = "container:Pods.xcodeproj"
   BuildableName = "Candy-Candy.bundle">
</BuildableReference>

When I then open the workspace in Xcode, this then auto-corrects to the expected BuildableName of Candy.bundle.
However, when building using TravisCI, the Xcode.app is not used to open the project, so the BuildableName is not corrected when building from the command line.

CocoaPods Environment

Stack

   CocoaPods : 1.5.3
        Ruby : ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16]
    RubyGems : 2.6.12
        Host : Mac OS X 10.13.6 (17G65)
       Xcode : 9.4.1 (9F2000)
         Git : git version 2.15.2 (Apple Git-101.1)
Ruby lib dir : /Users/dick/.rvm/rubies/ruby-2.4.1/lib
Repositories : master - https://github.com/CocoaPods/Specs.git @ af1c40cc1f1d4a977c53a7b7436f76f4c5358eec

Installation Source

Executable Path: /Users/dick/.rvm/gems/ruby-2.4.1/bin/pod

Plugins

cocoapods-deintegrate : 1.0.2
cocoapods-plugins     : 1.0.0
cocoapods-search      : 1.0.0
cocoapods-stats       : 1.0.0
cocoapods-trunk       : 1.3.0
cocoapods-try         : 1.1.0
moderate help wanted awaiting input

Most helpful comment

Definitely a thing we can improve on. Thanks for the great report. I think resource bundles are intentionally namespaced with the name of the pod so they do not collide between other pods so it will always prefix your pods name to the bundle name.

All 9 comments

Definitely a thing we can improve on. Thanks for the great report. I think resource bundles are intentionally namespaced with the name of the pod so they do not collide between other pods so it will always prefix your pods name to the bundle name.

After trying a few different things in the post_install, I found that this results in a consistent .xcscheme both before and after launching the project in Xcode:

post_install do |installer|
  installer.target_installation_results.pod_target_installation_results.each do |t, v|
    if v.resource_bundle_targets.length != 0
      v.resource_bundle_targets.each do |rbt|
        rbt.build_configuration_list.build_configurations.each do |bc|
          bc.build_settings['PRODUCT_NAME'] = rbt.product_name
...
end

It seems that the PBXNativeTarget.product_name and the XCBuildConfiguration.build_settings['PRODUCT_NAME'] have different values before opening Xcode. The PBXNativeTarget will have PodName-BundleName and the XCBuildConfiguration will have BundleName. When launching Xcode, Xcode then resolves this by prioritizing the value in XCBuildConfiguration.

The inverse works does not seem to work, however:

...
      v.resource_bundle_targets.each do |rbt|
        rbt.build_configuration_list.build_configurations.each do |bc|
          rbt.product_name = bc.build_settings['PRODUCT_NAME']
...

It appears that PBXNativeTarget.name is being used for both the BuildableName (Product Name) and BlueprintName (Target Name) instead of PBXNativeTarget.product_name for the BuildableName when generating the .xcscheme.

From what I can tell, the namespaced version of the bundle is always being discarded for the non-namespaced once Xcode is opened. In looking at some other pods that reference their own Asset Bundle (ISMessages, QBImagePicker, TOCropViewController), it appears that the non-namespaced version is the one being reference in code.

Playing with this some more, this appears to be the solution:

post_install do |installer|
  installer.target_installation_results.pod_target_installation_results.each do |target_name, target_value|
    target_value.resource_bundle_targets.each do |rbt|
      rbt.build_configuration_list.build_configurations.each do |bc|
        # PBXNativeTarget.name is BlueprintName
        # PBXNativeTarget.product_reference.path is BuildableName
        # But opening Xcode auto-corrects PBXNativeTarget.product_reference.path -> 'right_name'
        right_name = "#{bc.build_settings['PRODUCT_NAME']}.#{bc.build_settings['WRAPPER_EXTENSION']}"
        if rbt.product_reference.path != right_name
          puts "Renaming #{rbt.product_reference.path} -> #{right_name}"
          rbt.product_reference.path = right_name
        end
      end
    end
  end
end

Could review it in a PR along with a test!

@dnkoutso
For sure, my Ruby skills are pretty weak, so it may be a bit before I can dig into the actual code to figure out the fix. For now I'm just updating this issue with my findings in case anyone else encounters a similar issue and needs to solve it. Too often GitHub tickets have misleading workarounds, since once the poster finds the good one they stop updating the ticket. :D

My current work around:

post_install do |installer|
  installer.pods_project.targets.each do |nt|
    if nt.isa != 'PBXAggregateTarget'
      # PBXNativeTarget.name is BlueprintName
      # PBXNativeTarget.product_reference.path is BuildableName
      # But opening Xcode auto-corrects product_reference.path -> product_reference.name
      ref_name = nt.product_reference.name
      if nt.product_reference.path != ref_name
        puts "Renaming #{nt.product_reference.path} -> #{ref_name}"
        nt.product_reference.path = ref_name
      end
    end
  end
end

I found that it subtly affects all targets, potentially, even the top level AbtractTargets (which usually isn't an issue, but does mean the schemes are subtly different before opening Xcode):
screen shot 2018-09-03 at 11 20 04 pm
screen shot 2018-09-03 at 11 20 22 pm
(BuildableNames have the - are converted to _, once Xcode being opened, but by setting product_reference.path -> product_reference.name the schemes are 100% the same, and Xcode doesn't even reorder the other lines as shown in my diffs.)

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.

This issue will be auto-closed because there hasn't been any activity for a few months. Feel free to open a new one if you still experience this problem :+1:

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.

This issue will be auto-closed because there hasn't been any activity for a few months. Feel free to open a new one if you still experience this problem :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tlandsmancars picture tlandsmancars  路  3Comments

pronebird picture pronebird  路  3Comments

gerchicov-bp picture gerchicov-bp  路  3Comments

evermeer picture evermeer  路  3Comments

hmistry picture hmistry  路  3Comments