Rob Napier
Rob Napier

Reputation: 299703

Linking the same framework to multiple targets in CocoaPods

I have a Swift project with some local frameworks that are linked with the main app. One of the frameworks requires a CocoaPod that the main project also requires elsewhere. Obviously I'd only like one copy. That seems to work fine, but the unit tests are getting confused. This is a slightly simplified version of the Podfile:

platform :ios, '11.0'
inhibit_all_warnings!
use_frameworks!

# The main app target
target 'TheApp' do
  pod 'Instabug'

  target 'TheAppTests' do
    inherit! :search_paths
    pod 'OHHTTPStubs/Swift'
  end
end

# A framework target that's linked by TheApp
target 'Logging' do
  pod 'Instabug'

  target 'LoggingTests' do
    inherit! :search_paths
  end
end

I believe I'm supposed to nest the test targets inside their subject. TheApp imports Logging. Both import Instabug. TheAppTests has a host application of TheApp. LoggingTests has not host application.

I get Pods-TheApp, Pods-TheAppTests, and Pods-Logging the way I expect. Sometimes I get Pods-LoggingTests and sometimes I get Pods-Logging-LoggingTests. (This turns out to be tied to the inherit setting. If it's not set, then I get Pods-Logging-LoggingTests; if it is set to search_paths then I get Pods-LoggingTests.)

I'm often getting errors that Instabug isn't copied into the LoggingTest bundle, or I get errors that Instabug has been processed twice. The app itself seems to work fine. It's just that unit tests fail. (There are several other local frameworks that don't have any dependencies, and I don't list them in the Podfile.)

Note that all the framework targets live in one xcodeproj.

I suspect I'm just writing the Podfile incorrectly. Is there a canonical way to handle local (non-pod) frameworks that have their own tests and their own dependencies that match the app's?

This is CocoaPods 1.7.0. I had the same issue with 1.6.2.

Upvotes: 4

Views: 6623

Answers (2)

manman
manman

Reputation: 5113

I faced the same issue and I personally found it much easier to manage pods in a linear way and creating helper methods for referring each pod. This way when you share a pod among projects, you update the pod version only in one place:

platform :ios, '11.0'
inhibit_all_warnings!
use_frameworks!

##
## Group pods
##

def alamofire_pods
    pod 'Alamofire', ~> '4.0'
end

def snapkit_pods
    pod 'SnapKit', '~> 4.0'
end

#
# Now, lets create all subprojects and main project pod dependencies
#

target 'MySubproject' do
    project 'rel_path_to/subproject.xcodeproj'

    alamofire_pods

    target 'MySubproject Tests' do
        inherit! :complete
    end
end

# Following same pattern for all other subprojects

target 'MainProject' do
   project 'Mainproject.xcodeproj' # path to main project

   snapkit_pods
   alamofire_pods

   target 'Mainproject Unit Tests' do
   end
end

target 'Mainproject UI Tests' do
    # specific pods for your UI Test
end

This approach worked the best and helped with running also subproject tests in the project.

Rule of thumb, also always make sure to remove old pod references from your project. That was causing issues in my case and throwing errors when building for unit tests I believe for subprojects. Cocoapods doesn't clean the old pod target references from your project's build phase.

Note pod install shouldn't change the pod target name if you don't change anything in your podfile.

Upvotes: 3

Ben Scheirman
Ben Scheirman

Reputation: 41001

You can create abstract targets that your real targets inherit from, thereby having 2 sets of dependencies, some of which are shared.

This is what I do:

project "NSScreencast/NSScreencast.xcodeproj"
use_frameworks!

abstract_target "NSScreencast-Base" do
  pod "Kingfisher"
  pod "R.swift"

  target "NSScreencast" do
    platform :ios, "11.0"
    pod "AppCenter"
    pod "FXReachability"
    pod "Colorkit"
    pod "SVProgressHUD"
    pod "1PasswordExtension"
    pod "OneSignal", ">= 2.6.2", "< 3.0"
    pod "Reveal-SDK", :configurations => ["Debug", "Debug-LocalServer"]
  end

  target "OneSignalNotificationServiceExtension" do
    platform :ios, "11.0"
    pod "OneSignal", ">= 2.6.2", "< 3.0"
  end

  target "NSScreencastTV" do
    platform :tvos, "10.0"
  end
end

This allows me to use the shared pods in multiple targets (here, iOS and tvOS) and have specific ones for each target as well.

Does this solve your problem?

Upvotes: 4

Related Questions