'Pod install has required target membership unchecked

Question

How do I configure cocoapods so that running pod install results in the storyboard having ProjectName checked for target membership?

Background

I have a framework and an app that are both created by my company. We use Artifactory and Cocoapods to deploy the framework and pull it into the app. The framework contains a storyboard that is then used by the app to present a form. I am using XCode 8

Pod targets created by 'pod install'

  • ProjectName
  • ProjectName-ProjectName
  • Pods-ProjectNameTest

Problem

The problem is that the targets created by running 'pod install' have to be manually updated.

The storyboard from the framework only has the target membership checked for ProjectName-ProjectName. If I run the app I get the following exception:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Could not find a storyboard named 'ProjectName' in bundle NSBundle...

calling code

let bundle = NSBundle.init(forClass: ProjectNameViewController.classForCoder())]
let storyboard = UIStoryboard(name: "ProjectName", bundle: bundle)

Workaround

If I manually go to the storyboard and check the target membership for ProjectName this works as expected.

podspec

used to deploy framework

Pod::Spec.new do |spec|

  spec.name     = 'ProjectName'
  spec.version  = '0.3.1'
  spec.license  = { :type => "MIT", :file => "LICENSE" }
  spec.summary  = 'Summary.'
  spec.homepage = 'http://COMPANYWEBSITE'
  spec.authors  = 'Author'
  spec.source   = { :git => 'https://github.com/ProjectName.git',
                    :tag => spec.version.to_s, :submodules => true }
  spec.requires_arc = true
  spec.ios.deployment_target = '8.2'

  spec.framework        = 'Foundation, UIKit'
  spec.source_files     = 'ProjectName/**/*.{swift}'
  spec.resource_bundle = { 'ProjectName' => ['ProjectName/Resources/**/*'] }

end

Podfile

used to pull framework into app

use_frameworks!

plugin 'cocoapods-art', :sources => [
  'companyname-public'
]

target 'ProjectNameTest' do
  pod 'ProjectName'
end 


Solution 1:[1]

I was able to resolve this by changing:

spec.resource_bundle = { 'ProjectName' => ['ProjectName/Resources/**/*'] } 

to

spec.resources = 'ProjectName/Resources/**/*'

Solution 2:[2]

There is no need for a workaround, CocoaPods handles this itself when you add

 s.resource_bundles = {
    'ProjectName' => ['ProjectName/Classes/**/*.{xib,storyboard,lproj,plist,json}']
  }

CocoaPods automatically adds the matching files onto the resource bundle, Since in your case you have to manually add it ,that means it is not matching the path you gave in the podspec

Since you're podspec doesn't have storyboard mentioned in resource bundle

spec.resource_bundle = { 'ProjectName' => ['ProjectName/Resources/**/*'] }

Try changing the above to

spec.resource_bundle = { 'ProjectName' => ['path where storyboard or the resource you want to use is'] }

In most of the cases this should work

 s.resource_bundles = {
    'ProjectName' => ['ProjectName/Classes/**/*.{xib,storyboard,lproj,plist,json}']
  }

There is no need for a change in podfile

Now in order to fetch it create a Helper class as follows

final class MySDKBundleProvider {
    static let resourceBundle: Bundle = {
        let myBundle = Bundle(for: MySDKBundleProvider.self)

        guard let resourceBundleURL = myBundle.url(
            forResource: "ProjectName", withExtension: "bundle")
            else { fatalError(" not found!") }

        guard let resourceBundle = Bundle(url: resourceBundleURL)
            else { fatalError("Cannot access ProjectName.bundle!") }

        return resourceBundle
    }()
    

It can handle both the cases of static as well as dynamic linking of pod

Solution 3:[3]

The underlying problem why it does not work is a naming collision. Your resource_bundle has the same name as the module, thus creating a ProjectName-ProjectName bundle.

If you rename the resource_bundle in your podspec to something else, it will work, and you won't rely on the deprecated resources parameter:

spec.resource_bundle = { 'SomethingElse' => ['ProjectName/Resources/**/*'] }

This will create a ProjectName-SomethingElse bundle.

I got the tip from this answer: https://stackoverflow.com/a/70763171/4755172

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 David Light
Solution 2 nitin upadhyay
Solution 3 ffritz