Jonas Zaugg
Jonas Zaugg

Reputation: 3015

Using Cocoapods in an app extension using a framework

I have an app (let's call it MyApp) written in Swift with the following targets :

The MyAppKit framework is linked into each target that uses it, namely MyApp and MyAppWidget. Enter Cocoapods : I used to have the following Podfile structure :

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    # Mostly UI or convenience pods
    pod 'Eureka', '~> 2.0.0-beta'
    pod 'PKHUD', '~> 4.0'
    pod '1PasswordExtension', '~> 1.8'
end

target 'MyAppKit' do
    # Backend pods for networking, storage, etc.
    pod 'Alamofire', '~> 4.0'
    pod 'Fuzi', '~> 1.0'
    pod 'KeychainAccess', '~> 3.0'
    pod 'RealmSwift', '~> 2.0'
    pod 'Result', '~> 3.0'
end

target 'MyAppWidget' do
    # Added here event though the target only imports MyAppKit but it worked
    pod 'RealmSwift', '~> 2.0'
end

The aim here was to expose only the MyAppKit framework to the other parts and not all its pods (e.g. I don't want to be able to import Alamofire inside the main app). However, starting with the Cocoapods 1.2.0 RCs, pod install failed with the following error : [!] The 'Pods-MyApp' target has frameworks with conflicting names: realm and realmswift.. It used to work because the pods were declared for the extension but only embedded in the host app (see this issue for more info). So I removed the pods from the widget's target, leaving me with just a blank target 'MyAppWidget' line.

With this configuration, pod install runs fine but compiling fails at the linking stage for the MyAppWidget target : ld: framework not found Realm for architecture x86_64. This can be fixed by explicitly adding both Realm.framework and RealmSwift.framework to the "Link Binary With Libraries" section and the following build setting in the target's Pods-MyAppWidget.[debug/release].xcconfig :

FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Realm" "$PODS_CONFIGURATION_BUILD_DIR/RealmSwift"`

However, whenever I run pod install, the build settings are naturally reverted and I have to add the build settings again.

I see the following solutions :

So, here's my question : what's the best way to integrate pods in a framework shared between the main app and the extension while still being able to compile, without tweaking around and manually adding stuff?

Cheers and thanks in advance!


EDIT

Following Prientus' comment I've explored the possibilities of abstraction and inheritance. The underlying issues I've now uncovered are actually manifold :

Using this last option and manually linking Realm.framework works but is suboptimal regarding my intents and what used to work. Some of these issues seem to be a bug according to various issues on Cocoapods' GitHub. I've added my own issue and will update when I have news.

Upvotes: 28

Views: 21215

Answers (3)

YorkFish
YorkFish

Reputation: 87

This is a swift-3.0 project's profile example.

platform :ios, '8.0'

def import_public_pods

  pod 'SwiftyJSON'

end


target 'Demo' do
  use_frameworks!

  # Pods for Demo
  import_public_pods 
  pod 'Fabric'
  pod 'Crashlytics'

  target 'DemoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'DemoUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end


target 'DemoKit' do
  use_frameworks!

  # Pods for DemoKit
  import_public_pods
  pod 'RealmSwift'

  target 'DemoKitTests' do
    inherit! :search_paths
    # Pods for testing
  end

end

Upvotes: 2

Jonas Zaugg
Jonas Zaugg

Reputation: 3015

So, what gives :

  • My concern of "separating pods between targets" is absurd because you can still import them anywhere.
  • The "you have to manually link" issue is fixed by an easy import RealmSwift statement.

The fixed and working Podfile therefore is :

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    pod 'Eureka', '~> 2.0.0-beta'
    pod 'PKHUD', '~> 4.0'
    pod '1PasswordExtension', '~> 1.8'
end

target 'MyAppKit' do
    pod 'Fuzi', '~> 1.0'
    pod 'RealmSwift', '~> 2.0'
    pod 'Alamofire', '~> 4.0'
    pod 'KeychainAccess', '~> 3.0'
    pod 'Result', '~> 3.0'

    target 'MyAppWidget' do
        inherit! :search_paths
    end
end

And that's it. I would say that the old behaviour was more obvious and didn't require reading up on "podfile target inheritance". I did learn a lot though. Cheers!

Upvotes: 24

J.Wang
J.Wang

Reputation: 1236

I don't know you. But for me, it's totally legit and reasonable to have the extension and the host app contain all the pods that a framework defines. And this is what i mean:

def shared_pods
    pod 'Alamofire'
end

target 'Framework' do
    shared_pods
end

target 'Host' do
    shared_pods
    // Some other pods
end

target 'Extension' do
    shared_pods
end

I know you are worried about but if you think about it, all those 3rd party frameworks you use, they all have dependencies. You don't have to worries about them because Cocoapods takes care of them for you. If you want to utilise that, then you'll need to put a local pod entry in the list.

target 'Host' do
    pod Framework, :path => '../Framework'
end

But then you have to maintain the podspec file.

Upvotes: 7

Related Questions