Cocoapods with multiple projects and shared libraries - ios

I have a workspace with several projects. Each customer has its own project and each customer's project depends on
Core project: Static library with common code
Interface project: Static library with common interface, i.e. UIViewController code
The Interface library depends on Core too.
Each one of the projects have two targets. The normal target and the tests target, so,
Core, CoreTests
Interface, InterfaceTests
Customer, CustomerTests
Since every aspect of the app is being heavily developed at the moment, I have all projects on the same workspace and also on the same repository because changes may occur in any part of the structure at any moment.
I want to use CocoaPods to manage the dependencies that the projects have. To keep it simple let's say I can to use OCMock on every test target, NewRelicAgent on every normal target and Reachability only on the Core target.
The Podfile looks like this:
workspace 'CompanyWorkspace'
xcodeproj 'Core/Core.xcodeproj'
xcodeproj 'Interface/Interface.xcodeproj'
xcodeproj 'Customer/Customer.xcodeproj'
target :Core do
platform :ios, '6.0'
xcodeproj 'Core/Core.xcodeproj'
pod 'NewRelicAgent', '~> 5.1'
pod 'Reachability', '~> 3.2'
end
target :CoreTests do
platform :ios, '6.0'
xcodeproj 'Core/Core.xcodeproj'
pod 'OCMock', '~> 3.1'
end
target :Interface do
platform :ios, '6.0'
xcodeproj 'Interface/Interface.xcodeproj'
pod 'NewRelicAgent', '~> 5.1'
end
target :InterfaceTest do
platform :ios, '6.0'
xcodeproj 'Interface/Interface.xcodeproj'
pod 'OCMock', '~> 3.1'
end
target :Customer do
platform :ios, '7.0'
xcodeproj 'Customer/Customer.xcodeproj'
pod 'NewRelicAgent', '~> 5.1'
end
target :CustomerTests do
platform :ios, '7.0'
xcodeproj 'Customer/Customer.xcodeproj'
pod 'OCMock', '~> 3.1'
end
I solved the dependencies between my structure by adding the static library Core.a into the build phases of Interface.a and by changing User Header Search Paths so it finds the headers. In the Customer project I added Core.a and Interface.a into the build phases and modified User Header Search Paths so it finds the code from Core and Interface.
The problem with this approach is that Core and Interface build an execute their tests properly but when I try to build Customer.app I get a number of duplicate symbols errors. I believe that this is because the target keyword in CocoaPods generates static libraries with the dependencies configured so when Customer is built it tries to include twice the code from Core.
Any idea as how to solve this problem?

Related

Module not found - cocoapods

I'm trying to pod install this library into my project's (lets say child xcodeproj) parent project (lets say Parent xcodeproj).
Child .xcodeproj has its own podfile where I have added RxSwift, RxCocoa, Realm and this GeoSwift library. Here is the cocoapods file as show below
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, "9.0"
inhibit_all_warnings!
use_frameworks!
project 'LocationManager/LocationManager'
def pods
pod 'GEOSwift'
pod 'RxSwift', '~> 4.0'
pod 'RxCocoa', '~> 4.0'
pod 'RealmSwift', '~> 3.0'
end
target 'LocationManager' do
pods
target 'LocationManagerTests' do
inherit! :search_paths
pod 'RxBlocking', '~> 4.0'
pod 'RxTest', '~> 4.0'
end
end
This LocationManager is installed into another XCode project as another podfile
def location_pods
pod 'GEOSwift'
pod 'LocationManager', :git => 'git#github.com:myrepo/locationmanager.git', :branch => 'users/me/add-geoswift'
end
target 'TestApp' do
location_pods
project 'TestApp.project'
end
When I try to compile the TestApp target, XCode throws an error as below
GeoSwift module is not found. This error is inside the Pods > LocationManager > MockLocationManager.swift The same module imported else where in that Pods > LocationManager works. Also import RxSwift and import RxCoca works. When I accessed Pods > Targets > LocationManager > Build Phases > Target Dependencies I see all the pods except GeoSwift
May I know how to fix this issue? Adding GeoSwift to this targetDependency doesn't compile either. When compiling LocationManager.xcworkspace as a separate entity it works perfectly fine. That module import GeoSwift doesn't throw any compilation error.
I had an issue similar to this.
Go into Pods:
Then click on "Build Settings", find the row titled "Swift Language Version", and try updating it to the latest (in my case, it was 4.1).
This worked for me! Hopefully it helps someone else out there too.
More info: Xcode 9 Swift Language Version (SWIFT_VERSION)
From what I know Cocoapods do not support sub-projects. I had an issue with this too and I promoted all my sub-projects as folders within the main project and put them under a different target. Now those targets can use Cocoapods too.

How to use CocoaPods with multiple Framework subprojects

First of all, I've turned on use_framework! in Podfile.
Assume the main project is MAIN_APP, and two subprojects are FRAMEWORK_A and FRAMEWORK_B.
MAIN_APP requires FRAMEWORK_A and FRAMEWORK_B, and FRAMEWORK_B requires FRAMEWORK_A as well.
All projects/targets are using CocoaPods to manage third party libraries.
For now, my Podfile looks like:
target :MAIN_APP do
project 'MAIN_APP'
pod 'PodA'
end
target :FRAMEWORK_A do
project 'FRAMEWORK_A'
pod 'PodB'
end
target :FRAMEWORK_B do
project 'FRAMEWORK_B'
pod 'PodC'
end
I manually added FRAMEWORK_A to build settings of FRAMEWORK_B, and both FRAMEWORK_A and FRAMEWORK_B to build settings of MAIN_APP.
All code compiles well, but when running the MAIN_APP crashes because it cannot load Framework of PodB.
I know I can manually add PodB to MAIN_APP and FRAMEWORK_B as well, but is it possible to define this kind of target dependency in Podfile?
Btw, when pod install, I got the warning:
[!] The Podfile contains framework targets, for which the Podfile does not contain host targets (targets which embed the framework).
If this project is for doing framework development, you can ignore this message. Otherwise, add a target to the Podfile that embeds these frameworks to make this message go away (e.g. a test target).
As I know, I can use nested target for host targets like:
target :FRAMEWORK_A
target :MAIN_APP
end
end
So CocoaPods will setup MAIN_APP to use FRAMEWORK_A and inherit pod dependencies from FRAMEWORK_A. But seems I cannot do it with multiple dependencies like:
target :FRAMEWORK_A
target :MAIN_APP
end
end
target :FRAMEWORK_B
target :MAIN_APP
end
end
Because target :MAIN_APP cannot be declared twice.
Is there any better solutions instead of defining pod dependencies as a function in Podfile and include in all target?
This is a great question and I've struggled with a similar situation. This is my PodFile:
platform :ios, '8.0'
workspace 'mygreatapp.xcworkspace'
project 'app/MyGreatApp/MyGreatApp.xcodeproj'
project 'platform/MyGreatFramework/MyGreatFramework.xcodeproj'
abstract_target 'This can say whatever you want' do
target 'MyGreatApp' do
project 'app/MyGreatApp/MyGreatApp.xcodeproj'
pod 'AFNetworking', '~> 2.6.0'
pod 'PromiseKit', '~> 1.5'
pod 'PromiseKit/Join'
pod 'KVOController', '~> 1.0'
pod 'FLAnimatedImage', '~> 1.0'
pod 'Crashlytics', '~> 3.3'
pod 'SSZipArchive'
end
target 'MyGreatAppTests' do
project 'app/MyGreatApp/MyGreatApp.xcodeproj'
pod 'OCMock', '~> 3.1'
end
target 'MyGreatFramework' do
project 'platform/MyGreatFramework/MyGreatFramework.xcodeproj'
pod 'SSZipArchive'
end
target 'MyGreatFrameworkTests' do
project 'platform/MyGreatFramework/MyGreatFramework.xcodeproj'
pod 'OCMock', '~> 3.1'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
end
As you can see I'm not using frameworks and I use an abstract_target to group it all together. I wish these kinds of dependencies were easier to do in CocoaPods. I know this doesn't really answer your question but it might be helpful nonetheless.
I think you can also get around this by just making FrameworkA and FrameworkB into local (static library) pods and it will de-duplicate everything for you and integrate it into the host app properly.
Examples: https://github.com/rob-keepsafe/PodFrameworksIssue
master branch shows duplicate classes and umbrella frameworks like you have
deduped branch makes the internal dynamic frameworks into local pods (as static libs) to de-dupe and still link in the dependencies
I'm not entirely sure your issue is the same as mine, but I'm going to leave my solution here just-in-case someone has a similar issue.
I have a project with multiple sub-projects I use to modularize my code (and potentially prepare to extract to my own private pods).
I had the issue of one importing an external pod to one of the sub-projects, and receiving a dyld error due to a "missing image".
I found this Medium article from which I concluded that I had to always include the pods in the main project for the sub-projects to be able to find them. Neither of my external pods are used in the main project.
( https://medium.com/#akfreas/how-to-use-cocoapods-with-your-internal-ios-frameworks-192aa472f64b )
(I'm probably not writing the podfile as correctly or efficiently as I could, but this seems to fix my issue)
My podfile is therefore as follows:
abstract_target "RandomName" do
target "MainProject" do
inherit! :complete
workspace './MainProject.xcodeproj'
pod 'Moya', '~> 13.0'
pod 'KeychainSwift', '~> 17.0'
end
target "ModuleA" do
project './ModuleA/ModuleA.xcodeproj'
workspace './ModuleA/ModuleA.xcodeproj'
pod 'Moya', '~> 13.0'
end
target "ModuleB" do
project './ModuleB/ModuleB.xcodeproj'
workspace './ModuleB/ModuleB.xcodeproj'
pod 'KeychainSwift', '~> 17.0'
end
end

Import a workspace with pod in a other similar worskspace in Xcode

I built 2 swift projects. Both use CocoaPod, so these projects are workspaces.
The first one is like a framework with a lot of Classes I use in the second one.
I don't succeed in this importation:
I followed those steps from the Apple Docs , but any Classes from my Framework (1st project) are recognized... I have 80 error like this :
Use of undeclared type < MyFrameworkClass >
I know two options for setting up a workspace with multiple pods.
You can create a single podfile for both projects. As you can imagine, it will create a single workspace where your two projects (app and framework) will be at (let's cocoapods take care of the entire workspace).
The pod file will look like this:
platform :ios, '8.0'
use_frameworks!
workspace 'WorkspaceName’
xcodeproj ‘FolderOfApp/Project.xcodeproj'
xcodeproj ‘FolderOfApp/App.xcodeproj'
target :ApptTarget do
xcodeproj 'FolderOfApp/App.xcodeproj'
pod ‘MyAppPod’
end
target :FrameworkTarget do
xcodeproj 'FolderOfFramework/Framework.xcodeproj
pod ‘MyFrameworkPod’
end
You will probably need to add the "MyFrameworkPod" to the AppTarget too, and this bring some warnings that I still couldn't solve.
Anyway, you have another option that I was using before. Create and execute the two pod files as you are doing now, create another workspace, add the two projects and the two pods (separate them with folders). DONT ADD THE WORKSPACES, just the projects.
With this approach I had a feel problems like the app not finding the frameworks dependencies, but I solved adding the framework search path.
Swift 5 Very easy solution in your POD File
in your directory : touch Podfile (file will create in workspace)
# platform :ios, '10.0'
use_frameworks!
workspace 'TestWorkSpace'
xcodeproj 'Project1/Project1.xcodeproj'
xcodeproj 'Project2/Project2.xcodeproj'
target 'Project1' do
xcodeproj 'Project1/Project1.xcodeproj'
#Pods for Project1
pod 'SwiftyJSON', '~> 4.0'
end
target 'Project2' do
xcodeproj 'Project2/Project2.xcodeproj'
#Pods for Project2
pod 'SwiftyJSON', '~> 4.0'
end

SimpleAuth pod not installing properly

I use several pods in my Xcode project, all work perfectly well except SimpleAuth
Here is my code in my podfile:
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
platform :ios, ‘8.0’
pod 'SWRevealViewController', '~> 2.3'
pod 'SAMCache'
source 'https://github.com/calebd/SimpleAuth'
use_frameworks!
pod 'SimpleAuth/Instagram'
Then, I install my pod using my terminal targeting my project folder. And as you can see, the "SimpleAuth" folder created in my project is empty when it should include all the objective-c classes that it needs to operate:
Any help by more experience objective-c coders much appreciated.
why are you using two ways. instead use simple
podflie
use_frameworks!
platform :ios, ‘8.0’
pod 'SWRevealViewController', '~> 2.3'
pod 'SAMCache'
pod 'SimpleAuth/Instagram'
there is no need of mentioning source path. Cocoapods will do it automatically.
It is not used because if sometime in future if it change then you will have a problem.

Cocoapods can't find header xcode 6

I have a problem xcode can't find the headers of my pods in my wokspace.
The headers search path for the target seems ok
Here is the content of my podfile
target "MyApp" do
pod 'AFNetworking', '~> 2.0'
pod 'Reachability'
pod 'ViewDeck', '2.2.11'
pod 'MBProgressHUD', '~> 0.8'
end
But when i build the project i have this error in the prefix.pch
/Users/...../MyApp-Prefix.pch:17:13: 'AFNetworking.h' file not found
I have tried to add platform :ios, "8.0" in my podfile and do a pod update but still no luck
I have also tried to add $(inherited) like suggested in the SO question :
Xcode 6 doesn´t find cocoapods libraries
I'm using xcode 6 on mavericks
I found solution. In your project properties replace this:
You might also want to link your pods with both your targets like so:
platform :osx, '10.7'
link_with 'MyApp', 'MyApp Tests'
pod 'AFNetworking', '~> 1.0'
pod 'Objection', '0.9'
From Cocoapods docs and this answer
Update: This no longer works for Cocoapods 1.0+, the correct way to implement the Podfile is:
platform :ios, '9.0'
inhibit_all_warnings!
target 'MyApp' do
pod 'ObjectiveSugar', '~> 0.5'
target "MyAppTests" do
inherit! :search_paths
pod 'OCMock', '~> 2.0.1'
end
end
Source: https://guides.cocoapods.org/syntax/podfile.html#podfile
I was able to fix this in my project. I had a second target for tests. I never used this target and the error disappeared after I deleted it from the project. So maybe not your main target is the source of the problem, but another one.
I agree with jwswart's answer because quite many times I have realized that the issue with just defining dependencies for the 'MyApp' and leaving out 'MyAppTests' as in:
target :'MyApp' do
..
end
breaks the build process because the classes defined in 'MyApp' make use of the dependencies which are not visible in the 'MyAppTests'. Thus as jwswart suggested:
link_with 'MyApp', 'MyApp Tests'
Just have a try to comment this line for your target
# use_frameworks!
~~

Resources